Merge "[Bluetooth] Convert BluetoothController logs to log buffer so we'll always have them." into tm-qpr-dev
diff --git a/apct-tests/perftests/surfaceflinger/Android.bp b/apct-tests/perftests/surfaceflinger/Android.bp
new file mode 100644
index 0000000..0c28bce
--- /dev/null
+++ b/apct-tests/perftests/surfaceflinger/Android.bp
@@ -0,0 +1,40 @@
+// 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 {
+ // 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: "SurfaceFlingerPerfTests",
+ srcs: ["src/**/*.java"],
+ libs: ["android.test.runner.stubs"],
+ static_libs: [
+ "androidx.test.rules",
+ "androidx.test.ext.junit",
+ "androidx.annotation_annotation",
+ "apct-perftests-utils",
+ "collector-device-lib",
+ "platform-test-annotations",
+ ],
+ test_suites: ["device-tests"],
+ data: [":perfetto_artifacts"],
+ platform_apis: true,
+ certificate: "platform",
+}
diff --git a/apct-tests/perftests/surfaceflinger/AndroidManifest.xml b/apct-tests/perftests/surfaceflinger/AndroidManifest.xml
new file mode 100644
index 0000000..26f2586
--- /dev/null
+++ b/apct-tests/perftests/surfaceflinger/AndroidManifest.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.perftests.surfaceflinger">
+
+ <!-- permission needed to write perfetto trace and read/write simpleperf report -->
+ <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+
+ <application android:label="SurfaceFlingerPerfTests">
+ <uses-library android:name="android.test.runner" />
+ <activity android:name="android.surfaceflinger.SurfaceFlingerTestActivity"
+ android:exported="true">
+
+ <intent-filter>
+ <action android:name="com.android.perftests.core.PERFTEST" />
+ </intent-filter>
+ </activity>
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.perftests.surfaceflinger">
+ </instrumentation>
+</manifest>
diff --git a/apct-tests/perftests/surfaceflinger/AndroidTest.xml b/apct-tests/perftests/surfaceflinger/AndroidTest.xml
new file mode 100644
index 0000000..53e5d99
--- /dev/null
+++ b/apct-tests/perftests/surfaceflinger/AndroidTest.xml
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<configuration description="Runs SurfaceFlingerPerfTests 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="install-arg" value="-t" />
+ <option name="test-file-name" value="SurfaceFlingerPerfTests.apk" />
+ </target_preparer>
+
+ <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
+ <option name="force-skip-system-props" value="true" />
+ <option name="run-command" value="input keyevent KEYCODE_WAKEUP" />
+ <option name="run-command" value="cmd window dismiss-keyguard" />
+ <option name="run-command" value="cmd package compile -m speed android.perftests.surfaceflinger" />
+ </target_preparer>
+
+ <!-- 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" />
+ </target_preparer>
+
+ <!-- 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="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+ <option name="package" value="android.perftests.surfaceflinger" />
+ <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,android.device.collectors.SimpleperfListener" />
+
+ <!-- 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" />
+
+ <!-- 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" />
+
+ <!-- SimpleperfListener related arguments -->
+ <option name="instrumentation-arg" key="report" value="true" />
+ <option name="instrumentation-arg" key="arguments" value="""" />
+ <option name="instrumentation-arg" key="events_to_record" value="instructions,cpu-cycles,raw-l3d-cache-refill,sched:sched_waking" />
+ <option name="instrumentation-arg" key="processes_to_record" value="surfaceflinger" />
+ <option name="instrumentation-arg" key="symbols_to_report" value=""android::SurfaceFlinger::commit(;android::SurfaceFlinger::composite("" />
+
+ <!-- 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" />
+
+ </test>
+
+ <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
+ <option name="directory-keys" value="/data/local/tmp/SurfaceFlingerPerfTests" />
+ <!-- Needed for pulling the collected trace config on to the host -->
+ <option name="pull-pattern-keys" value="perfetto_file_path" />
+ <option name="pull-pattern-keys" value="simpleperf_file_path" />
+ </metrics_collector>
+
+</configuration>
diff --git a/apct-tests/perftests/surfaceflinger/OWNERS b/apct-tests/perftests/surfaceflinger/OWNERS
new file mode 100644
index 0000000..0862c05
--- /dev/null
+++ b/apct-tests/perftests/surfaceflinger/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/wm/OWNERS
diff --git a/apct-tests/perftests/surfaceflinger/README.md b/apct-tests/perftests/surfaceflinger/README.md
new file mode 100644
index 0000000..0dec70f
--- /dev/null
+++ b/apct-tests/perftests/surfaceflinger/README.md
@@ -0,0 +1,34 @@
+## SurfaceFlinger performance tests
+
+### Precondition
+To reduce the variance of the test, if `perf-setup.sh` (platform_testing/scripts/perf-setup)
+is available, it is better to use the following instructions to lock CPU and GPU frequencies.
+```
+m perf-setup
+PERF_SETUP_PATH=/data/local/tmp/perf-setup.sh
+adb push $OUT/$PERF_SETUP_PATH $PERF_SETUP_PATH
+adb shell chmod +x $PERF_SETUP_PATH
+adb shell $PERF_SETUP_PATH
+```
+
+### Example to run
+Use `atest`
+```
+atest SurfaceFlingerPerfTests:SurfaceFlingerPerfTest -- \
+ --module-arg SurfaceFlingerPerfTests:instrumentation-arg:kill-bg:=true
+```
+Use `am instrument`
+```
+adb shell am instrument -w -r -e class android.surfaceflinger.SurfaceFlingerPerfTest \
+ -e kill-bg true \
+ com.android.perftests.surfaceflinger/androidx.test.runner.AndroidJUnitRunner
+```
+* `kill-bg` is optional.
+
+Test arguments
+- kill-bg
+ * boolean: Kill background process before running test.
+- profiling-iterations
+ * int: Run the extra iterations with enabling method profiling.
+- profiling-sampling
+ * int: The interval (0=trace each method, default is 10) of sample profiling in microseconds.
diff --git a/apct-tests/perftests/surfaceflinger/src/android/surfaceflinger/BufferFlinger.java b/apct-tests/perftests/surfaceflinger/src/android/surfaceflinger/BufferFlinger.java
new file mode 100644
index 0000000..52fb8a6
--- /dev/null
+++ b/apct-tests/perftests/surfaceflinger/src/android/surfaceflinger/BufferFlinger.java
@@ -0,0 +1,79 @@
+/*
+ * 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 android.surfaceflinger;
+
+import android.annotation.ColorInt;
+import android.graphics.Canvas;
+import android.graphics.GraphicBuffer;
+import android.graphics.PixelFormat;
+import android.hardware.HardwareBuffer;
+import android.hardware.SyncFence;
+import android.view.SurfaceControl;
+
+import java.util.concurrent.ArrayBlockingQueue;
+
+/**
+ * Allocates n amount of buffers to a SurfaceControl using a Queue implementation. Executes a
+ * releaseCallback so a buffer can be safely re-used.
+ *
+ * @hide
+ */
+public class BufferFlinger {
+ ArrayBlockingQueue<GraphicBuffer> mBufferQ;
+
+ public BufferFlinger(int numOfBuffers, @ColorInt int color) {
+ mBufferQ = new ArrayBlockingQueue<>(numOfBuffers);
+
+ while (numOfBuffers > 0) {
+ GraphicBuffer buffer = GraphicBuffer.create(500, 500,
+ PixelFormat.RGBA_8888,
+ GraphicBuffer.USAGE_HW_TEXTURE | GraphicBuffer.USAGE_HW_COMPOSER
+ | GraphicBuffer.USAGE_SW_WRITE_RARELY);
+
+ Canvas canvas = buffer.lockCanvas();
+ canvas.drawColor(color);
+ buffer.unlockCanvasAndPost(canvas);
+
+ mBufferQ.add(buffer);
+ numOfBuffers--;
+ }
+ }
+
+ public void addBuffer(SurfaceControl.Transaction t, SurfaceControl surfaceControl)
+ throws InterruptedException {
+ GraphicBuffer buffer = mBufferQ.take();
+ t.setBuffer(surfaceControl,
+ HardwareBuffer.createFromGraphicBuffer(buffer),
+ null,
+ (SyncFence fence) -> {
+ releaseCallback(fence, buffer);
+ });
+ }
+
+ public void releaseCallback(SyncFence fence, GraphicBuffer buffer) {
+ if (fence != null) {
+ fence.awaitForever();
+ }
+ mBufferQ.add(buffer);
+ }
+
+ public void freeBuffers() {
+ for (GraphicBuffer buffer : mBufferQ) {
+ buffer.destroy();
+ }
+ }
+}
diff --git a/apct-tests/perftests/surfaceflinger/src/android/surfaceflinger/SurfaceFlingerPerfTest.java b/apct-tests/perftests/surfaceflinger/src/android/surfaceflinger/SurfaceFlingerPerfTest.java
new file mode 100644
index 0000000..45d164c
--- /dev/null
+++ b/apct-tests/perftests/surfaceflinger/src/android/surfaceflinger/SurfaceFlingerPerfTest.java
@@ -0,0 +1,228 @@
+/*
+ * 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 android.surfaceflinger;
+
+import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.view.SurfaceControl;
+
+import androidx.test.ext.junit.rules.ActivityScenarioRule;
+import androidx.test.filters.LargeTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.RuleChain;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.Random;
+
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class SurfaceFlingerPerfTest {
+ protected ActivityScenarioRule<SurfaceFlingerTestActivity> mActivityRule =
+ new ActivityScenarioRule<>(SurfaceFlingerTestActivity.class);
+ protected PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ private SurfaceFlingerTestActivity mActivity;
+ static final int BUFFER_COUNT = 2;
+
+ @Rule
+ public final RuleChain mAllRules = RuleChain
+ .outerRule(mPerfStatusReporter)
+ .around(mActivityRule);
+ @Before
+ public void setup() {
+ mActivityRule.getScenario().onActivity(activity -> mActivity = activity);
+ }
+
+ @After
+ public void teardown() {
+ mSurfaceControls.forEach(SurfaceControl::release);
+ mByfferTrackers.forEach(BufferFlinger::freeBuffers);
+ }
+
+
+ private ArrayList<BufferFlinger> mByfferTrackers = new ArrayList<>();
+ private BufferFlinger createBufferTracker(int color) {
+ BufferFlinger bufferTracker = new BufferFlinger(BUFFER_COUNT, color);
+ mByfferTrackers.add(bufferTracker);
+ return bufferTracker;
+ }
+
+ private ArrayList<SurfaceControl> mSurfaceControls = new ArrayList<>();
+ private SurfaceControl createSurfaceControl() throws InterruptedException {
+ SurfaceControl sc = mActivity.createChildSurfaceControl();
+ mSurfaceControls.add(sc);
+ return sc;
+ }
+
+ @Test
+ public void singleBuffer() throws Exception {
+ SurfaceControl sc = createSurfaceControl();
+ BufferFlinger bufferTracker = createBufferTracker(Color.GREEN);
+ SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ bufferTracker.addBuffer(t, sc);
+ t.show(sc);
+
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ bufferTracker.addBuffer(t, sc);
+ t.apply();
+ }
+ }
+
+ static int getRandomColorComponent() {
+ return new Random().nextInt(155) + 100;
+ }
+
+ @Test
+ public void multipleBuffers() throws Exception {
+ final int MAX_BUFFERS = 10;
+
+ SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ for (int i = 0; i < MAX_BUFFERS; i++) {
+ SurfaceControl sc = createSurfaceControl();
+ BufferFlinger bufferTracker = createBufferTracker(Color.argb(getRandomColorComponent(),
+ getRandomColorComponent(), getRandomColorComponent(),
+ getRandomColorComponent()));
+ bufferTracker.addBuffer(t, sc);
+ t.setPosition(sc, i * 10, i * 10);
+ t.show(sc);
+ }
+ t.apply(true);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ for (int i = 0; i < MAX_BUFFERS; i++) {
+ mByfferTrackers.get(i).addBuffer(t, mSurfaceControls.get(i));
+ }
+ t.apply();
+ }
+ }
+
+ @Test
+ public void multipleOpaqueBuffers() throws Exception {
+ final int MAX_BUFFERS = 10;
+
+ SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ for (int i = 0; i < MAX_BUFFERS; i++) {
+ SurfaceControl sc = createSurfaceControl();
+ BufferFlinger bufferTracker = createBufferTracker(Color.rgb(getRandomColorComponent(),
+ getRandomColorComponent(), getRandomColorComponent()));
+ bufferTracker.addBuffer(t, sc);
+ t.setOpaque(sc, true);
+ t.setPosition(sc, i * 10, i * 10);
+ t.show(sc);
+ }
+ t.apply(true);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ for (int i = 0; i < MAX_BUFFERS; i++) {
+ mByfferTrackers.get(i).addBuffer(t, mSurfaceControls.get(i));
+ }
+ t.apply();
+ }
+ }
+
+ @Test
+ public void geometryChanges() throws Exception {
+ final int MAX_POSITION = 10;
+ final float MAX_SCALE = 2.0f;
+
+ SurfaceControl sc = createSurfaceControl();
+ BufferFlinger bufferTracker = createBufferTracker(Color.GREEN);
+ SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ bufferTracker.addBuffer(t, sc);
+ t.show(sc).apply(true);
+
+ int step = 0;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ step = ++step % MAX_POSITION;
+ t.setPosition(sc, step, step);
+ float scale = ((step * MAX_SCALE) / MAX_POSITION) + 0.5f;
+ t.setScale(sc, scale, scale);
+ t.apply();
+ }
+ }
+
+ @Test
+ public void geometryWithBufferChanges() throws Exception {
+ final int MAX_POSITION = 10;
+
+ SurfaceControl sc = createSurfaceControl();
+ BufferFlinger bufferTracker = createBufferTracker(Color.GREEN);
+ SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ bufferTracker.addBuffer(t, sc);
+ t.show(sc).apply(true);
+
+ int step = 0;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ step = ++step % MAX_POSITION;
+ t.setPosition(sc, step, step);
+ float scale = ((step * 2.0f) / MAX_POSITION) + 0.5f;
+ t.setScale(sc, scale, scale);
+ bufferTracker.addBuffer(t, sc);
+ t.apply();
+ }
+ }
+
+ @Test
+ public void addRemoveLayers() throws Exception {
+ SurfaceControl sc = createSurfaceControl();
+ BufferFlinger bufferTracker = createBufferTracker(Color.GREEN);
+ SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ SurfaceControl childSurfaceControl = new SurfaceControl.Builder()
+ .setName("childLayer").setBLASTLayer().build();
+ bufferTracker.addBuffer(t, childSurfaceControl);
+ t.reparent(childSurfaceControl, sc);
+ t.apply();
+ t.remove(childSurfaceControl).apply();
+ }
+ }
+
+ @Test
+ public void displayScreenshot() throws Exception {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ Bitmap screenshot =
+ InstrumentationRegistry.getInstrumentation().getUiAutomation().takeScreenshot();
+ screenshot.recycle();
+ }
+ }
+
+ @Test
+ public void layerScreenshot() throws Exception {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ Bitmap screenshot =
+ InstrumentationRegistry.getInstrumentation().getUiAutomation().takeScreenshot(
+ mActivity.getWindow());
+ screenshot.recycle();
+ }
+ }
+
+}
diff --git a/apct-tests/perftests/surfaceflinger/src/android/surfaceflinger/SurfaceFlingerTestActivity.java b/apct-tests/perftests/surfaceflinger/src/android/surfaceflinger/SurfaceFlingerTestActivity.java
new file mode 100644
index 0000000..832a0cd
--- /dev/null
+++ b/apct-tests/perftests/surfaceflinger/src/android/surfaceflinger/SurfaceFlingerTestActivity.java
@@ -0,0 +1,82 @@
+/*
+ * 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 android.surfaceflinger;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.SurfaceControl;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.WindowManager;
+
+import java.util.concurrent.CountDownLatch;
+
+/**
+ * A simple activity used for testing, e.g. performance of activity switching, or as a base
+ * container of testing view.
+ */
+public class SurfaceFlingerTestActivity extends Activity {
+ public TestSurfaceView mTestSurfaceView;
+ SurfaceControl mSurfaceControl;
+ CountDownLatch mIsReady = new CountDownLatch(1);
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+ mTestSurfaceView = new TestSurfaceView(this);
+ setContentView(mTestSurfaceView);
+ }
+
+ public SurfaceControl createChildSurfaceControl() throws InterruptedException {
+ return mTestSurfaceView.getChildSurfaceControlHelper();
+ }
+
+ public class TestSurfaceView extends SurfaceView {
+ public TestSurfaceView(Context context) {
+ super(context);
+ SurfaceHolder holder = getHolder();
+ holder.addCallback(new SurfaceHolder.Callback() {
+ @Override
+ public void surfaceCreated(SurfaceHolder holder) {
+ mIsReady.countDown();
+ }
+ @Override
+ public void surfaceChanged(SurfaceHolder holder, int format, int width,
+ int height) {}
+ @Override
+ public void surfaceDestroyed(SurfaceHolder holder) {
+ }
+ });
+ }
+
+ public SurfaceControl getChildSurfaceControlHelper() throws InterruptedException {
+ mIsReady.await();
+ SurfaceHolder holder = getHolder();
+
+ // check to see if surface is valid
+ if (holder.getSurface().isValid()) {
+ mSurfaceControl = getSurfaceControl();
+ }
+ return new SurfaceControl.Builder()
+ .setName("ChildSurfaceControl")
+ .setParent(mSurfaceControl)
+ .build();
+ }
+ }
+}
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 12a6cd2..31c0e30 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -2413,6 +2413,16 @@
method public final boolean shouldShowComplications();
}
+ public class DreamService extends android.app.Service implements android.view.Window.Callback {
+ method @Nullable public static android.service.dreams.DreamService.DreamMetadata getDreamMetadata(@NonNull android.content.Context, @Nullable android.content.pm.ServiceInfo);
+ }
+
+ public static final class DreamService.DreamMetadata {
+ field @Nullable public final android.graphics.drawable.Drawable previewImage;
+ field @Nullable public final android.content.ComponentName settingsActivity;
+ field @NonNull public final boolean showComplications;
+ }
+
}
package android.service.notification {
@@ -3350,17 +3360,11 @@
ctor public TaskFragmentOrganizer(@NonNull java.util.concurrent.Executor);
method @NonNull public java.util.concurrent.Executor getExecutor();
method @NonNull public android.window.TaskFragmentOrganizerToken getOrganizerToken();
- method public void onActivityReparentedToTask(@NonNull android.window.WindowContainerTransaction, int, @NonNull android.content.Intent, @NonNull android.os.IBinder);
method @Deprecated public void onTaskFragmentAppeared(@NonNull android.window.TaskFragmentInfo);
- method public void onTaskFragmentAppeared(@NonNull android.window.WindowContainerTransaction, @NonNull android.window.TaskFragmentInfo);
method @Deprecated public void onTaskFragmentError(@NonNull android.os.IBinder, @NonNull Throwable);
- method public void onTaskFragmentError(@NonNull android.window.WindowContainerTransaction, @NonNull android.os.IBinder, @Nullable android.window.TaskFragmentInfo, int, @NonNull Throwable);
method @Deprecated public void onTaskFragmentInfoChanged(@NonNull android.window.TaskFragmentInfo);
- method public void onTaskFragmentInfoChanged(@NonNull android.window.WindowContainerTransaction, @NonNull android.window.TaskFragmentInfo);
method @Deprecated public void onTaskFragmentParentInfoChanged(@NonNull android.os.IBinder, @NonNull android.content.res.Configuration);
- method public void onTaskFragmentParentInfoChanged(@NonNull android.window.WindowContainerTransaction, int, @NonNull android.content.res.Configuration);
method @Deprecated public void onTaskFragmentVanished(@NonNull android.window.TaskFragmentInfo);
- method public void onTaskFragmentVanished(@NonNull android.window.WindowContainerTransaction, @NonNull android.window.TaskFragmentInfo);
method @CallSuper public void registerOrganizer();
method @CallSuper public void unregisterOrganizer();
}
diff --git a/core/java/android/accessibilityservice/InputMethod.java b/core/java/android/accessibilityservice/InputMethod.java
index 1585f99..93888ef 100644
--- a/core/java/android/accessibilityservice/InputMethod.java
+++ b/core/java/android/accessibilityservice/InputMethod.java
@@ -517,7 +517,8 @@
@Override
public void invalidateInput(EditorInfo editorInfo,
IRemoteAccessibilityInputConnection connection, int sessionId) {
- if (!mStartedInputConnection.isSameConnection(connection)) {
+ if (!mEnabled || mStartedInputConnection == null
+ || !mStartedInputConnection.isSameConnection(connection)) {
// This is not an error, and can be safely ignored.
return;
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index a70a1a8..51efdba 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -534,9 +534,8 @@
// A reusable token for other purposes, e.g. content capture, translation. It shouldn't be
// used without security checks
public IBinder shareableActivityToken;
- // The token of the initial TaskFragment that embedded this activity. Do not rely on it
- // after creation because the activity could be reparented.
- @Nullable public IBinder mInitialTaskFragmentToken;
+ // The token of the TaskFragment that embedded this activity.
+ @Nullable public IBinder mTaskFragmentToken;
int ident;
@UnsupportedAppUsage
Intent intent;
@@ -620,7 +619,7 @@
List<ReferrerIntent> pendingNewIntents, ActivityOptions activityOptions,
boolean isForward, ProfilerInfo profilerInfo, ClientTransactionHandler client,
IBinder assistToken, IBinder shareableActivityToken, boolean launchedFromBubble,
- IBinder initialTaskFragmentToken) {
+ IBinder taskFragmentToken) {
this.token = token;
this.assistToken = assistToken;
this.shareableActivityToken = shareableActivityToken;
@@ -641,7 +640,7 @@
compatInfo);
mActivityOptions = activityOptions;
mLaunchedFromBubble = launchedFromBubble;
- mInitialTaskFragmentToken = initialTaskFragmentToken;
+ mTaskFragmentToken = taskFragmentToken;
init();
}
diff --git a/core/java/android/app/ActivityTransitionState.java b/core/java/android/app/ActivityTransitionState.java
index 877e7d3..6f4bb45 100644
--- a/core/java/android/app/ActivityTransitionState.java
+++ b/core/java/android/app/ActivityTransitionState.java
@@ -145,7 +145,10 @@
* that it is preserved through activty destroy and restore.
*/
private ArrayList<String> getPendingExitNames() {
- if (mPendingExitNames == null && mEnterTransitionCoordinator != null) {
+ if (mPendingExitNames == null
+ && mEnterTransitionCoordinator != null
+ && !mEnterTransitionCoordinator.isReturning()
+ ) {
mPendingExitNames = mEnterTransitionCoordinator.getPendingExitSharedElementNames();
}
return mPendingExitNames;
@@ -202,6 +205,7 @@
restoreExitedViews();
activity.getWindow().getDecorView().setVisibility(View.VISIBLE);
}
+ getPendingExitNames(); // Set mPendingExitNames before resetting mEnterTransitionCoordinator
mEnterTransitionCoordinator = new EnterTransitionCoordinator(activity,
resultReceiver, sharedElementNames, mEnterActivityOptions.isReturning(),
mEnterActivityOptions.isCrossTask());
@@ -250,6 +254,7 @@
public void onStop(Activity activity) {
restoreExitedViews();
if (mEnterTransitionCoordinator != null) {
+ getPendingExitNames(); // Set mPendingExitNames before clearing
mEnterTransitionCoordinator.stop();
mEnterTransitionCoordinator = null;
}
@@ -275,6 +280,7 @@
restoreReenteringViews();
} else if (mEnterTransitionCoordinator.isReturning()) {
mEnterTransitionCoordinator.runAfterTransitionsComplete(() -> {
+ getPendingExitNames(); // Set mPendingExitNames before clearing
mEnterTransitionCoordinator = null;
});
}
@@ -374,6 +380,7 @@
}
public void startExitOutTransition(Activity activity, Bundle options) {
+ getPendingExitNames(); // Set mPendingExitNames before clearing mEnterTransitionCoordinator
mEnterTransitionCoordinator = null;
if (!activity.getWindow().hasFeature(Window.FEATURE_ACTIVITY_TRANSITIONS) ||
mExitTransitionCoordinators == null) {
diff --git a/core/java/android/app/NotificationChannelGroup.java b/core/java/android/app/NotificationChannelGroup.java
index 2b245aa..5c29eb3 100644
--- a/core/java/android/app/NotificationChannelGroup.java
+++ b/core/java/android/app/NotificationChannelGroup.java
@@ -95,8 +95,11 @@
} else {
mId = null;
}
- mName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
- mName = getTrimmedString(mName.toString());
+ if (in.readByte() != 0) {
+ mName = getTrimmedString(in.readString());
+ } else {
+ mName = "";
+ }
if (in.readByte() != 0) {
mDescription = getTrimmedString(in.readString());
} else {
@@ -122,7 +125,12 @@
} else {
dest.writeByte((byte) 0);
}
- TextUtils.writeToParcel(mName.toString(), dest, flags);
+ if (mName != null) {
+ dest.writeByte((byte) 1);
+ dest.writeString(mName.toString());
+ } else {
+ dest.writeByte((byte) 0);
+ }
if (mDescription != null) {
dest.writeByte((byte) 1);
dest.writeString(mDescription);
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 7a88a057..5ca8b05 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -3920,6 +3920,12 @@
* that has been started. This is sent as a foreground
* broadcast, since it is part of a visible user interaction; be as quick
* as possible when handling it.
+ *
+ * <p>
+ * <b>Note:</b> The user's actual state might have changed by the time the broadcast is
+ * received. For example, the user could have been removed, started or stopped already,
+ * regardless of which broadcast you receive. Because of that, receivers should always check
+ * the current state of the user.
* @hide
*/
public static final String ACTION_USER_STARTED =
@@ -3937,6 +3943,12 @@
* {@link #ACTION_USER_STOPPING}. It is <b>not</b> generally safe to use with
* other user state broadcasts since those are foreground broadcasts so can
* execute in a different order.
+ *
+ * <p>
+ * <b>Note:</b> The user's actual state might have changed by the time the broadcast is
+ * received. For example, the user could have been removed, started or stopped already,
+ * regardless of which broadcast you receive. Because of that, receivers should always check
+ * the current state of the user.
* @hide
*/
public static final String ACTION_USER_STARTING =
@@ -3955,6 +3967,11 @@
* {@link #ACTION_USER_STARTING}. It is <b>not</b> generally safe to use with
* other user state broadcasts since those are foreground broadcasts so can
* execute in a different order.
+ * <p>
+ * <b>Note:</b> The user's actual state might have changed by the time the broadcast is
+ * received. For example, the user could have been removed, started or stopped already,
+ * regardless of which broadcast you receive. Because of that, receivers should always check
+ * the current state of the user.
* @hide
*/
public static final String ACTION_USER_STOPPING =
@@ -3967,6 +3984,12 @@
* specific package. This is only sent to registered receivers, not manifest
* receivers. It is sent to all running users <em>except</em> the one that
* has just been stopped (which is no longer running).
+ *
+ * <p>
+ * <b>Note:</b> The user's actual state might have changed by the time the broadcast is
+ * received. For example, the user could have been removed, started or stopped already,
+ * regardless of which broadcast you receive. Because of that, receivers should always check
+ * the current state of the user.
* @hide
*/
@TestApi
@@ -3999,6 +4022,12 @@
* It is sent to all running users.
* You must hold
* {@link android.Manifest.permission#MANAGE_USERS} to receive this broadcast.
+ *
+ * <p>
+ * <b>Note:</b> The user's actual state might have changed by the time the broadcast is
+ * received. For example, the user could have been removed, started or stopped already,
+ * regardless of which broadcast you receive. Because of that, receivers should always check
+ * the current state of the user.
* @hide
*/
@SystemApi
@@ -4009,6 +4038,12 @@
* Broadcast Action: Sent when the credential-encrypted private storage has
* become unlocked for the target user. This is only sent to registered
* receivers, not manifest receivers.
+ *
+ * <p>
+ * <b>Note:</b> The user's actual state might have changed by the time the broadcast is
+ * received. For example, the user could have been removed, started or stopped already,
+ * regardless of which broadcast you receive. Because of that, receivers should always check
+ * the current state of the user.
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_USER_UNLOCKED = "android.intent.action.USER_UNLOCKED";
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 0bbe8c4..4be5e14 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -1119,6 +1119,16 @@
public static final long OVERRIDE_MIN_ASPECT_RATIO_TO_ALIGN_WITH_SPLIT_SCREEN = 208648326L;
/**
+ * Overrides the min aspect ratio restriction in portrait fullscreen in order to use all
+ * available screen space.
+ * @hide
+ */
+ @ChangeId
+ @Disabled
+ @Overridable
+ public static final long OVERRIDE_MIN_ASPECT_RATIO_EXCLUDE_PORTRAIT_FULLSCREEN = 218959984L;
+
+ /**
* Compares activity window layout min width/height with require space for multi window to
* determine if it can be put into multi window mode.
*/
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index a90f6d6..f224f8a1 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -8065,7 +8065,7 @@
}
PackageParser.Package pkg = parser.parsePackage(apkFile, 0, false);
- if ((flagsBits & GET_SIGNATURES) != 0) {
+ if ((flagsBits & GET_SIGNATURES) != 0 || (flagsBits & GET_SIGNING_CERTIFICATES) != 0) {
PackageParser.collectCertificates(pkg, false /* skipVerify */);
}
return PackageParser.generatePackageInfo(pkg, null, (int) flagsBits, 0, 0, null,
diff --git a/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java b/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java
index 98f571b..c59d757 100644
--- a/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java
+++ b/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java
@@ -217,7 +217,8 @@
FINGERPRINT_ACQUIRED_START,
FINGERPRINT_ACQUIRED_UNKNOWN,
FINGERPRINT_ACQUIRED_IMMOBILE,
- FINGERPRINT_ACQUIRED_TOO_BRIGHT})
+ FINGERPRINT_ACQUIRED_TOO_BRIGHT,
+ FINGERPRINT_ACQUIRED_POWER_PRESSED})
@Retention(RetentionPolicy.SOURCE)
@interface FingerprintAcquired {}
@@ -302,6 +303,13 @@
int FINGERPRINT_ACQUIRED_TOO_BRIGHT = 10;
/**
+ * For sensors that have the power button co-located with their sensor, this event will
+ * be sent during enrollment.
+ * @hide
+ */
+ int FINGERPRINT_ACQUIRED_POWER_PRESSED = 11;
+
+ /**
* @hide
*/
int FINGERPRINT_ACQUIRED_VENDOR_BASE = 1000;
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index d6d3a97..dff2f7e 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -1204,6 +1204,20 @@
* to begin with, {@link #onPhysicalCameraUnavailable} may be invoked after
* {@link #onCameraAvailable}.</p>
*
+ * <p>Limitation: Opening a logical camera disables the {@link #onPhysicalCameraAvailable}
+ * and {@link #onPhysicalCameraUnavailable} callbacks for its physical cameras. For example,
+ * if app A opens the camera device:</p>
+ *
+ * <ul>
+ *
+ * <li>All apps subscribing to ActivityCallback get {@link #onCameraUnavailable}.</li>
+ *
+ * <li>No app (including app A) subscribing to ActivityCallback gets
+ * {@link #onPhysicalCameraAvailable} or {@link #onPhysicalCameraUnavailable}, because
+ * the logical camera is unavailable (some app is using it).</li>
+ *
+ * </ul>
+ *
* <p>The default implementation of this method does nothing.</p>
*
* @param cameraId The unique identifier of the logical multi-camera.
@@ -1221,11 +1235,24 @@
* A previously-available physical camera has become unavailable for use.
*
* <p>By default, all of the physical cameras of a logical multi-camera are
- * available, so {@link #onPhysicalCameraAvailable} is not called for any of the physical
- * cameras of a logical multi-camera, when {@link #onCameraAvailable} for the logical
- * multi-camera is invoked. If some specific physical cameras are unavailable
- * to begin with, {@link #onPhysicalCameraUnavailable} may be invoked after
- * {@link #onCameraAvailable}.</p>
+ * unavailable if the logical camera itself is unavailable.
+ * No availability callbacks will be called for any of the physical
+ * cameras of its parent logical multi-camera, when {@link #onCameraUnavailable} for
+ * the logical multi-camera is invoked.</p>
+ *
+ * <p>Limitation: Opening a logical camera disables the {@link #onPhysicalCameraAvailable}
+ * and {@link #onPhysicalCameraUnavailable} callbacks for its physical cameras. For example,
+ * if app A opens the camera device:</p>
+ *
+ * <ul>
+ *
+ * <li>All apps subscribing to ActivityCallback get {@link #onCameraUnavailable}.</li>
+ *
+ * <li>No app (including app A) subscribing to ActivityCallback gets
+ * {@link #onPhysicalCameraAvailable} or {@link #onPhysicalCameraUnavailable}, because
+ * the logical camera is unavailable (some app is using it).</li>
+ *
+ * </ul>
*
* <p>The default implementation of this method does nothing.</p>
*
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index 72d8122..0fd164d 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -1538,6 +1538,9 @@
case FINGERPRINT_ACQUIRED_TOO_BRIGHT:
return context.getString(
com.android.internal.R.string.fingerprint_acquired_too_bright);
+ case FINGERPRINT_ACQUIRED_POWER_PRESSED:
+ return context.getString(
+ com.android.internal.R.string.fingerprint_acquired_power_press);
case FINGERPRINT_ACQUIRED_VENDOR: {
String[] msgArray = context.getResources().getStringArray(
com.android.internal.R.array.fingerprint_acquired_vendor);
diff --git a/core/java/android/net/Ikev2VpnProfile.java b/core/java/android/net/Ikev2VpnProfile.java
index ba0546a..3979c6c 100644
--- a/core/java/android/net/Ikev2VpnProfile.java
+++ b/core/java/android/net/Ikev2VpnProfile.java
@@ -171,7 +171,7 @@
mPassword = password;
mRsaPrivateKey = rsaPrivateKey;
mUserCert = userCert;
- mProxyInfo = new ProxyInfo(proxyInfo);
+ mProxyInfo = (proxyInfo == null) ? null : new ProxyInfo(proxyInfo);
// UnmodifiableList doesn't make a defensive copy by default.
mAllowedAlgorithms = Collections.unmodifiableList(new ArrayList<>(allowedAlgorithms));
diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java
index 7e355d9..e845ffa 100644
--- a/core/java/android/os/Bundle.java
+++ b/core/java/android/os/Bundle.java
@@ -934,6 +934,12 @@
* you must call {@link #setClassLoader(ClassLoader)} with the proper {@link ClassLoader} first.
* Otherwise, this method might throw an exception or return {@code null}.
*
+ * <p><b>Warning: </b> the class that implements {@link Parcelable} has to be the immediately
+ * enclosing class of the runtime type of its CREATOR field (that is,
+ * {@link Class#getEnclosingClass()} has to return the parcelable implementing class),
+ * otherwise this method might throw an exception. If the Parcelable class does not enclose the
+ * CREATOR, use the deprecated {@link #getParcelable(String)} instead.
+ *
* @param key a String, or {@code null}
* @param clazz The type of the object expected
* @return a Parcelable value, or {@code null}
@@ -990,6 +996,13 @@
* you must call {@link #setClassLoader(ClassLoader)} with the proper {@link ClassLoader} first.
* Otherwise, this method might throw an exception or return {@code null}.
*
+ * <p><b>Warning: </b> if the list contains items implementing the {@link Parcelable} interface,
+ * the class that implements {@link Parcelable} has to be the immediately
+ * enclosing class of the runtime type of its CREATOR field (that is,
+ * {@link Class#getEnclosingClass()} has to return the parcelable implementing class),
+ * otherwise this method might throw an exception. If the Parcelable class does not enclose the
+ * CREATOR, use the deprecated {@link #getParcelableArray(String)} instead.
+ *
* @param key a String, or {@code null}
* @param clazz The type of the items inside the array. This is only verified when unparceling.
* @return a Parcelable[] value, or {@code null}
@@ -1054,6 +1067,13 @@
* you must call {@link #setClassLoader(ClassLoader)} with the proper {@link ClassLoader} first.
* Otherwise, this method might throw an exception or return {@code null}.
*
+ * <p><b>Warning: </b> if the list contains items implementing the {@link Parcelable} interface,
+ * the class that implements {@link Parcelable} has to be the immediately
+ * enclosing class of the runtime type of its CREATOR field (that is,
+ * {@link Class#getEnclosingClass()} has to return the parcelable implementing class),
+ * otherwise this method might throw an exception. If the Parcelable class does not enclose the
+ * CREATOR, use the deprecated {@link #getParcelableArrayList(String)} instead.
+ *
* @param key a String, or {@code null}
* @param clazz The type of the items inside the array list. This is only verified when
* unparceling.
@@ -1105,6 +1125,13 @@
* <li>The object is not of type {@code clazz}.
* </ul>
*
+ * <p><b>Warning: </b> if the list contains items implementing the {@link Parcelable} interface,
+ * the class that implements {@link Parcelable} has to be the immediately
+ * enclosing class of the runtime type of its CREATOR field (that is,
+ * {@link Class#getEnclosingClass()} has to return the parcelable implementing class),
+ * otherwise this method might throw an exception. If the Parcelable class does not enclose the
+ * CREATOR, use the deprecated {@link #getSparseParcelableArray(String)} instead.
+ *
* @param key a String, or null
* @param clazz The type of the items inside the sparse array. This is only verified when
* unparceling.
diff --git a/core/java/android/os/IVibratorManagerService.aidl b/core/java/android/os/IVibratorManagerService.aidl
index a0d6ce1..fb9752f 100644
--- a/core/java/android/os/IVibratorManagerService.aidl
+++ b/core/java/android/os/IVibratorManagerService.aidl
@@ -30,7 +30,7 @@
boolean unregisterVibratorStateListener(int vibratorId, in IVibratorStateListener listener);
boolean setAlwaysOnEffect(int uid, String opPkg, int alwaysOnId,
in CombinedVibration vibration, in VibrationAttributes attributes);
- void vibrate(int uid, String opPkg, in CombinedVibration vibration,
+ void vibrate(int uid, int displayId, String opPkg, in CombinedVibration vibration,
in VibrationAttributes attributes, String reason, IBinder token);
void cancelVibrate(int usageFilter, IBinder token);
}
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index 2664f05..3d70138 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -3235,6 +3235,13 @@
* Same as {@link #readList(List, ClassLoader)} but accepts {@code clazz} parameter as
* the type required for each item.
*
+ * <p><b>Warning: </b> if the list contains items implementing the {@link Parcelable} interface,
+ * the class that implements {@link Parcelable} has to be the immediately
+ * enclosing class of the runtime type of its CREATOR field (that is,
+ * {@link Class#getEnclosingClass()} has to return the parcelable implementing class),
+ * otherwise this method might throw an exception. If the Parcelable class does not enclose the
+ * CREATOR, use the deprecated {@link #readList(List, ClassLoader)} instead.
+ *
* @throws BadParcelableException Throws BadParcelableException if the item to be deserialized
* is not an instance of that class or any of its children classes or there was an error
* trying to instantiate an element.
@@ -3463,6 +3470,13 @@
* Same as {@link #readArrayList(ClassLoader)} but accepts {@code clazz} parameter as
* the type required for each item.
*
+ * <p><b>Warning: </b> if the list contains items implementing the {@link Parcelable} interface,
+ * the class that implements {@link Parcelable} has to be the immediately
+ * enclosing class of the runtime type of its CREATOR field (that is,
+ * {@link Class#getEnclosingClass()} has to return the parcelable implementing class),
+ * otherwise this method might throw an exception. If the Parcelable class does not enclose the
+ * CREATOR, use the deprecated {@link #readArrayList(ClassLoader)} instead.
+ *
* @throws BadParcelableException Throws BadParcelableException if the item to be deserialized
* is not an instance of that class or any of its children classes or there was an error
* trying to instantiate an element.
@@ -3497,6 +3511,13 @@
* Same as {@link #readArray(ClassLoader)} but accepts {@code clazz} parameter as
* the type required for each item.
*
+ * <p><b>Warning: </b> if the list contains items implementing the {@link Parcelable} interface,
+ * the class that implements {@link Parcelable} has to be the immediately
+ * enclosing class of the runtime type of its CREATOR field (that is,
+ * {@link Class#getEnclosingClass()} has to return the parcelable implementing class),
+ * otherwise this method might throw an exception. If the Parcelable class does not enclose the
+ * CREATOR, use the deprecated {@link #readArray(ClassLoader)} instead.
+ *
* @throws BadParcelableException Throws BadParcelableException if the item to be deserialized
* is not an instance of that class or any of its children classes or there was an error
* trying to instantiate an element.
@@ -3530,6 +3551,13 @@
* Same as {@link #readSparseArray(ClassLoader)} but accepts {@code clazz} parameter as
* the type required for each item.
*
+ * <p><b>Warning: </b> if the list contains items implementing the {@link Parcelable} interface,
+ * the class that implements {@link Parcelable} has to be the immediately
+ * enclosing class of the runtime type of its CREATOR field (that is,
+ * {@link Class#getEnclosingClass()} has to return the parcelable implementing class),
+ * otherwise this method might throw an exception. If the Parcelable class does not enclose the
+ * CREATOR, use the deprecated {@link #readSparseArray(ClassLoader)} instead.
+ *
* @throws BadParcelableException Throws BadParcelableException if the item to be deserialized
* is not an instance of that class or any of its children classes or there was an error
* trying to instantiate an element.
@@ -3847,6 +3875,13 @@
* Same as {@link #readParcelableList(List, ClassLoader)} but accepts {@code clazz} parameter as
* the type required for each item.
*
+ * <p><b>Warning: </b> if the list contains items implementing the {@link Parcelable} interface,
+ * the class that implements {@link Parcelable} has to be the immediately
+ * enclosing class of the runtime type of its CREATOR field (that is,
+ * {@link Class#getEnclosingClass()} has to return the parcelable implementing class),
+ * otherwise this method might throw an exception. If the Parcelable class does not enclose the
+ * CREATOR, use the deprecated {@link #readParcelableList(List, ClassLoader)} instead.
+ *
* @throws BadParcelableException Throws BadParcelableException if the item to be deserialized
* is not an instance of that class or any of its children classes or there was an error
* trying to instantiate an element.
@@ -4744,6 +4779,12 @@
* Same as {@link #readParcelable(ClassLoader)} but accepts {@code clazz} parameter as the type
* required for each item.
*
+ * <p><b>Warning: </b> the class that implements {@link Parcelable} has to be the immediately
+ * enclosing class of the runtime type of its CREATOR field (that is,
+ * {@link Class#getEnclosingClass()} has to return the parcelable implementing class),
+ * otherwise this method might throw an exception. If the Parcelable class does not enclose the
+ * CREATOR, use the deprecated {@link #readParcelable(ClassLoader)} instead.
+ *
* @throws BadParcelableException Throws BadParcelableException if the item to be deserialized
* is not an instance of that class or any of its children classes or there was an error
* trying to instantiate an element.
@@ -4812,6 +4853,12 @@
* Same as {@link #readParcelableCreator(ClassLoader)} but accepts {@code clazz} parameter
* as the required type.
*
+ * <p><b>Warning: </b> the class that implements {@link Parcelable} has to be the immediately
+ * enclosing class of the runtime type of its CREATOR field (that is,
+ * {@link Class#getEnclosingClass()} has to return the parcelable implementing class),
+ * otherwise this method might throw an exception. If the Parcelable class does not enclose the
+ * CREATOR, use the deprecated {@link #readParcelableCreator(ClassLoader) instead.
+ *
* @throws BadParcelableException Throws BadParcelableException if the item to be deserialized
* is not an instance of that class or any of its children classes or there there was an error
* trying to read the {@link Parcelable.Creator}.
@@ -4939,6 +4986,12 @@
* Same as {@link #readParcelableArray(ClassLoader)} but accepts {@code clazz} parameter as
* the type required for each item.
*
+ * <p><b>Warning: </b> the class that implements {@link Parcelable} has to be the immediately
+ * enclosing class of the runtime type of its CREATOR field (that is,
+ * {@link Class#getEnclosingClass()} has to return the parcelable implementing class),
+ * otherwise this method might throw an exception. If the Parcelable class does not enclose the
+ * CREATOR, use the deprecated {@link #readParcelableArray(ClassLoader)} instead.
+ *
* @throws BadParcelableException Throws BadParcelableException if the item to be deserialized
* is not an instance of that class or any of its children classes or there was an error
* trying to instantiate an element.
diff --git a/core/java/android/os/SystemVibratorManager.java b/core/java/android/os/SystemVibratorManager.java
index c690df2..eb2a712 100644
--- a/core/java/android/os/SystemVibratorManager.java
+++ b/core/java/android/os/SystemVibratorManager.java
@@ -137,7 +137,8 @@
return;
}
try {
- mService.vibrate(uid, opPkg, effect, attributes, reason, mToken);
+ mService.vibrate(uid, mContext.getAssociatedDisplayId(), opPkg, effect, attributes,
+ reason, mToken);
} catch (RemoteException e) {
Log.w(TAG, "Failed to vibrate.", e);
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 1fcdd60..b964e1c 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6660,6 +6660,26 @@
public static final String BLUETOOTH_ADDR_VALID = "bluetooth_addr_valid";
/**
+ * This is used by LocalBluetoothLeBroadcast to store the broadcast program info.
+ * @hide
+ */
+ public static final String BLUETOOTH_LE_BROADCAST_PROGRAM_INFO =
+ "bluetooth_le_broadcast_program_info";
+
+ /**
+ * This is used by LocalBluetoothLeBroadcast to store the broadcast code.
+ * @hide
+ */
+ public static final String BLUETOOTH_LE_BROADCAST_CODE = "bluetooth_le_broadcast_code";
+
+ /**
+ * This is used by LocalBluetoothLeBroadcast to store the app source name.
+ * @hide
+ */
+ public static final String BLUETOOTH_LE_BROADCAST_APP_SOURCE_NAME =
+ "bluetooth_le_broadcast_app_source_name";
+
+ /**
* Setting to indicate that on device captions are enabled.
*
* @hide
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index 2d461c6..7515538 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -22,6 +22,7 @@
import android.annotation.Nullable;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.TestApi;
import android.app.Activity;
import android.app.ActivityTaskManager;
import android.app.AlarmManager;
@@ -1124,7 +1125,8 @@
* @hide
*/
@Nullable
- public static DreamMetadata getDreamMetadata(Context context,
+ @TestApi
+ public static DreamMetadata getDreamMetadata(@NonNull Context context,
@Nullable ServiceInfo serviceInfo) {
if (serviceInfo == null) return null;
@@ -1183,7 +1185,8 @@
}
}
- private static ComponentName convertToComponentName(String flattenedString,
+ @Nullable
+ private static ComponentName convertToComponentName(@Nullable String flattenedString,
ServiceInfo serviceInfo) {
if (flattenedString == null) {
return null;
@@ -1193,7 +1196,17 @@
return new ComponentName(serviceInfo.packageName, flattenedString);
}
- return ComponentName.unflattenFromString(flattenedString);
+ // Ensure that the component is from the same package as the dream service. If not,
+ // treat the component as invalid and return null instead.
+ final ComponentName cn = ComponentName.unflattenFromString(flattenedString);
+ if (cn == null) return null;
+ if (!cn.getPackageName().equals(serviceInfo.packageName)) {
+ Log.w(TAG,
+ "Inconsistent package name in component: " + cn.getPackageName()
+ + ", should be: " + serviceInfo.packageName);
+ return null;
+ }
+ return cn;
}
/**
@@ -1489,6 +1502,7 @@
*
* @hide
*/
+ @TestApi
public static final class DreamMetadata {
@Nullable
public final ComponentName settingsActivity;
diff --git a/core/java/android/service/trust/TrustAgentService.java b/core/java/android/service/trust/TrustAgentService.java
index 559313a..41345e0 100644
--- a/core/java/android/service/trust/TrustAgentService.java
+++ b/core/java/android/service/trust/TrustAgentService.java
@@ -141,7 +141,9 @@
*
* Without this flag, the message passed to {@code grantTrust} is only used for debugging
* purposes. With the flag, it may be displayed to the user as the reason why the device is
- * unlocked.
+ * unlocked. If this flag isn't set OR the message is set to null, the device will display
+ * its own default message for trust granted. If the TrustAgent intentionally doesn't want to
+ * show any message, then it can set this flag AND set the message to an empty string.
*/
public static final int FLAG_GRANT_TRUST_DISPLAY_MESSAGE = 1 << 3;
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 14cfe6a..01749c0 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -519,7 +519,7 @@
* {@link #addLocalColorsAreas(List)}
* {@link #removeLocalColorsAreas(List)}
* When local colors change, call {@link #notifyLocalColorsChanged(List, List)}
- * See {@link com.android.systemui.ImageWallpaper} for an example
+ * See {@link com.android.systemui.wallpapers.ImageWallpaper} for an example
* @hide
*/
public boolean supportsLocalColorExtraction() {
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index c102ad3..c198098 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -349,20 +349,6 @@
return insets;
}
- // TODO: Remove this once the task bar is treated as navigation bar.
- public Insets calculateInsetsWithInternalTypes(Rect frame, @InternalInsetsType int[] types,
- boolean ignoreVisibility) {
- Insets insets = Insets.NONE;
- for (int i = types.length - 1; i >= 0; i--) {
- InsetsSource source = mSources[types[i]];
- if (source == null) {
- continue;
- }
- insets = Insets.max(source.calculateInsets(frame, ignoreVisibility), insets);
- }
- return insets;
- }
-
public Insets calculateInsets(Rect frame, @InsetsType int types,
InsetsVisibilities overrideVisibilities) {
Insets insets = Insets.NONE;
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index ba6ba63..b0d4657 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -12709,7 +12709,6 @@
if (mViewTranslationCallback != null) {
mViewTranslationCallback.onClearTranslation(this);
}
- clearViewTranslationCallback();
clearViewTranslationResponse();
if (hasTranslationTransientState()) {
setHasTransientState(false);
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index e673041..ec6b4ac 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -284,7 +284,7 @@
* @hide
*/
public static final boolean LOCAL_LAYOUT =
- SystemProperties.getBoolean("persist.debug.local_layout", true);
+ SystemProperties.getBoolean("persist.debug.local_layout", false);
/**
* Set this system property to true to force the view hierarchy to render
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 2195b83..218ca58 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -285,12 +285,18 @@
int TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER = 21;
/**
- * Keyguard is being occluded.
+ * Keyguard is being occluded by non-Dream.
* @hide
*/
int TRANSIT_OLD_KEYGUARD_OCCLUDE = 22;
/**
+ * Keyguard is being occluded by Dream.
+ * @hide
+ */
+ int TRANSIT_OLD_KEYGUARD_OCCLUDE_BY_DREAM = 33;
+
+ /**
* Keyguard is being unoccluded.
* @hide
*/
diff --git a/core/java/android/window/TaskFragmentOrganizer.java b/core/java/android/window/TaskFragmentOrganizer.java
index 649785a..648541b 100644
--- a/core/java/android/window/TaskFragmentOrganizer.java
+++ b/core/java/android/window/TaskFragmentOrganizer.java
@@ -35,7 +35,6 @@
import android.annotation.Nullable;
import android.annotation.TestApi;
import android.app.WindowConfiguration;
-import android.content.Intent;
import android.content.res.Configuration;
import android.os.Bundle;
import android.os.IBinder;
@@ -203,7 +202,7 @@
* Routes to {@link ITaskFragmentOrganizerController#applyTransaction} instead of
* {@link IWindowOrganizerController#applyTransaction} for the different transition options.
*
- * @see #applyTransaction(WindowContainerTransaction, int, boolean, boolean)
+ * @see #applyTransaction(WindowContainerTransaction, int, boolean)
*/
@Override
public void applyTransaction(@NonNull WindowContainerTransaction wct) {
@@ -285,72 +284,30 @@
* Called when a TaskFragment is created and organized by this organizer.
*
* @param taskFragmentInfo Info of the TaskFragment that is created.
- * @deprecated Use {@link #onTaskFragmentAppeared(WindowContainerTransaction, TaskFragmentInfo)}
- * instead.
+ * @deprecated Use {@link #onTransactionReady(TaskFragmentTransaction)} instead.
*/
@Deprecated
public void onTaskFragmentAppeared(@NonNull TaskFragmentInfo taskFragmentInfo) {}
/**
- * Called when a TaskFragment is created and organized by this organizer.
- *
- * @param wct The {@link WindowContainerTransaction} to make any changes with if needed. No
- * need to call {@link #applyTransaction} as it will be applied by the caller.
- * @param taskFragmentInfo Info of the TaskFragment that is created.
- */
- public void onTaskFragmentAppeared(@NonNull WindowContainerTransaction wct,
- @NonNull TaskFragmentInfo taskFragmentInfo) {
- // TODO(b/240519866): doing so to keep CTS compatibility. Remove in the next release.
- onTaskFragmentAppeared(taskFragmentInfo);
- }
-
- /**
* Called when the status of an organized TaskFragment is changed.
*
* @param taskFragmentInfo Info of the TaskFragment that is changed.
- * @deprecated Use {@link #onTaskFragmentInfoChanged(WindowContainerTransaction,
- * TaskFragmentInfo)} instead.
+ * @deprecated Use {@link #onTransactionReady(TaskFragmentTransaction)} instead.
*/
@Deprecated
public void onTaskFragmentInfoChanged(@NonNull TaskFragmentInfo taskFragmentInfo) {}
/**
- * Called when the status of an organized TaskFragment is changed.
- *
- * @param wct The {@link WindowContainerTransaction} to make any changes with if needed. No
- * need to call {@link #applyTransaction} as it will be applied by the caller.
- * @param taskFragmentInfo Info of the TaskFragment that is changed.
- */
- public void onTaskFragmentInfoChanged(@NonNull WindowContainerTransaction wct,
- @NonNull TaskFragmentInfo taskFragmentInfo) {
- // TODO(b/240519866): doing so to keep CTS compatibility. Remove in the next release.
- onTaskFragmentInfoChanged(taskFragmentInfo);
- }
-
- /**
* Called when an organized TaskFragment is removed.
*
* @param taskFragmentInfo Info of the TaskFragment that is removed.
- * @deprecated Use {@link #onTaskFragmentVanished(WindowContainerTransaction,
- * TaskFragmentInfo)} instead.
+ * @deprecated Use {@link #onTransactionReady(TaskFragmentTransaction)} instead.
*/
@Deprecated
public void onTaskFragmentVanished(@NonNull TaskFragmentInfo taskFragmentInfo) {}
/**
- * Called when an organized TaskFragment is removed.
- *
- * @param wct The {@link WindowContainerTransaction} to make any changes with if needed. No
- * need to call {@link #applyTransaction} as it will be applied by the caller.
- * @param taskFragmentInfo Info of the TaskFragment that is removed.
- */
- public void onTaskFragmentVanished(@NonNull WindowContainerTransaction wct,
- @NonNull TaskFragmentInfo taskFragmentInfo) {
- // TODO(b/240519866): doing so to keep CTS compatibility. Remove in the next release.
- onTaskFragmentVanished(taskFragmentInfo);
- }
-
- /**
* Called when the parent leaf Task of organized TaskFragments is changed.
* When the leaf Task is changed, the organizer may want to update the TaskFragments in one
* transaction.
@@ -361,94 +318,26 @@
*
* @param fragmentToken The parent Task this TaskFragment is changed.
* @param parentConfig Config of the parent Task.
- * @deprecated Use {@link #onTaskFragmentParentInfoChanged(WindowContainerTransaction, int,
- * Configuration)} instead.
+ * @deprecated Use {@link #onTransactionReady(TaskFragmentTransaction)} instead.
*/
@Deprecated
public void onTaskFragmentParentInfoChanged(
@NonNull IBinder fragmentToken, @NonNull Configuration parentConfig) {}
/**
- * Called when the parent leaf Task of organized TaskFragments is changed.
- * When the leaf Task is changed, the organizer may want to update the TaskFragments in one
- * transaction.
- *
- * For case like screen size change, it will trigger onTaskFragmentParentInfoChanged with new
- * Task bounds, but may not trigger onTaskFragmentInfoChanged because there can be an override
- * bounds.
- *
- * @param wct The {@link WindowContainerTransaction} to make any changes with if needed. No
- * need to call {@link #applyTransaction} as it will be applied by the caller.
- * @param taskId Id of the parent Task that is changed.
- * @param parentConfig Config of the parent Task.
- */
- public void onTaskFragmentParentInfoChanged(@NonNull WindowContainerTransaction wct, int taskId,
- @NonNull Configuration parentConfig) {
- // TODO(b/240519866): doing so to keep CTS compatibility. Remove in the next release.
- final List<IBinder> tokens = mTaskIdToFragmentTokens.get(taskId);
- if (tokens == null || tokens.isEmpty()) {
- return;
- }
- for (int i = tokens.size() - 1; i >= 0; i--) {
- onTaskFragmentParentInfoChanged(tokens.get(i), parentConfig);
- }
- }
-
- /**
* Called when the {@link WindowContainerTransaction} created with
* {@link WindowContainerTransaction#setErrorCallbackToken(IBinder)} failed on the server side.
*
* @param errorCallbackToken token set in
* {@link WindowContainerTransaction#setErrorCallbackToken(IBinder)}
* @param exception exception from the server side.
- * @deprecated Use {@link #onTaskFragmentError(WindowContainerTransaction, IBinder,
- * TaskFragmentInfo, int, Throwable)} instead.
+ * @deprecated Use {@link #onTransactionReady(TaskFragmentTransaction)} instead.
*/
@Deprecated
public void onTaskFragmentError(
@NonNull IBinder errorCallbackToken, @NonNull Throwable exception) {}
/**
- * Called when the {@link WindowContainerTransaction} created with
- * {@link WindowContainerTransaction#setErrorCallbackToken(IBinder)} failed on the server side.
- *
- * @param wct The {@link WindowContainerTransaction} to make any changes with if needed. No
- * need to call {@link #applyTransaction} as it will be applied by the caller.
- * @param errorCallbackToken token set in
- * {@link WindowContainerTransaction#setErrorCallbackToken(IBinder)}
- * @param taskFragmentInfo The {@link TaskFragmentInfo}. This could be {@code null} if no
- * TaskFragment created.
- * @param opType The {@link WindowContainerTransaction.HierarchyOp} of the failed
- * transaction operation.
- * @param exception exception from the server side.
- */
- public void onTaskFragmentError(@NonNull WindowContainerTransaction wct,
- @NonNull IBinder errorCallbackToken, @Nullable TaskFragmentInfo taskFragmentInfo,
- int opType, @NonNull Throwable exception) {
- // Doing so to keep compatibility. This will be removed in the next release.
- onTaskFragmentError(errorCallbackToken, exception);
- }
-
- /**
- * Called when an Activity is reparented to the Task with organized TaskFragment. For example,
- * when an Activity enters and then exits Picture-in-picture, it will be reparented back to its
- * original Task. In this case, we need to notify the organizer so that it can check if the
- * Activity matches any split rule.
- *
- * @param wct The {@link WindowContainerTransaction} to make any changes with if needed. No
- * need to call {@link #applyTransaction} as it will be applied by the caller.
- * @param taskId The Task that the activity is reparented to.
- * @param activityIntent The intent that the activity is original launched with.
- * @param activityToken If the activity belongs to the same process as the organizer, this
- * will be the actual activity token; if the activity belongs to a
- * different process, the server will generate a temporary token that
- * the organizer can use to reparent the activity through
- * {@link WindowContainerTransaction} if needed.
- */
- public void onActivityReparentedToTask(@NonNull WindowContainerTransaction wct,
- int taskId, @NonNull Intent activityIntent, @NonNull IBinder activityToken) {}
-
- /**
* Called when the transaction is ready so that the organizer can update the TaskFragments based
* on the changes in transaction.
* @hide
@@ -463,23 +352,18 @@
final int taskId = change.getTaskId();
switch (change.getType()) {
case TYPE_TASK_FRAGMENT_APPEARED:
- // TODO(b/240519866): doing so to keep CTS compatibility. Remove in the next
- // release.
if (!mTaskIdToFragmentTokens.contains(taskId)) {
mTaskIdToFragmentTokens.put(taskId, new ArrayList<>());
}
mTaskIdToFragmentTokens.get(taskId).add(change.getTaskFragmentToken());
onTaskFragmentParentInfoChanged(change.getTaskFragmentToken(),
mTaskIdToConfigurations.get(taskId));
-
- onTaskFragmentAppeared(wct, change.getTaskFragmentInfo());
+ onTaskFragmentAppeared(change.getTaskFragmentInfo());
break;
case TYPE_TASK_FRAGMENT_INFO_CHANGED:
- onTaskFragmentInfoChanged(wct, change.getTaskFragmentInfo());
+ onTaskFragmentInfoChanged(change.getTaskFragmentInfo());
break;
case TYPE_TASK_FRAGMENT_VANISHED:
- // TODO(b/240519866): doing so to keep CTS compatibility. Remove in the next
- // release.
if (mTaskIdToFragmentTokens.contains(taskId)) {
final List<IBinder> tokens = mTaskIdToFragmentTokens.get(taskId);
tokens.remove(change.getTaskFragmentToken());
@@ -488,33 +372,30 @@
mTaskIdToConfigurations.remove(taskId);
}
}
-
- onTaskFragmentVanished(wct, change.getTaskFragmentInfo());
+ onTaskFragmentVanished(change.getTaskFragmentInfo());
break;
case TYPE_TASK_FRAGMENT_PARENT_INFO_CHANGED:
- // TODO(b/240519866): doing so to keep CTS compatibility. Remove in the next
- // release.
- mTaskIdToConfigurations.put(taskId, change.getTaskConfiguration());
-
- onTaskFragmentParentInfoChanged(wct, taskId, change.getTaskConfiguration());
+ final Configuration parentConfig = change.getTaskConfiguration();
+ mTaskIdToConfigurations.put(taskId, parentConfig);
+ final List<IBinder> tokens = mTaskIdToFragmentTokens.get(taskId);
+ if (tokens == null || tokens.isEmpty()) {
+ break;
+ }
+ for (int i = tokens.size() - 1; i >= 0; i--) {
+ onTaskFragmentParentInfoChanged(tokens.get(i), parentConfig);
+ }
break;
case TYPE_TASK_FRAGMENT_ERROR:
final Bundle errorBundle = change.getErrorBundle();
onTaskFragmentError(
- wct,
change.getErrorCallbackToken(),
- errorBundle.getParcelable(
- KEY_ERROR_CALLBACK_TASK_FRAGMENT_INFO, TaskFragmentInfo.class),
- errorBundle.getInt(KEY_ERROR_CALLBACK_OP_TYPE),
errorBundle.getSerializable(KEY_ERROR_CALLBACK_THROWABLE,
java.lang.Throwable.class));
break;
case TYPE_ACTIVITY_REPARENTED_TO_TASK:
- onActivityReparentedToTask(
- wct,
- change.getTaskId(),
- change.getActivityIntent(),
- change.getActivityToken());
+ // This is for CTS compat:
+ // There is no TestApi for CTS to handle this type of change, but we don't want
+ // it to throw exception as default. This has been updated in next release.
break;
default:
throw new IllegalArgumentException(
diff --git a/core/java/android/window/TaskFragmentTransaction.java b/core/java/android/window/TaskFragmentTransaction.java
index 84a5fea..413c0dd 100644
--- a/core/java/android/window/TaskFragmentTransaction.java
+++ b/core/java/android/window/TaskFragmentTransaction.java
@@ -21,6 +21,7 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SuppressLint;
import android.content.Intent;
import android.content.res.Configuration;
import android.os.Binder;
@@ -63,6 +64,7 @@
dest.writeTypedList(mChanges);
}
+ @NonNull
public IBinder getTransactionToken() {
return mTransactionToken;
}
@@ -105,6 +107,7 @@
return 0;
}
+ @NonNull
public static final Creator<TaskFragmentTransaction> CREATOR = new Creator<>() {
@Override
public TaskFragmentTransaction createFromParcel(Parcel in) {
@@ -218,24 +221,28 @@
}
/** The change is related to the TaskFragment created with this unique token. */
+ @NonNull
public Change setTaskFragmentToken(@NonNull IBinder taskFragmentToken) {
mTaskFragmentToken = requireNonNull(taskFragmentToken);
return this;
}
/** Info of the embedded TaskFragment. */
+ @NonNull
public Change setTaskFragmentInfo(@NonNull TaskFragmentInfo info) {
mTaskFragmentInfo = requireNonNull(info);
return this;
}
/** Task id the parent Task. */
+ @NonNull
public Change setTaskId(int taskId) {
mTaskId = taskId;
return this;
}
/** Configuration of the parent Task. */
+ @NonNull
public Change setTaskConfiguration(@NonNull Configuration configuration) {
mTaskConfiguration = requireNonNull(configuration);
return this;
@@ -246,6 +253,7 @@
* from the {@link TaskFragmentOrganizer}, it may come with an error callback token to
* report back.
*/
+ @NonNull
public Change setErrorCallbackToken(@Nullable IBinder errorCallbackToken) {
mErrorCallbackToken = errorCallbackToken;
return this;
@@ -255,6 +263,7 @@
* Bundle with necessary info about the failure operation of
* {@link #TYPE_TASK_FRAGMENT_ERROR}.
*/
+ @NonNull
public Change setErrorBundle(@NonNull Bundle errorBundle) {
mErrorBundle = requireNonNull(errorBundle);
return this;
@@ -264,6 +273,7 @@
* Intent of the activity that is reparented to the Task for
* {@link #TYPE_ACTIVITY_REPARENTED_TO_TASK}.
*/
+ @NonNull
public Change setActivityIntent(@NonNull Intent intent) {
mActivityIntent = requireNonNull(intent);
return this;
@@ -276,6 +286,7 @@
* a temporary token that the organizer can use to reparent the activity through
* {@link WindowContainerTransaction} if needed.
*/
+ @NonNull
public Change setActivityToken(@NonNull IBinder activityToken) {
mActivityToken = requireNonNull(activityToken);
return this;
@@ -310,11 +321,12 @@
return mErrorCallbackToken;
}
- @Nullable
+ @NonNull
public Bundle getErrorBundle() {
- return mErrorBundle;
+ return mErrorBundle != null ? mErrorBundle : Bundle.EMPTY;
}
+ @SuppressLint("IntentBuilderName") // This is not creating new Intent.
@Nullable
public Intent getActivityIntent() {
return mActivityIntent;
@@ -335,6 +347,7 @@
return 0;
}
+ @NonNull
public static final Creator<Change> CREATOR = new Creator<>() {
@Override
public Change createFromParcel(Parcel in) {
diff --git a/core/java/android/window/TransitionInfo.java b/core/java/android/window/TransitionInfo.java
index dc1f612..8ca763e 100644
--- a/core/java/android/window/TransitionInfo.java
+++ b/core/java/android/window/TransitionInfo.java
@@ -397,6 +397,8 @@
private @Surface.Rotation int mEndFixedRotation = ROTATION_UNDEFINED;
private int mRotationAnimation = ROTATION_ANIMATION_UNSPECIFIED;
private @ColorInt int mBackgroundColor;
+ private SurfaceControl mSnapshot = null;
+ private float mSnapshotLuma;
public Change(@Nullable WindowContainerToken container, @NonNull SurfaceControl leash) {
mContainer = container;
@@ -420,6 +422,8 @@
mEndFixedRotation = in.readInt();
mRotationAnimation = in.readInt();
mBackgroundColor = in.readInt();
+ mSnapshot = in.readTypedObject(SurfaceControl.CREATOR);
+ mSnapshotLuma = in.readFloat();
}
/** Sets the parent of this change's container. The parent must be a participant or null. */
@@ -489,6 +493,12 @@
mBackgroundColor = backgroundColor;
}
+ /** Sets a snapshot surface for the "start" state of the container. */
+ public void setSnapshot(@Nullable SurfaceControl snapshot, float luma) {
+ mSnapshot = snapshot;
+ mSnapshotLuma = luma;
+ }
+
/** @return the container that is changing. May be null if non-remotable (eg. activity) */
@Nullable
public WindowContainerToken getContainer() {
@@ -587,6 +597,17 @@
return mBackgroundColor;
}
+ /** @return a snapshot surface (if applicable). */
+ @Nullable
+ public SurfaceControl getSnapshot() {
+ return mSnapshot;
+ }
+
+ /** @return the luma calculated for the snapshot surface (if applicable). */
+ public float getSnapshotLuma() {
+ return mSnapshotLuma;
+ }
+
/** @hide */
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
@@ -605,6 +626,8 @@
dest.writeInt(mEndFixedRotation);
dest.writeInt(mRotationAnimation);
dest.writeInt(mBackgroundColor);
+ dest.writeTypedObject(mSnapshot, flags);
+ dest.writeFloat(mSnapshotLuma);
}
@NonNull
@@ -629,11 +652,13 @@
@Override
public String toString() {
- return "{" + mContainer + "(" + mParent + ") leash=" + mLeash
+ String out = "{" + mContainer + "(" + mParent + ") leash=" + mLeash
+ " m=" + modeToString(mMode) + " f=" + flagsToString(mFlags) + " sb="
+ mStartAbsBounds + " eb=" + mEndAbsBounds + " eo=" + mEndRelOffset + " r="
+ mStartRotation + "->" + mEndRotation + ":" + mRotationAnimation
- + " endFixedRotation=" + mEndFixedRotation + "}";
+ + " endFixedRotation=" + mEndFixedRotation;
+ if (mSnapshot != null) out += " snapshot=" + mSnapshot;
+ return out + "}";
}
}
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index fbabf52..8f0fc2d 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -63,6 +63,7 @@
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
+import android.graphics.Insets;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.drawable.AnimatedVectorDrawable;
@@ -141,11 +142,13 @@
import java.net.URISyntaxException;
import java.text.Collator;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.function.Supplier;
/**
@@ -281,6 +284,7 @@
private long mQueriedSharingShortcutsTimeMs;
private int mCurrAvailableWidth = 0;
+ private Insets mLastAppliedInsets = null;
private int mLastNumberOfChildren = -1;
private int mMaxTargetsPerRow = 1;
@@ -1619,6 +1623,8 @@
if (mChooserMultiProfilePagerAdapter.getInactiveListAdapter() != null) {
mChooserMultiProfilePagerAdapter.getInactiveListAdapter().destroyAppPredictor();
}
+ mPersonalAppPredictor = null;
+ mWorkAppPredictor = null;
}
@Override // ResolverListCommunicator
@@ -2531,7 +2537,11 @@
|| gridAdapter.calculateChooserTargetWidth(availableWidth)
|| recyclerView.getAdapter() == null
|| availableWidth != mCurrAvailableWidth;
+
+ boolean insetsChanged = !Objects.equals(mLastAppliedInsets, mSystemWindowInsets);
+
if (isLayoutUpdated
+ || insetsChanged
|| mLastNumberOfChildren != recyclerView.getChildCount()) {
mCurrAvailableWidth = availableWidth;
if (isLayoutUpdated) {
@@ -2552,7 +2562,7 @@
return;
}
- if (mLastNumberOfChildren == recyclerView.getChildCount()) {
+ if (mLastNumberOfChildren == recyclerView.getChildCount() && !insetsChanged) {
return;
}
@@ -2563,6 +2573,7 @@
int offset = calculateDrawerOffset(top, bottom, recyclerView, gridAdapter);
mResolverDrawerLayout.setCollapsibleHeightReserved(offset);
mEnterTransitionAnimationDelegate.markOffsetCalculated();
+ mLastAppliedInsets = mSystemWindowInsets;
});
}
}
@@ -2929,12 +2940,14 @@
private void startFinishAnimation() {
View rootView = findRootView();
- rootView.startAnimation(new FinishAnimation(this, rootView));
+ if (rootView != null) {
+ rootView.startAnimation(new FinishAnimation(this, rootView));
+ }
}
private boolean maybeCancelFinishAnimation() {
View rootView = findRootView();
- Animation animation = rootView.getAnimation();
+ Animation animation = rootView == null ? null : rootView.getAnimation();
if (animation instanceof FinishAnimation) {
boolean hasEnded = animation.hasEnded();
animation.cancel();
@@ -3055,7 +3068,12 @@
mChooserMultiProfilePagerAdapter.setupContainerPadding(
getActiveEmptyStateView().findViewById(R.id.resolver_empty_state_container));
}
- return super.onApplyWindowInsets(v, insets);
+
+ WindowInsets result = super.onApplyWindowInsets(v, insets);
+ if (mResolverDrawerLayout != null) {
+ mResolverDrawerLayout.requestLayout();
+ }
+ return result;
}
private void setHorizontalScrollingEnabled(boolean enabled) {
@@ -3693,6 +3711,7 @@
this.mRows = rows;
this.mCellCountPerRow = cellCountPerRow;
this.mCellVisibility = new boolean[rows.size() * cellCountPerRow];
+ Arrays.fill(mCellVisibility, true);
this.mListAdapterSupplier = listAdapterSupplier;
}
@@ -4056,11 +4075,13 @@
*/
private static class FinishAnimation extends AlphaAnimation implements
Animation.AnimationListener {
+ @Nullable
private Activity mActivity;
+ @Nullable
private View mRootView;
private final float mFromAlpha;
- FinishAnimation(Activity activity, View rootView) {
+ FinishAnimation(@NonNull Activity activity, @NonNull View rootView) {
super(rootView.getAlpha(), 0.0f);
mActivity = activity;
mRootView = rootView;
@@ -4084,7 +4105,9 @@
@Override
public void cancel() {
- mRootView.setAlpha(mFromAlpha);
+ if (mRootView != null) {
+ mRootView.setAlpha(mFromAlpha);
+ }
cleanup();
super.cancel();
}
@@ -4095,9 +4118,10 @@
@Override
public void onAnimationEnd(Animation animation) {
- if (mActivity != null) {
- mActivity.finish();
- cleanup();
+ Activity activity = mActivity;
+ cleanup();
+ if (activity != null) {
+ activity.finish();
}
}
diff --git a/core/java/com/android/internal/policy/DividerSnapAlgorithm.java b/core/java/com/android/internal/policy/DividerSnapAlgorithm.java
index 527286cf0..a065e2b 100644
--- a/core/java/com/android/internal/policy/DividerSnapAlgorithm.java
+++ b/core/java/com/android/internal/policy/DividerSnapAlgorithm.java
@@ -287,7 +287,6 @@
int dividerMax = isHorizontalDivision
? mDisplayHeight
: mDisplayWidth;
- int navBarSize = isHorizontalDivision ? mInsets.bottom : mInsets.right;
int startPos = -mDividerSize;
if (dockedSide == DOCKED_RIGHT) {
startPos += mInsets.left;
@@ -308,8 +307,7 @@
addMinimizedTarget(isHorizontalDivision, dockedSide);
break;
}
- mTargets.add(new SnapTarget(dividerMax - navBarSize, dividerMax,
- SnapTarget.FLAG_DISMISS_END, 0.35f));
+ mTargets.add(new SnapTarget(dividerMax, dividerMax, SnapTarget.FLAG_DISMISS_END, 0.35f));
}
private void addNonDismissingTargets(boolean isHorizontalDivision, int topPosition,
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index 65bec0e..44cfe1a 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -264,11 +264,6 @@
void stopTracing();
/**
- * Handles a logging command from the WM shell command.
- */
- void handleWindowManagerLoggingCommand(in String[] args, in ParcelFileDescriptor outFd);
-
- /**
* If true, suppresses the ambient display from showing. If false, re-enables the ambient
* display.
*/
diff --git a/core/java/com/android/internal/widget/ConversationLayout.java b/core/java/com/android/internal/widget/ConversationLayout.java
index 4706aff..5f8acff 100644
--- a/core/java/com/android/internal/widget/ConversationLayout.java
+++ b/core/java/com/android/internal/widget/ConversationLayout.java
@@ -111,6 +111,7 @@
private Icon mLargeIcon;
private View mExpandButtonContainer;
private ViewGroup mExpandButtonAndContentContainer;
+ private ViewGroup mExpandButtonContainerA11yContainer;
private NotificationExpandButton mExpandButton;
private MessagingLinearLayout mImageMessageContainer;
private int mBadgeProtrusion;
@@ -234,6 +235,8 @@
});
mConversationText = findViewById(R.id.conversation_text);
mExpandButtonContainer = findViewById(R.id.expand_button_container);
+ mExpandButtonContainerA11yContainer =
+ findViewById(R.id.expand_button_a11y_container);
mConversationHeader = findViewById(R.id.conversation_header);
mContentContainer = findViewById(R.id.notification_action_list_margin_target);
mExpandButtonAndContentContainer = findViewById(R.id.expand_button_and_content_container);
@@ -1091,7 +1094,7 @@
newContainer = mExpandButtonAndContentContainer;
} else {
buttonGravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP;
- newContainer = this;
+ newContainer = mExpandButtonContainerA11yContainer;
}
mExpandButton.setExpanded(!mIsCollapsed);
diff --git a/core/proto/android/server/vibrator/vibratormanagerservice.proto b/core/proto/android/server/vibrator/vibratormanagerservice.proto
index 25a1f68..c211a5e 100644
--- a/core/proto/android/server/vibrator/vibratormanagerservice.proto
+++ b/core/proto/android/server/vibrator/vibratormanagerservice.proto
@@ -127,6 +127,7 @@
IGNORED_FOR_RINGER_MODE = 23;
IGNORED_FOR_SETTINGS = 24;
IGNORED_SUPERSEDED = 25;
+ IGNORED_FROM_VIRTUAL_DEVICE = 26;
}
}
diff --git a/core/res/res/layout/notification_template_material_conversation.xml b/core/res/res/layout/notification_template_material_conversation.xml
index 42fb4a2..ce8a904 100644
--- a/core/res/res/layout/notification_template_material_conversation.xml
+++ b/core/res/res/layout/notification_template_material_conversation.xml
@@ -89,45 +89,62 @@
<include layout="@layout/notification_material_action_list" />
</com.android.internal.widget.RemeasuringLinearLayout>
- <!--This is dynamically placed between here and at the end of the layout. It starts here since
- only FrameLayout layout params have gravity-->
+ <!--expand_button_a11y_container ensures talkback focus order is correct when view is expanded.
+ The -1px of marginTop and 1px of paddingTop make sure expand_button_a11y_container is prior to
+ its sibling view in accessibility focus order.
+ {see android.view.ViewGroup.addChildrenForAccessibility()}
+ expand_button_container will be moved under expand_button_and_content_container when collapsed,
+ this dynamic movement ensures message can flow under expand button when expanded-->
<FrameLayout
- android:id="@+id/expand_button_container"
- android:layout_width="wrap_content"
+ android:id="@+id/expand_button_a11y_container"
+ android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="end|top"
android:clipChildren="false"
- android:clipToPadding="false">
- <!--This layout makes sure that we can nicely center the expand content in the
- collapsed layout while the parent makes sure that we're never laid out bigger
- than the messaging content.-->
- <LinearLayout
- android:id="@+id/expand_button_touch_container"
+ android:clipToPadding="false"
+ android:layout_marginTop="-1px"
+ android:paddingTop="1px"
+ >
+ <!--expand_button_container is dynamically placed between here and at the end of the
+ layout. It starts here since only FrameLayout layout params have gravity-->
+ <FrameLayout
+ android:id="@+id/expand_button_container"
android:layout_width="wrap_content"
- android:layout_height="@dimen/conversation_expand_button_height"
- android:orientation="horizontal"
+ android:layout_height="match_parent"
android:layout_gravity="end|top"
- android:paddingEnd="0dp"
- android:clipToPadding="false"
android:clipChildren="false"
- >
- <!-- Images -->
- <com.android.internal.widget.MessagingLinearLayout
- android:id="@+id/conversation_image_message_container"
- android:forceHasOverlappingRendering="false"
- android:layout_width="40dp"
- android:layout_height="40dp"
- android:layout_marginStart="@dimen/conversation_image_start_margin"
- android:spacing="0dp"
- android:layout_gravity="center"
+ android:clipToPadding="false">
+ <!--expand_button_touch_container makes sure that we can nicely center the expand
+ content in the collapsed layout while the parent makes sure that we're never laid out
+ bigger than the messaging content.-->
+ <LinearLayout
+ android:id="@+id/expand_button_touch_container"
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/conversation_expand_button_height"
+ android:orientation="horizontal"
+ android:layout_gravity="end|top"
+ android:paddingEnd="0dp"
android:clipToPadding="false"
android:clipChildren="false"
- />
- <include layout="@layout/notification_expand_button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- />
- </LinearLayout>
+ >
+ <!-- Images -->
+ <com.android.internal.widget.MessagingLinearLayout
+ android:id="@+id/conversation_image_message_container"
+ android:forceHasOverlappingRendering="false"
+ android:layout_width="40dp"
+ android:layout_height="40dp"
+ android:layout_marginStart="@dimen/conversation_image_start_margin"
+ android:spacing="0dp"
+ android:layout_gravity="center"
+ android:clipToPadding="false"
+ android:clipChildren="false"
+ />
+ <include layout="@layout/notification_expand_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ />
+ </LinearLayout>
+ </FrameLayout>
</FrameLayout>
</com.android.internal.widget.ConversationLayout>
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index c8eefc7..1119ead 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -608,7 +608,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"Vingerafdrukhandeling is gekanselleer."</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Vingerafdrukhandeling is deur gebruiker gekanselleer."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"Te veel pogings. Probeer later weer."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Te veel pogings. Vingerafdruksensor is gedeaktiveer."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Te veel pogings. Gebruik eerder skermslot."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Probeer weer."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Geen vingerafdrukke is geregistreer nie."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Hierdie toetstel het nie \'n vingerafdruksensor nie."</string>
@@ -637,7 +637,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Besoek \'n verskaffer wat herstelwerk doen."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"Kan nie jou gesigmodel skep nie. Probeer weer."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Te helder. Probeer sagter beligting."</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"Probeer helderder beligting"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"Beweeg foon verder weg"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"Beweeg foon nader"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"Beweeg foon hoër op"</string>
@@ -1926,8 +1927,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"Streekvoorkeur"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Voer taalnaam in"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"Voorgestel"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Voorgestel"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"Alle tale"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"Allle streke"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"Soek"</string>
@@ -2050,8 +2050,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Gee <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> toegang tot alle toestelloglêers?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"Gee eenmalige toegang"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Moenie toelaat nie"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"Toestelloglêers teken aan wat op jou toestel gebeur. Programme kan hierdie loglêers gebruik om kwessies op te spoor en reg te stel.\n\nSommige loglêers bevat dalk sensitiewe inligting en daarom moet jy toegang tot alle toestelloglêers net gee aan programme wat jy vertrou. \n\nAs jy nie vir hierdie program toegang tot alle toestelloglêers gee nie, het die program steeds toegang tot eie loglêers. Jou toestelvervaardiger het dalk steeds toegang tot sommige loglêers of inligting op jou toestel."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Moenie weer wys nie"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> wil <xliff:g id="APP_2">%2$s</xliff:g>-skyfies wys"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Wysig"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 168e3e7..7f7cd10 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -111,8 +111,8 @@
<string name="roamingText0" msgid="7793257871609854208">"በዝውውር ላይ አመላካች በርቷል"</string>
<string name="roamingText1" msgid="5073028598334616445">"በዝውውር ላይ አመልካች ጠፍቷል"</string>
<string name="roamingText2" msgid="2834048284153110598">"በዝውውር ላይ አመልካች ብልጭ ብልጭ ይላል"</string>
- <string name="roamingText3" msgid="831690234035748988">"ከጎረቤት ውጪ"</string>
- <string name="roamingText4" msgid="2171252529065590728">"ከህንፃ ውጪ"</string>
+ <string name="roamingText3" msgid="831690234035748988">"ከጎረቤት ውጭ"</string>
+ <string name="roamingText4" msgid="2171252529065590728">"ከህንፃ ውጭ"</string>
<string name="roamingText5" msgid="4294671587635796641">"የዝውውር- ተመራጭ ስርዓት"</string>
<string name="roamingText6" msgid="5536156746637992029">"ዝውውር- ዝግጁ የሆነ ስርዓት"</string>
<string name="roamingText7" msgid="1783303085512907706">" የዝውውር- አጋር ስምምነት"</string>
@@ -433,7 +433,7 @@
<string name="permdesc_readCalendar" product="tablet" msgid="515452384059803326">"ይህ መተግበሪያ ሁሉንም በእርስዎ ጡባዊ ላይ የተከማቹ የቀን መቁጠሪያ ክስተቶችን ማንበብ ወይም የእርስዎን የቀን መቁጠሪያ ውሂብ ማስቀመጥ ይችላል።"</string>
<string name="permdesc_readCalendar" product="tv" msgid="5811726712981647628">"ይህ መተግበሪያ ሁሉንም በእርስዎ Android TV መሣሪያ ላይ የተከማቹ የቀን መቁጠሪያ ክስተቶችን ማንበብ ወይም የእርስዎን የቀን መቁጠሪያ ውሂብ ማስቀመጥ ይችላል።"</string>
<string name="permdesc_readCalendar" product="default" msgid="9118823807655829957">"ይህ መተግበሪያ ሁሉንም በእርስዎ ስልክ ላይ የተከማቹ የቀን መቁጠሪያ ክስተቶችን ማንበብ ወይም የእርስዎን የቀን መቁጠሪያ ውሂብ ማስቀመጥ ይችላል።"</string>
- <string name="permlab_writeCalendar" msgid="6422137308329578076">"የቀን መቁጠሪያ ክስተቶችን ቀይር ወይም አክል እና ለእንግዶች ከባለቤቱ ዕውቅና ውጪ ላክ።"</string>
+ <string name="permlab_writeCalendar" msgid="6422137308329578076">"የቀን መቁጠሪያ ክስተቶችን ቀይር ወይም አክል እና ለእንግዶች ከባለቤቱ ዕውቅና ውጭ ላክ።"</string>
<string name="permdesc_writeCalendar" product="tablet" msgid="8722230940717092850">"ይህ መተግበሪያ በእርስዎ ጡባዊ ላይ የቀን መቁጠሪያ ክስተቶችን ሊያክል፣ ሊያስወግድ ወይም ሊለውጥ ይችላል። ይህ መተግበሪያ ከቀን መቁጠሪያ የመጡ መስለው የሚታዩ መልእክቶችን ሊልክ ወይም ባለቤቶቹን ሳያሳውቅ ክስተቶችን ሊለውጥ ይችላል።"</string>
<string name="permdesc_writeCalendar" product="tv" msgid="951246749004952706">"ይህ መተግበሪያ በእርስዎ Android TV መሣሪያ ላይ የቀን መቁጠሪያ ክስተቶችን ሊያክል፣ ሊያስወግድ ወይም ሊለውጥ ይችላል። ይህ መተግበሪያ ከቀን መቁጠሪያ የመጡ መስለው የሚታዩ መልእክቶችን ሊልክ ወይም ባለቤቶቹን ሳያሳውቅ ክስተቶችን ሊለውጥ ይችላል።"</string>
<string name="permdesc_writeCalendar" product="default" msgid="5416380074475634233">"ይህ መተግበሪያ በእርስዎ ስልክ ላይ የቀን መቁጠሪያ ክስተቶችን ሊያክል፣ ሊያስወግድ ወይም ሊለውጥ ይችላል። ይህ መተግበሪያ ከቀን መቁጠሪያ የመጡ መስለው የሚታዩ መልእክቶችን ሊልክ ወይም ባለቤቶቹን ሳያሳውቅ ክስተቶችን ሊለውጥ ይችላል።"</string>
@@ -608,7 +608,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"የጣት አሻራ ስርዓተ ክወና ተትቷል።"</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"የጣት አሻራ ክወና በተጠቃሚ ተሰርዟል።"</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"ከልክ በላይ ብዙ ሙከራዎች። በኋላ ላይ እንደገና ይሞክሩ።"</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"በጣም ብዙ ሙከራዎች። የጣት አሻራ ዳሳሽ ተሰናክሏል።"</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"በጣም ብዙ ሙከራዎች። በምትኩ የማያ ገጽ መቆለፊያን ይጠቀሙ።"</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"እንደገና ይሞክሩ።"</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"ምንም የጣት አሻራዎች አልተመዘገቡም።"</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ይህ መሣሪያ የጣት አሻራ ዳሳሽ የለውም።"</string>
@@ -637,7 +637,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"የጥገና አገልግሎት ሰጪን ይጎብኙ።"</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"የመልክዎን ሞዴል መፍጠር አልተቻለም። እንደገና ይሞክሩ።"</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"ከልክ በላይ ፈካ ያለ። ይበልጥ ረጋ ያለ ብርሃን አጠቃቀምን ይሞክሩ።"</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"ከዚህ ፈካ ያለ ብርሃንን ይሞክሩ"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"ስልኩን ያርቁት"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"ስልኩን ያቅርቡት"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"ስልኩን ከፍ ወዳለ ቦታ ይውሰዱት"</string>
@@ -1165,7 +1166,7 @@
<string name="dialog_alert_title" msgid="651856561974090712">"ትኩረት"</string>
<string name="loading" msgid="3138021523725055037">"በመጫን ላይ…"</string>
<string name="capital_on" msgid="2770685323900821829">"በ"</string>
- <string name="capital_off" msgid="7443704171014626777">"ውጪ"</string>
+ <string name="capital_off" msgid="7443704171014626777">"ውጭ"</string>
<string name="checked" msgid="9179896827054513119">"ምልክት ተደርጎበታል"</string>
<string name="not_checked" msgid="7972320087569023342">"ምልክት አልተደረገበትም"</string>
<string name="selected" msgid="6614607926197755875">"ተመርጧል"</string>
@@ -1477,7 +1478,7 @@
<string name="permission_request_notification_title" msgid="1810025922441048273">"ፈቃድ ተጠይቋል"</string>
<string name="permission_request_notification_with_subtitle" msgid="3743417870360129298">\n" ለ<xliff:g id="ACCOUNT">%s</xliff:g> መለያ ፈቃድ ተጠይቋል"</string>
<string name="permission_request_notification_for_app_with_subtitle" msgid="1298704005732851350">"ለመለያ <xliff:g id="ACCOUNT">%2$s</xliff:g>\nበ<xliff:g id="APP">%1$s</xliff:g> የተጠየቀ ፈቃድ።"</string>
- <string name="forward_intent_to_owner" msgid="4620359037192871015">"ከስራ መገለጫዎ ውጪ ሆነው መተግበሪያ እየተጠቀሙ ነው"</string>
+ <string name="forward_intent_to_owner" msgid="4620359037192871015">"ከስራ መገለጫዎ ውጭ ሆነው መተግበሪያ እየተጠቀሙ ነው"</string>
<string name="forward_intent_to_work" msgid="3620262405636021151">"ይህን መተግበሪያ በእርስዎ የስራ መገለጫ ላይ እየተጠቀሙበት ነው"</string>
<string name="input_method_binding_label" msgid="1166731601721983656">"ግቤት ስልት"</string>
<string name="sync_binding_label" msgid="469249309424662147">"አስምር"</string>
@@ -1926,8 +1927,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"የክልል ምርጫ"</string>
<string name="search_language_hint" msgid="7004225294308793583">"የቋንቋ ስም ይተይቡ"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"የተጠቆሙ"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"በአስተያየት የተጠቆሙ"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"ሁሉም ቋንቋዎች"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"ሁሉም ክልሎች"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"ፈልግ"</string>
@@ -2050,8 +2050,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> ሁሉንም የመሣሪያ ምዝግብ ማስታወሻዎች እንዲደርስ ይፈቀድለት?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"የአንድ ጊዜ መዳረሻን ፍቀድ"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"አትፍቀድ"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"የመሣሪያ ምዝግብ ማስታወሻዎች በመሣሪያዎ ላይ ምን እንደሚከሰት ይመዘግባሉ። መተግበሪያዎች ችግሮችን ለማግኘት እና ለማስተካከል እነዚህን ምዝግብ ማስታወሻዎች መጠቀም ይችላሉ።\n\nአንዳንድ ምዝግብ ማስታወሻዎች ሚስጥራዊነት ያለው መረጃ ሊይዙ ይችላሉ፣ ስለዚህ የሚያምኗቸውን መተግበሪያዎች ብቻ ሁሉንም የመሣሪያ ምዝግብ ማስታወሻዎች እንዲደርሱ ይፍቀዱላቸው። \n\nይህ መተግበሪያ ሁሉንም የመሣሪያ ምዝግብ ማስታወሻዎች እንዲደርስ ካልፈቀዱለት አሁንም የራሱን ምዝግብ ማስታወሻዎች መድረስ ይችላል። የእርስዎ መሣሪያ አምራች አሁንም አንዳንድ ምዝግብ ማስታወሻዎችን ወይም መረጃዎችን በመሣሪያዎ ላይ ሊደርስ ይችላል።"</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"ዳግም አታሳይ"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> የ<xliff:g id="APP_2">%2$s</xliff:g> ቁራጮችን ማሳየት ይፈልጋል"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"አርትዕ"</string>
@@ -2292,7 +2291,6 @@
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"ንቁ መተግበሪያዎችን ይፈትሹ"</string>
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"የስልኩን ካሜራ ከእርስዎ <xliff:g id="DEVICE">%1$s</xliff:g> መድረስ አይቻልም"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"ጡባዊውን ካሜራ ከእርስዎ <xliff:g id="DEVICE">%1$s</xliff:g> መድረስ አይቻልም"</string>
- <!-- no translation found for vdm_secure_window (161700398158812314) -->
- <skip />
+ <string name="vdm_secure_window" msgid="161700398158812314">"ዥረት በመልቀቅ ላይ ሳለ ይህ ሊደረስበት አይችልም። በምትኩ በስልክዎ ላይ ይሞክሩ።"</string>
<string name="system_locale_title" msgid="711882686834677268">"የሥርዓት ነባሪ"</string>
</resources>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 76b07c0..90bc7f2 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -612,7 +612,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"تم إلغاء تشغيل بصمة الإصبع."</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"تم إلغاء تشغيل بصمة الإصبع بواسطة المستخدم."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"تم إجراء عدد كبير من المحاولات. أعد المحاولة لاحقًا."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"تم إجراء عدد كبير جدًا من المحاولات. لذا تم إيقاف جهاز استشعار بصمات الإصبع."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"تم إجراء عدد كبير جدًا من المحاولات. عليك استخدام قفل الشاشة بدلاً من ذلك."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"أعد المحاولة."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"ليست هناك بصمات إصبع مسجَّلة."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"لا يحتوي هذا الجهاز على مستشعِر بصمات إصبع."</string>
@@ -641,7 +641,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"يُرجى التواصل مع مقدِّم خدمات إصلاح."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"يتعذّر إنشاء نموذج الوجه. يُرجى إعادة المحاولة."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"ساطع للغاية. تجربة مستوى سطوع أقلّ."</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"جرِّب زيادة الإضاءة."</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"يُرجى إبعاد الهاتف عنك."</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"يُرجى تقريب الهاتف منك."</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"يُرجى رفع الهاتف للأعلى."</string>
@@ -1427,7 +1428,7 @@
<string name="ext_media_unmounting_notification_title" msgid="4147986383917892162">"جارٍ إخراج <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="ext_media_unmounting_notification_message" msgid="5717036261538754203">"عدم الإزالة"</string>
<string name="ext_media_init_action" msgid="2312974060585056709">"إعداد"</string>
- <string name="ext_media_unmount_action" msgid="966992232088442745">"إلغاء"</string>
+ <string name="ext_media_unmount_action" msgid="966992232088442745">"إخراج"</string>
<string name="ext_media_browse_action" msgid="344865351947079139">"استكشاف"</string>
<string name="ext_media_seamless_action" msgid="8837030226009268080">"تبديل جهاز إخراج الصوت"</string>
<string name="ext_media_missing_title" msgid="3209472091220515046">"<xliff:g id="NAME">%s</xliff:g> مفقود"</string>
@@ -1930,8 +1931,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"تفضيل المنطقة"</string>
<string name="search_language_hint" msgid="7004225294308793583">"اكتب اسم اللغة"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"اللغات المقترَحة"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"الاقتراحات"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"جميع اللغات"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"كل المناطق"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"البحث"</string>
@@ -2054,8 +2054,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"هل تريد السماح لتطبيق <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> بالوصول إلى جميع سجلّات الجهاز؟"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"السماح بالوصول إلى السجلّ لمرة واحدة"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"عدم السماح"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"ترصد سجلّات الجهاز ما يحدث على جهازك. يمكن أن تستخدم التطبيقات هذه السجلّات لتحديد المشاكل وحلها.\n\nقد تحتوي بعض السجلّات على معلومات حساسة، ولذلك يجب عدم السماح بالوصول إلى جميع سجلّات الجهاز إلا للتطبيقات التي تثق بها. \n\nإذا لم تسمح بوصول هذا التطبيق إلى جميع سجلّات الجهاز، يظل بإمكان التطبيق الوصول إلى سجلّاته. ويظل بإمكان الشركة المصنِّعة لجهازك الوصول إلى بعض السجلّات أو المعلومات المتوفّرة على جهازك."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"عدم الإظهار مرة أخرى"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"يريد تطبيق <xliff:g id="APP_0">%1$s</xliff:g> عرض شرائح تطبيق <xliff:g id="APP_2">%2$s</xliff:g>."</string>
<string name="screenshot_edit" msgid="7408934887203689207">"تعديل"</string>
@@ -2296,7 +2295,6 @@
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"التحقّق من التطبيقات النشطة"</string>
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"يتعذّر الوصول إلى كاميرا الهاتف من على جهاز <xliff:g id="DEVICE">%1$s</xliff:g>."</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"يتعذّر الوصول إلى كاميرا الجهاز اللوحي من على جهاز <xliff:g id="DEVICE">%1$s</xliff:g>."</string>
- <!-- no translation found for vdm_secure_window (161700398158812314) -->
- <skip />
+ <string name="vdm_secure_window" msgid="161700398158812314">"لا يمكن الوصول إلى هذا المحتوى أثناء البث. بدلاً من ذلك، جرِّب استخدام هاتفك."</string>
<string name="system_locale_title" msgid="711882686834677268">"الإعداد التلقائي للنظام"</string>
</resources>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index d70d03b..8340ba2 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -608,7 +608,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"ফিংগাৰপ্ৰিণ্ট কাৰ্য বাতিল কৰা হ’ল।"</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"ব্যৱহাৰকাৰীয়ে ফিংগাৰপ্ৰিণ্ট ক্ৰিয়া বাতিল কৰিছে।"</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"অত্যধিক ভুল প্ৰয়াস। কিছুসময়ৰ পাছত আকৌ চেষ্টা কৰক।"</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"অত্যধিক প্ৰয়াস। ফিংগাৰপ্ৰিণ্ট ছেন্সৰ অক্ষম কৰা হ’ল।"</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"অতি বেছিসংখ্যক প্ৰয়াস। ইয়াৰ সলনি স্ক্ৰীন লক ব্যৱহাৰ কৰক।"</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"আকৌ চেষ্টা কৰক।"</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"কোনো ফিংগাৰপ্ৰিণ্ট যোগ কৰা নহ\'ল।"</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"এই ডিভাইচটোত ফিংগাৰপ্ৰিণ্ট ছেন্সৰ নাই।"</string>
@@ -637,7 +637,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"মেৰামতি সেৱা প্ৰদানকাৰী কোনো প্ৰতিষ্ঠানলৈ যাওক।"</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"মুখাৱয়বৰ মডেল সৃষ্টি কৰিব নোৱাৰি। পুনৰ চেষ্টা কৰক।"</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"অতি উজ্জ্বল। ইয়াতকৈ কম পোহৰৰ উৎস ব্যৱহাৰ কৰক।"</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"উজ্জ্বল পোহৰ থকা ঠাইলৈ গৈ চাওক"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"ফ’নটো আৰু আঁতৰলৈ নিয়ক"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"ফ’নটো ওচৰলৈ আনক"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"ফ’নটো ওপৰলৈ নিয়ক"</string>
@@ -1926,8 +1927,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"অঞ্চলৰ অগ্ৰাধিকাৰ"</string>
<string name="search_language_hint" msgid="7004225294308793583">"ভাষাৰ নাম লিখক"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"প্ৰস্তাৱিত"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"পৰামৰ্শিত"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"সকলো ভাষা"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"আটাইবোৰ অঞ্চল"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"সন্ধান কৰক"</string>
@@ -2050,8 +2050,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g>ক আটাইবোৰ ডিভাইচৰ লগ এক্সেছ কৰাৰ অনুমতি প্ৰদান কৰিবনে?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"কেৱল এবাৰ এক্সেছ কৰাৰ অনুমতি দিয়ক"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"অনুমতি নিদিব"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"আপোনাৰ ডিভাইচত কি কি ঘটে সেয়া ডিভাইচ লগে ৰেকৰ্ড কৰে। এপ্সমূহে সমস্যা বিচাৰিবলৈ আৰু সমাধান কৰিবলৈ এই লগসমূহ ব্যৱহাৰ কৰিব পাৰে।\n\nকিছুমান লগত সংবেদনশীল তথ্য থাকিব পাৰে, গতিকে কেৱল আপুনি বিশ্বাস কৰা এপকহে আটাইবোৰ ডিভাইচ লগ এক্সেছ কৰাৰ অনুমতি দিয়ক। \n\nআপুনি যদি এই এপ্টোক আটাইবোৰ ডিভাইচ লগ এক্সেছ কৰাৰ অনুমতি নিদিয়ে, তথাপিও ই নিজৰ লগসমূহ এক্সেছ কৰিব পাৰিব। আপোনাৰ ডিভাইচৰ নিৰ্মাতাই তথাপিও হয়তো আপোনাৰ ডিভাইচটোত থকা কিছু লগ অথবা তথ্য এক্সেছ কৰিব পাৰিব।"</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"পুনৰ নেদেখুৱাব"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g>এ <xliff:g id="APP_2">%2$s</xliff:g>ৰ অংশ দেখুওৱাব খুজিছে"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"সম্পাদনা কৰক"</string>
@@ -2292,7 +2291,6 @@
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"সক্ৰিয় এপ্সমূহ পৰীক্ষা কৰক"</string>
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"আপোনাৰ <xliff:g id="DEVICE">%1$s</xliff:g>ৰ পৰা ফ’নটোৰ কেমেৰা এক্সেছ কৰিব নোৱাৰি"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"আপোনাৰ <xliff:g id="DEVICE">%1$s</xliff:g>ৰ পৰা টেবলেটটোৰ কেমেৰা এক্সেছ কৰিব নোৱাৰি"</string>
- <!-- no translation found for vdm_secure_window (161700398158812314) -->
- <skip />
+ <string name="vdm_secure_window" msgid="161700398158812314">"ষ্ট্ৰীম কৰি থকাৰ সময়ত এইটো এক্সেছ কৰিব নোৱাৰি। তাৰ পৰিৱৰ্তে আপোনাৰ ফ’নত চেষ্টা কৰি চাওক।"</string>
<string name="system_locale_title" msgid="711882686834677268">"ছিষ্টেম ডিফ’ল্ট"</string>
</resources>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index adcafd7..9c35b96 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -608,7 +608,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"Barmaq izi əməliyyatı ləğv edildi."</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Barmaq izi əməliyyatı istifadəçi tərəfindən ləğv edildi."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"Cəhdlər çox oldu. Sonraya saxlayın."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Həddindən çox cəhd. Barmaq izi sensoru deaktiv edilib."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Həddindən çox cəhd edilib. Əvəzində ekran kilidindən istifadə edin."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Yenidən cəhd edin."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Barmaq izi qeydə alınmayıb."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Bu cihazda barmaq izi sensoru yoxdur."</string>
@@ -637,7 +637,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Təmir provayderini ziyarət edin."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"Üz modelinizi yaratmaq olmur. Yenə cəhd edin."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Çox işıqlıdır. Daha az işıqlı şəkli sınayın."</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"Parlaq işıqdan istifadə edin"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"Telefonu uzaq tutun"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"Telefonu yaxına tutun"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"Telefonu yuxarı tutun"</string>
@@ -1926,8 +1927,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"Region seçimi"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Dil adını daxil edin"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"Təklif edilmiş"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Təklif edilib"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"Bütün dillər"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"Bütün bölgələr"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"Axtarın"</string>
@@ -2050,8 +2050,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> tətbiqinin bütün cihaz qeydlərinə girişinə icazə verilsin?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"Birdəfəlik girişə icazə verin"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"İcazə verməyin"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"Cihaz qeydləri cihazınızda baş verənləri qeyd edir. Tətbiqlər problemləri tapmaq və həll etmək üçün bu qeydlərdən istifadə edə bilər.\n\nBəzi qeydlərdə həssas məlumatlar ola bilər, ona görə də yalnız etibar etdiyiniz tətbiqlərin bütün cihaz qeydlərinə giriş etməsinə icazə verin. \n\nBu tətbiqin bütün cihaz qeydlərinə girişinə icazə verməsəniz, o, hələ də öz qeydlərinə giriş edə bilər. Cihaz istehsalçınız hələ də cihazınızda bəzi qeydlərə və ya məlumatlara giriş edə bilər."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Daha göstərməyin"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> <xliff:g id="APP_2">%2$s</xliff:g> tətbiqindən bölmələr göstərmək istəyir"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Redaktə edin"</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index d1ed1f7..8b0949d 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -609,7 +609,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"Radnja sa otiskom prsta je otkazana."</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Korisnik je otkazao radnju sa otiskom prsta."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"Previše pokušaja. Probajte ponovo kasnije."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Previše pokušaja. Senzor za otisak prsta je onemogućen."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Previše pokušaja. Koristite zaključavanje ekrana umesto toga."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Probajte ponovo."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nije registrovan nijedan otisak prsta."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Ovaj uređaj nema senzor za otisak prsta."</string>
@@ -638,7 +638,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Posetite dobavljača za popravke."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"Pravljenje modela lica nije uspelo. Probajte ponovo."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Previše je svetlo. Probajte sa slabijim osvetljenjem."</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"Probajte sa jačim osvetljenjem"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"Udaljite telefon"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"Približite telefon"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"Pomerite telefon nagore"</string>
@@ -1927,8 +1928,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"Podešavanje regiona"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Unesite naziv jezika"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"Predloženi"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Predloženo"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"Svi jezici"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"Svi regioni"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"Pretraži"</string>
@@ -2051,8 +2051,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Želite da dozvolite aplikaciji <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> da pristupa svim evidencijama uređaja?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"Dozvoli jednokratan pristup"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Ne dozvoli"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"Evidencije uređaja registruju šta se dešava na uređaju. Aplikacije mogu da koriste te evidencije da bi pronašle i rešile probleme.\n\nNeke evidencije mogu da sadrže osetljive informacije, pa pristup svim evidencijama uređaja treba da dozvoljavate samo aplikacijama u koje imate poverenja. \n\nAko ne dozvolite ovoj aplikaciji da pristupa svim evidencijama uređaja, ona i dalje može da pristupa sopstvenim evidencijama. Proizvođač uređaja će možda i dalje moći da pristupa nekim evidencijama ili informacijama na uređaju."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Ne prikazuj ponovo"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"Aplikacija <xliff:g id="APP_0">%1$s</xliff:g> želi da prikazuje isečke iz aplikacije <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Izmeni"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 41677fd..ef91aae 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -610,7 +610,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"Аперацыя з адбіткамі пальцаў скасавана."</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Аўтэнтыфікацыя па адбітках пальцаў скасавана карыстальнікам."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"Занадта шмат спроб. Паспрабуйце яшчэ раз пазней."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Занадта шмат спроб. Сканер адбіткаў пальцаў выключаны."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Занадта шмат спроб. Скарыстайце блакіроўку экрана."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Паўтарыце спробу."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Адбіткі пальцаў не зарэгістраваны."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"На гэтай прыладзе няма сканера адбіткаў пальцаў."</string>
@@ -639,7 +639,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Звярніцеся ў сэрвісны цэнтр."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"Не ўдалося стварыць мадэль твару. Паўтарыце."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Занадта светла. Прыглушыце асвятленне."</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"Павялічце асвятленне"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"Перамясціце тэлефон далей"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"Перамясціце тэлефон бліжэй"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"Перамясціце тэлефон вышэй"</string>
@@ -1928,8 +1929,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"Параметры рэгіёна"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Увядзіце назву мовы"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"Прапанаваныя"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Прапанавана"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"Усе мовы"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"Усе рэгіёны"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"Шукаць"</string>
@@ -2052,8 +2052,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Дазволіць праграме \"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g>\" мець доступ да ўсіх журналаў прылады?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"Дазволіць аднаразовы доступ"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Не дазваляць"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"Журналы прылад запісваюць усё, што адбываецца на вашай прыладзе. Праграмы выкарыстоўваюць гэтыя журналы для пошуку і выпраўлення памылак.\n\nУ некаторых журналах можа ўтрымлівацца канфідэнцыяльная інфармацыя, таму давайце доступ да ўсіх журналаў прылады толькі тым праграмам, якім вы давяраеце. \n\nКалі вы не дасце гэтай праграме доступу да ўсіх журналаў прылад, у яе ўсё роўна застанецца доступ да ўласных журналаў. Для вытворцы вашай прылады будуць даступнымі некаторыя журналы і інфармацыя на вашай прыладзе."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Больш не паказваць"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"Праграма <xliff:g id="APP_0">%1$s</xliff:g> запытвае дазвол на паказ зрэзаў праграмы <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Рэдагаваць"</string>
@@ -2294,7 +2293,6 @@
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Праверце актыўныя праграмы"</string>
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Не ўдалося атрымаць доступ да камеры тэлефона з прылады \"<xliff:g id="DEVICE">%1$s</xliff:g>\""</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Не ўдалося атрымаць доступ да камеры планшэта з прылады \"<xliff:g id="DEVICE">%1$s</xliff:g>\""</string>
- <!-- no translation found for vdm_secure_window (161700398158812314) -->
- <skip />
+ <string name="vdm_secure_window" msgid="161700398158812314">"Не ўдаецца атрымаць доступ у час перадачы плынню. Паспрабуйце скарыстаць тэлефон."</string>
<string name="system_locale_title" msgid="711882686834677268">"Стандартная сістэмная налада"</string>
</resources>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index d9f01e6..0cd0b1d 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -608,7 +608,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"Операцията за отпечатък е анулирана."</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Операцията за удостоверяване чрез отпечатък бе анулирана от потребителя."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"Твърде много опити. Пробвайте отново по-късно."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Твърде много опити. Сензорът за отпечатъци е деактивиран."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Твърде много опити. Вместо това използвайте опция за заключване на екрана."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Опитайте отново."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Няма регистрирани отпечатъци."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Това устройство няма сензор за отпечатъци."</string>
@@ -637,7 +637,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Посетете оторизиран сервиз."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"Моделът на лицето ви не бе създаден. Опитайте пак."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Твърде светло е. Опитайте при по-слабо осветление."</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"Опитайте при по-силно осветление"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"Отдалечете телефона"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"Доближете телефона"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"Преместете телефона по-високо"</string>
@@ -1926,8 +1927,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"Предпочитание за региона"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Въведете име на език"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"Предложени"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Предложени"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"Всички езици"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"Всички региони"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"Търсене"</string>
@@ -2050,8 +2050,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Да се разреши ли на <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> достъп до всички регистрационни файлове за устройството?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"Разрешаване на еднократен достъп"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Забраняване"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"В регистрационните файлове за устройството се записва какво се извършва на него. Приложенията могат да използват тези регистрационни файлове, за да откриват и отстраняват проблеми.\n\nНякои регистрационни файлове за устройството може да съдържат поверителна информация, затова разрешавайте достъп до всички тях само на приложения, на които имате доверие. \n\nАко не разрешите на това приложение достъп до всички регистрационни файлове за устройството, то пак може да осъществява достъп до собствените си регистрационни файлове. Производителят на устройството пак може да има достъп до някои регистрационни файлове или информация на устройството ви."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Да не се показва пак"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> иска да показва части от <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Редактиране"</string>
@@ -2292,7 +2291,6 @@
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Проверете активните приложения"</string>
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Няма достъп до камерата на телефона от вашия <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Няма достъп до камерата на таблета от вашия <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
- <!-- no translation found for vdm_secure_window (161700398158812314) -->
- <skip />
+ <string name="vdm_secure_window" msgid="161700398158812314">"До това съдържание не може да се осъществи достъп при поточно предаване. Вместо това опитайте от телефона си."</string>
<string name="system_locale_title" msgid="711882686834677268">"Стандартно за системата"</string>
</resources>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index 9a87b36..dd13a55 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -608,7 +608,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"আঙ্গুলের ছাপ অপারেশন বাতিল করা হয়েছে৷"</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"ব্যবহারকারী আঙ্গুলের ছাপের অপারেশনটি বাতিল করেছেন।"</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"অনেকবার প্রচেষ্টা করা হয়েছে৷ পরে আবার চেষ্টা করুন৷"</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"বহুবার চেষ্টা করেছেন। আঙ্গুলের ছাপ নেওয়ার সেন্সর অক্ষম করা হয়েছে।"</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"অনেকবার চেষ্টা করেছেন। পরিবর্তে স্ক্রিন লক ব্যবহার করুন।"</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"আবার চেষ্টা করুন৷"</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"কোনও আঙ্গুলের ছাপ নথিভুক্ত করা হয়নি।"</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"এই ডিভাইসে আঙ্গুলের ছাপ নেওয়ার সেন্সর নেই।"</string>
@@ -637,7 +637,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"একজন মেরামতি মিস্ত্রির কাছে যান।"</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"ফেস মডেল তৈরি করা যাচ্ছে না। আবার চেষ্টা করুন।"</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"খুব উজ্জ্বল। আলো কমিয়ে চেষ্টা করে দেখুন।"</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"আরও উজ্জ্বল আলো ব্যবহার করে দেখুন"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"ফোন আরও দূরে নিয়ে যান"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"ফোন আরও কাছে নিয়ে আসুন"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"ফোন আরও উঁচুতে তুলুন"</string>
@@ -1926,8 +1927,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"পছন্দের অঞ্চল"</string>
<string name="search_language_hint" msgid="7004225294308793583">"ভাষার নাম লিখুন"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"প্রস্তাবিত"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"সাজেস্ট করা অঞ্চল"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"সকল ভাষা"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"সমস্ত অঞ্চল"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"সার্চ"</string>
@@ -2050,8 +2050,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> অ্যাপকে ডিভাইসের সব লগ অ্যাক্সেসের অনুমতি দিতে চান?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"এককালীন অ্যাক্সেসের অনুমতি দিন"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"অনুমতি দেবেন না"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"ডিভাইস লগে আপনার ডিভাইসে করা অ্যাক্টিভিটি রেকর্ড করা হয়। অ্যাপ সমস্যা খুঁজে তা সমাধান করতে এইসব লগ ব্যবহার করতে পারে।\n\nকিছু লগে সংবেদনশীল তথ্য থাকতে পারে, তাই বিশ্বাস করেন শুধুমাত্র এমন অ্যাপকেই সব ডিভাইসের লগ অ্যাক্সেসের অনুমতি দিন। \n\nআপনি এই অ্যাপকে ডিভাইসের সব লগ অ্যাক্সেস করার অনুমতি না দিলেও, এটি নিজের লগ অ্যাক্সেস করতে পারবে। ডিভাইস প্রস্তুতকারকও আপনার ডিভাইসের কিছু লগ বা তথ্য হয়ত অ্যাক্সেস করতে পারবে।"</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"আর দেখতে চাই না"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> অ্যাপটি <xliff:g id="APP_2">%2$s</xliff:g> এর অংশ দেখাতে চায়"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"এডিট করুন"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index 778bbeb..7a1989d 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -609,7 +609,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"Radnja s otiskom prsta je otkazana."</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Korisnik je otkazao radnju s otiskom prsta."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"Previše pokušaja. Pokušajte ponovo kasnije."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Previše pokušaja. Senzor za otisak prsta je onemogućen."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Previše pokušaja. Umjesto toga koristite zaključavanje ekrana."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Pokušajte ponovo."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nije prijavljen nijedan otisak prsta."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Ovaj uređaj nema senzor za otisak prsta."</string>
@@ -638,7 +638,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Posjetite pružaoca usluga za popravke."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"Nije moguće kreirati model lica. Pokušajte ponovo."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Previše svijetlo. Probajte s blažim osvjetljenjem."</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"Pokušajte s jačim osvjetljenjem"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"Odmaknite telefon"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"Primaknite telefon"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"Pomjerite telefon naviše"</string>
@@ -1428,7 +1429,7 @@
<string name="ext_media_browse_action" msgid="344865351947079139">"Istraži"</string>
<string name="ext_media_seamless_action" msgid="8837030226009268080">"Prebacite izlaz"</string>
<string name="ext_media_missing_title" msgid="3209472091220515046">"<xliff:g id="NAME">%s</xliff:g> nedostaje"</string>
- <string name="ext_media_missing_message" msgid="4408988706227922909">"Ponovo ubacite uređaj"</string>
+ <string name="ext_media_missing_message" msgid="4408988706227922909">"Ponovo umetnite uređaj"</string>
<string name="ext_media_move_specific_title" msgid="8492118544775964250">"Premješta se <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="ext_media_move_title" msgid="2682741525619033637">"Premještanje podataka"</string>
<string name="ext_media_move_success_title" msgid="4901763082647316767">"Prijenos sadržaja je završen"</string>
@@ -1927,8 +1928,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"Izbor regije"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Upišite ime jezika"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"Predloženo"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Predloženo"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"Svi jezici"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"Sve regije"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"Pretraga"</string>
@@ -2051,8 +2051,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Dozvoliti aplikaciji <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> da pristupa svim zapisnicima uređaja?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"Dozvoli jednokratan pristup"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Nemoj dozvoliti"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"Zapisnici uređaja bilježe šta se dešava na uređaju. Aplikacije mogu koristiti te zapisnike da pronađu i isprave probleme.\n\nNeki zapisnici mogu sadržavati osjetljive podatke, zato pristup svim zapisnicima uređaja dozvolite samo aplikacijama kojima vjerujete. \n\nAko ne dozvolite ovoj aplikaciji da pristupa svim zapisnicima uređaja, ona i dalje može pristupati svojim zapisnicima. Proizvođač uređaja će možda i dalje biti u stanju pristupiti nekim zapisnicima ili podacima na uređaju."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Ne prikazuj ponovo"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"Aplikacija <xliff:g id="APP_0">%1$s</xliff:g> želi prikazati isječke aplikacije <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Uredi"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 8dd5fc5..972e85b 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -608,7 +608,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"S\'ha cancel·lat l\'operació d\'empremta digital."</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"L\'usuari ha cancel·lat l\'operació d\'empremta digital."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"S\'han produït massa intents. Torna-ho a provar més tard."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"S\'han fet massa intents. S\'ha desactivat el sensor d\'empremtes digitals."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Massa intents. Utilitza el bloqueig de pantalla."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Torna-ho a provar."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"No s\'ha registrat cap empremta digital."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Aquest dispositiu no té sensor d\'empremtes digitals."</string>
@@ -637,7 +637,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Visita un proveïdor de reparacions."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"No es pot crear el model facial. Torna-ho a provar."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Massa brillant Prova una il·luminació més suau."</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"Prova amb més il·luminació"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"Allunya\'t del telèfon"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"Apropa el telèfon"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"Mou el telèfon més amunt"</string>
@@ -1926,8 +1927,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"Preferència de regió"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Escriu el nom de l\'idioma"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"Suggerits"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Recomanades"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"Tots els idiomes"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"Totes les regions"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"Cerca"</string>
@@ -2050,8 +2050,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Vols permetre que <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> accedeixi a tots els registres del dispositiu?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"Permet l\'accés únic"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"No permetis"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"Els registres del dispositiu inclouen informació sobre tot allò que passa al teu dispositiu. Les aplicacions poden utilitzar aquests registres per detectar i corregir problemes.\n\nÉs possible que alguns registres continguin informació sensible; per això només has de donar-hi accés a les aplicacions de confiança. \n\nEncara que no permetis que aquesta aplicació pugui accedir a tots els registres del dispositiu, podrà accedir als seus propis registres. És possible que el fabricant del dispositiu també tingui accés a alguns registres o a informació del teu dispositiu."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"No tornis a mostrar"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> vol mostrar porcions de l\'aplicació <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Edita"</string>
@@ -2292,7 +2291,6 @@
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Consulta les aplicacions actives"</string>
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"No es pot accedir a la càmera del telèfon des del teu <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"No es pot accedir a la càmera de la tauleta des del teu <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
- <!-- no translation found for vdm_secure_window (161700398158812314) -->
- <skip />
+ <string name="vdm_secure_window" msgid="161700398158812314">"No s\'hi pot accedir mentre s\'està reproduint en continu. Prova-ho al telèfon."</string>
<string name="system_locale_title" msgid="711882686834677268">"Valor predeterminat del sistema"</string>
</resources>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 098e83b..226f9fd 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -610,7 +610,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"Operace otisku prstu byla zrušena."</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Uživatel operaci s otiskem prstu zrušil."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"Příliš mnoho pokusů. Zkuste to později."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Příliš mnoho pokusů. Snímač otisků prstů byl deaktivován."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Příliš mnoho pokusů. Použijte zámek obrazovky."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Zkuste to znovu."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nejsou zaregistrovány žádné otisky prstů."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Toto zařízení nemá snímač otisků prstů."</string>
@@ -639,7 +639,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Navštivte servis"</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"Model se nepodařilo vytvořit. Zkuste to znovu."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Je příliš světlo. Zmírněte osvětlení."</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"Přejděte na světlo"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"Umístěte telefon dál"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"Umístěte telefon blíž"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"Umístěte telefon výš"</string>
@@ -1429,7 +1430,7 @@
<string name="ext_media_browse_action" msgid="344865351947079139">"Otevřít"</string>
<string name="ext_media_seamless_action" msgid="8837030226009268080">"Přepnout výstup"</string>
<string name="ext_media_missing_title" msgid="3209472091220515046">"<xliff:g id="NAME">%s</xliff:g> chybí"</string>
- <string name="ext_media_missing_message" msgid="4408988706227922909">"Znovu vložte zařízení"</string>
+ <string name="ext_media_missing_message" msgid="4408988706227922909">"Vložte zařízení znovu"</string>
<string name="ext_media_move_specific_title" msgid="8492118544775964250">"Přesouvání aplikace <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="ext_media_move_title" msgid="2682741525619033637">"Probíhá přesun dat"</string>
<string name="ext_media_move_success_title" msgid="4901763082647316767">"Přenos obsahu je dokončen"</string>
@@ -1568,7 +1569,7 @@
<string name="action_bar_home_description_format" msgid="5087107531331621803">"%1$s – %2$s"</string>
<string name="action_bar_home_subtitle_description_format" msgid="4346835454749569826">"%1$s, %2$s – %3$s"</string>
<string name="storage_internal" msgid="8490227947584914460">"Interní sdílené úložiště"</string>
- <string name="storage_sd_card" msgid="3404740277075331881">"Karta SD"</string>
+ <string name="storage_sd_card" msgid="3404740277075331881">"SD karta"</string>
<string name="storage_sd_card_label" msgid="7526153141147470509">"SD karta <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
<string name="storage_usb_drive" msgid="448030813201444573">"Jednotka USB"</string>
<string name="storage_usb_drive_label" msgid="6631740655876540521">"Jednotka USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
@@ -1928,8 +1929,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"Preferovaná oblast"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Zadejte název jazyka"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"Navrhované"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Navrženo"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"Všechny jazyky"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"Všechny oblasti"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"Vyhledávání"</string>
@@ -2052,8 +2052,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Povolit aplikaci <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> přístup ke všem protokolům zařízení?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"Povolit jednorázový přístup"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Nepovolovat"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"Do protokolů zařízení se zaznamenává, co se na zařízení děje. Aplikace tyto protokoly mohou používat k vyhledání a odstranění problémů.\n\nNěkteré protokoly mohou zahrnovat citlivé údaje. Přístup k protokolům zařízení proto povolte pouze aplikacím, kterým důvěřujete. \n\nPokud této aplikaci nepovolíte přístup ke všem protokolům zařízení, bude mít stále přístup ke svým vlastním protokolům. Výrobce zařízení může mít stále přístup k některým protokolům nebo informacím na vašem zařízení."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Příště nezobrazovat"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"Aplikace <xliff:g id="APP_0">%1$s</xliff:g> chce zobrazovat ukázky z aplikace <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Upravit"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 60d3556..2b9f98d 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -608,7 +608,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"Fingeraftrykshandlingen blev annulleret."</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Fingeraftrykshandlingen blev annulleret af brugeren."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"Du har prøvet for mange gange. Prøv igen senere."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Du har brugt for mange forsøg. Fingeraftrykslæseren er deaktiveret."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Du har brugt for mange forsøg. Brug skærmlåsen i stedet."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Prøv igen."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Der er ikke registreret nogen fingeraftryk."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Denne enhed har ingen fingeraftrykslæser."</string>
@@ -637,7 +637,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Få den repareret."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"Din ansigtsmodel kan ikke oprettes. Prøv igen."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Der er for lyst. Prøv en mere dæmpet belysning."</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"Prøv med mere belysning"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"Flyt telefonen længere væk"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"Flyt telefonen tættere på"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"Løft telefonen højere op"</string>
@@ -1567,7 +1568,7 @@
<string name="action_bar_home_subtitle_description_format" msgid="4346835454749569826">"%1$s, %2$s, %3$s"</string>
<string name="storage_internal" msgid="8490227947584914460">"Intern delt lagerplads"</string>
<string name="storage_sd_card" msgid="3404740277075331881">"SD-kort"</string>
- <string name="storage_sd_card_label" msgid="7526153141147470509">"SD-kort fra <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
+ <string name="storage_sd_card_label" msgid="7526153141147470509">"SD-kort (<xliff:g id="MANUFACTURER">%s</xliff:g>)"</string>
<string name="storage_usb_drive" msgid="448030813201444573">"USB-drev"</string>
<string name="storage_usb_drive_label" msgid="6631740655876540521">"USB-drev fra <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
<string name="storage_usb" msgid="2391213347883616886">"USB-lager"</string>
@@ -1926,8 +1927,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"Områdeindstilling"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Angiv sprog"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"Foreslået"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Forslag"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"Alle sprog"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"Alle områder"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"Søg"</string>
@@ -2050,8 +2050,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Vil du give <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> adgang til alle enhedslogs?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"Tillad engangsadgang"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Tillad ikke"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"Enhedslogs registrerer, hvad der sker på din enhed. Apps kan bruge disse logs til at finde og løse problemer.\n\nNogle logs kan indeholde følsomme oplysninger, så giv kun apps, du har tillid til, adgang til alle enhedslogs. \n\nSelvom du ikke giver denne app adgang til alle enhedslogs, kan den stadig tilgå sine egne logs. Producenten af din enhed kan muligvis fortsat tilgå visse logs eller oplysninger på din enhed."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Vis ikke igen"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> anmoder om tilladelse til at vise eksempler fra <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Rediger"</string>
@@ -2292,7 +2291,6 @@
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Tjek aktive apps"</string>
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Kameraet på din telefon kan ikke tilgås via din <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Kameraet på din tablet kan ikke tilgås via din <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
- <!-- no translation found for vdm_secure_window (161700398158812314) -->
- <skip />
+ <string name="vdm_secure_window" msgid="161700398158812314">"Der er ikke adgang til dette indhold under streaming. Prøv på din telefon i stedet."</string>
<string name="system_locale_title" msgid="711882686834677268">"Systemstandard"</string>
</resources>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 777e9af2..4944dd9 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -608,7 +608,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"Fingerabdruckvorgang abgebrochen"</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Vorgang der Fingerabdruckauthentifizierung vom Nutzer abgebrochen."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"Zu viele Versuche, bitte später noch einmal versuchen"</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Zu viele Versuche. Der Fingerabdrucksensor wurde deaktiviert."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Zu viele Versuche. Verwende stattdessen die Displaysperre."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Bitte versuche es noch einmal."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Keine Fingerabdrücke erfasst."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Dieses Gerät hat keinen Fingerabdrucksensor."</string>
@@ -637,7 +637,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Suche einen Reparaturdienstleister auf."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"Kein Gesichtsmodell möglich. Versuche es erneut."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Zu hell. Schwächere Beleuchtung ausprobieren."</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"Probiere es mit einer helleren Beleuchtung"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"Bewege das Smartphone weiter weg"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"Bewege das Smartphone näher heran"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"Bewege das Smartphone nach oben"</string>
@@ -1250,10 +1251,8 @@
<string name="android_upgrading_starting_apps" msgid="6206161195076057075">"Apps werden gestartet..."</string>
<string name="android_upgrading_complete" msgid="409800058018374746">"Start wird abgeschlossen..."</string>
<string name="fp_power_button_enrollment_message" msgid="5648173517663246140">"Du hast die Ein-/Aus-Taste gedrückt — damit wird der Bildschirm ausgeschaltet.\n\nTippe die Taste leicht an, um deinen Fingerabdruck einzurichten."</string>
- <!-- no translation found for fp_power_button_enrollment_title (8997641910928785172) -->
- <skip />
- <!-- no translation found for fp_power_button_enrollment_button_text (8351290204990805109) -->
- <skip />
+ <string name="fp_power_button_enrollment_title" msgid="8997641910928785172">"Tippen, um Display auszuschalten"</string>
+ <string name="fp_power_button_enrollment_button_text" msgid="8351290204990805109">"Display ausschalten"</string>
<string name="fp_power_button_bp_title" msgid="5585506104526820067">"Mit der Fingerabdruckprüfung fortfahren?"</string>
<string name="fp_power_button_bp_message" msgid="2983163038168903393">"Du hast die Ein-/Aus-Taste gedrückt — damit wird der Bildschirm ausgeschaltet.\n\nTippe die Taste leicht an, um mit deinem Fingerabdruck deine Identität zu bestätigen."</string>
<string name="fp_power_button_bp_positive_button" msgid="728945472408552251">"Ausschalten"</string>
@@ -1928,8 +1927,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"Region auswählen"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Sprache eingeben"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"Vorschläge"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Vorschläge"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"Alle Sprachen"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"Alle Regionen"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"Suche"</string>
@@ -2052,8 +2050,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> den Zugriff auf alle Geräteprotokolle erlauben?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"Einmaligen Zugriff zulassen"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Nicht zulassen"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"In Geräteprotokollen wird aufgezeichnet, welche Aktionen auf deinem Gerät ausgeführt werden. Apps können diese Protokolle verwenden, um Probleme zu finden und zu beheben.\n\nEinige Protokolle enthalten unter Umständen vertrauliche Informationen, daher solltest du nur vertrauenswürdigen Apps den Zugriff auf alle Geräteprotokolle erlauben. \n\nWenn du dieser App keinen Zugriff auf alle Geräteprotokolle gewährst, kann sie trotzdem auf ihre eigenen Protokolle zugreifen. Dein Gerätehersteller hat möglicherweise auch Zugriff auf einige Protokolle oder Informationen auf deinem Gerät."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Nicht mehr anzeigen"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> möchte Teile von <xliff:g id="APP_2">%2$s</xliff:g> anzeigen"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Bearbeiten"</string>
@@ -2294,7 +2291,6 @@
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Aktive Apps prüfen"</string>
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Zugriff auf die Kamera des Smartphones über dein Gerät (<xliff:g id="DEVICE">%1$s</xliff:g>) nicht möglich"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Zugriff auf die Kamera des Tablets über dein Gerät (<xliff:g id="DEVICE">%1$s</xliff:g>) nicht möglich"</string>
- <!-- no translation found for vdm_secure_window (161700398158812314) -->
- <skip />
+ <string name="vdm_secure_window" msgid="161700398158812314">"Während des Streamings ist kein Zugriff möglich. Versuch es stattdessen auf deinem Smartphone."</string>
<string name="system_locale_title" msgid="711882686834677268">"Standardeinstellung des Systems"</string>
</resources>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 9f19ef9..68f5e24 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -608,7 +608,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"Η λειτουργία δακτυλικού αποτυπώματος ακυρώθηκε."</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Η λειτουργία δακτυλικού αποτυπώματος ακυρώθηκε από τον χρήστη."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"Πάρα πολλές προσπάθειες. Δοκιμάστε ξανά αργότερα."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Πάρα πολλές προσπάθειες. Ο αισθητήρας δακτυλικών αποτυπωμάτων απενεργοποιήθηκε."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Υπερβολικά πολλές προσπάθειες. Χρησιμοποιήστε εναλλακτικά το κλείδωμα οθόνης."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Δοκιμάστε ξανά."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Δεν έχουν καταχωριστεί δακτυλικά αποτυπώματα."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Αυτή η συσκευή δεν διαθέτει αισθητήρα δακτυλικού αποτυπώματος."</string>
@@ -637,7 +637,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Επισκεφτείτε έναν πάροχο υπηρεσιών επισκευής."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"Αδύν. η δημιουρ. του μοντ. προσώπ. Δοκιμάστε ξανά."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Υπερβολικά έντονος φωτισμός. Δοκιμάστε πιο ήπιο."</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"Δοκιμάστε με περισσότερο φως"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"Απομακρύνετε περισσότερο το τηλέφωνο"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"Φέρτε πιο κοντά το τηλέφωνό σας"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"Μετακινήστε το τηλέφωνο πιο ψηλά"</string>
@@ -1926,8 +1927,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"Προτίμηση περιοχής"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Εισαγ. όνομα γλώσσας"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"Προτεινόμενες"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Προτεινόμενα"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"Όλες οι γλώσσες"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"Όλες οι περιοχές"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"Αναζήτηση"</string>
@@ -2050,8 +2050,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Να επιτρέπεται στο <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> η πρόσβαση σε όλα τα αρχεία καταγραφής συσκευής;"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"Να επιτρέπεται η πρόσβαση για μία φορά"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Να μην επιτραπεί"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"Τα αρχεία καταγραφής συσκευής καταγράφουν ό,τι συμβαίνει στη συσκευή σας. Οι εφαρμογές μπορούν να χρησιμοποιούν αυτά τα αρχεία καταγραφής για να εντοπίζουν και να διορθώνουν ζητήματα.\n\nΟρισμένα αρχεία καταγραφής ενδέχεται να περιέχουν ευαίσθητες πληροφορίες. Ως εκ τούτου, επιτρέψτε την πρόσβαση σε όλα τα αρχεία καταγραφής συσκευής μόνο στις εφαρμογές που εμπιστεύεστε. \n\nΕάν δεν επιτρέψετε σε αυτήν την εφαρμογή την πρόσβαση σε όλα τα αρχεία καταγραφής συσκευής, η εφαρμογή εξακολουθεί να έχει πρόσβαση στα δικά της αρχεία καταγραφής. Ο κατασκευαστής της συσκευής σας ενδέχεται να εξακολουθεί να έχει πρόσβαση σε ορισμένα αρχεία καταγραφής ή ορισμένες πληροφορίες στη συσκευή σας."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Να μην εμφανισ. ξανά"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"Η εφαρμογή <xliff:g id="APP_0">%1$s</xliff:g> θέλει να εμφανίζει τμήματα της εφαρμογής <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Επεξεργασία"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 8f7e2b5..cb6428a 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -608,7 +608,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"Fingerprint operation cancelled."</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Fingerprint operation cancelled by user."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"Too many attempts. Try again later."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Too many attempts. Fingerprint sensor disabled."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Too many attempts. Use screen lock instead."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Try again."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"No fingerprints enrolled."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"This device does not have a fingerprint sensor."</string>
@@ -637,7 +637,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Visit a repair provider."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"Can’t create your face model. Try again."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Too bright. Try gentler lighting."</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"Try brighter lighting"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"Move phone further away"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"Move phone closer"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"Move phone higher"</string>
@@ -1926,8 +1927,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"Region preference"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Type language name"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"Suggested"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Suggested"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"All languages"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"All regions"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"Search"</string>
@@ -2050,8 +2050,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Allow <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> to access all device logs?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"Allow one-time access"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Don’t allow"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"Device logs record what happens on your device. Apps can use these logs to find and fix issues.\n\nSome logs may contain sensitive info, so only allow apps that you trust to access all device logs. \n\nIf you don’t allow this app to access all device logs, it can still access its own logs. Your device manufacturer may still be able to access some logs or info on your device."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Don’t show again"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> wants to show <xliff:g id="APP_2">%2$s</xliff:g> slices"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Edit"</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index dd2545b..357f2be 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -608,7 +608,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"Fingerprint operation cancelled."</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Fingerprint operation cancelled by user."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"Too many attempts. Try again later."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Too many attempts. Fingerprint sensor disabled."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Too many attempts. Use screen lock instead."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Try again."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"No fingerprints enrolled."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"This device does not have a fingerprint sensor."</string>
@@ -637,7 +637,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Visit a repair provider."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"Can’t create your face model. Try again."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Too bright. Try gentler lighting."</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"Try brighter lighting"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"Move phone further away"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"Move phone closer"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"Move phone higher"</string>
@@ -1926,8 +1927,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"Region preference"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Type language name"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"Suggested"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Suggested"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"All languages"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"All regions"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"Search"</string>
@@ -2050,8 +2050,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Allow <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> to access all device logs?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"Allow one-time access"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Don’t allow"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"Device logs record what happens on your device. Apps can use these logs to find and fix issues.\n\nSome logs may contain sensitive info, so only allow apps that you trust to access all device logs. \n\nIf you don’t allow this app to access all device logs, it can still access its own logs. Your device manufacturer may still be able to access some logs or info on your device."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Don’t show again"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> wants to show <xliff:g id="APP_2">%2$s</xliff:g> slices"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Edit"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 9e25626..6b0f970 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -608,7 +608,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"Fingerprint operation cancelled."</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Fingerprint operation cancelled by user."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"Too many attempts. Try again later."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Too many attempts. Fingerprint sensor disabled."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Too many attempts. Use screen lock instead."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Try again."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"No fingerprints enrolled."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"This device does not have a fingerprint sensor."</string>
@@ -637,7 +637,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Visit a repair provider."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"Can’t create your face model. Try again."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Too bright. Try gentler lighting."</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"Try brighter lighting"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"Move phone further away"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"Move phone closer"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"Move phone higher"</string>
@@ -1926,8 +1927,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"Region preference"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Type language name"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"Suggested"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Suggested"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"All languages"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"All regions"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"Search"</string>
@@ -2050,8 +2050,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Allow <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> to access all device logs?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"Allow one-time access"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Don’t allow"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"Device logs record what happens on your device. Apps can use these logs to find and fix issues.\n\nSome logs may contain sensitive info, so only allow apps that you trust to access all device logs. \n\nIf you don’t allow this app to access all device logs, it can still access its own logs. Your device manufacturer may still be able to access some logs or info on your device."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Don’t show again"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> wants to show <xliff:g id="APP_2">%2$s</xliff:g> slices"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Edit"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index c3eff31..94ecf29 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -608,7 +608,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"Fingerprint operation cancelled."</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Fingerprint operation cancelled by user."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"Too many attempts. Try again later."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Too many attempts. Fingerprint sensor disabled."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Too many attempts. Use screen lock instead."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Try again."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"No fingerprints enrolled."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"This device does not have a fingerprint sensor."</string>
@@ -637,7 +637,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Visit a repair provider."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"Can’t create your face model. Try again."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Too bright. Try gentler lighting."</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"Try brighter lighting"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"Move phone further away"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"Move phone closer"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"Move phone higher"</string>
@@ -1926,8 +1927,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"Region preference"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Type language name"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"Suggested"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Suggested"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"All languages"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"All regions"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"Search"</string>
@@ -2050,8 +2050,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Allow <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> to access all device logs?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"Allow one-time access"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Don’t allow"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"Device logs record what happens on your device. Apps can use these logs to find and fix issues.\n\nSome logs may contain sensitive info, so only allow apps that you trust to access all device logs. \n\nIf you don’t allow this app to access all device logs, it can still access its own logs. Your device manufacturer may still be able to access some logs or info on your device."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Don’t show again"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> wants to show <xliff:g id="APP_2">%2$s</xliff:g> slices"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Edit"</string>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index 9e52152..344f3c1 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -608,7 +608,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"Fingerprint operation canceled."</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Fingerprint operation canceled by user."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"Too many attempts. Try again later."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Too many attempts. Fingerprint sensor disabled."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Too many attempts. Use screen lock instead."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Try again."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"No fingerprints enrolled."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"This device does not have a fingerprint sensor."</string>
@@ -637,7 +637,7 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Visit a repair provider."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"Can’t create your face model. Try again."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Too bright. Try gentler lighting."</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"Try brighter lighting"</string>
+ <string name="face_acquired_too_dark" msgid="8539853432479385326">"Not enough light"</string>
<string name="face_acquired_too_close" msgid="4453646176196302462">"Move phone farther away"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"Move phone closer"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"Move phone higher"</string>
@@ -2049,8 +2049,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Allow <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> to access all device logs?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"Allow one-time access"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Don’t allow"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"Device logs record what happens on your device. Apps can use these logs to find and fix issues.\n\nSome logs may contain sensitive info, so only allow apps you trust to access all device logs. \n\nIf you don’t allow this app to access all device logs, it can still access its own logs. Your device manufacturer may still be able to access some logs or info on your device."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Don’t show again"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> wants to show <xliff:g id="APP_2">%2$s</xliff:g> slices"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Edit"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 8ca8ad0..4f41820 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -51,6 +51,7 @@
<string name="needPuk2" msgid="7032612093451537186">"Escribir PUK2 para desbloquear la tarjeta SIM."</string>
<string name="enablePin" msgid="2543771964137091212">"Error; habilita el bloqueo de SIM/RUIM."</string>
<plurals name="pinpuk_attempts" formatted="false" msgid="1619867269012213584">
+ <item quantity="many">You have <xliff:g id="NUMBER_1">%d</xliff:g> remaining attempts before SIM is locked.</item>
<item quantity="other">Tienes <xliff:g id="NUMBER_1">%d</xliff:g> intentos más antes de que se bloquee la tarjeta SIM.</item>
<item quantity="one">Tienes <xliff:g id="NUMBER_0">%d</xliff:g> un intento más antes de que se bloquee la tarjeta SIM.</item>
</plurals>
@@ -180,7 +181,7 @@
<string name="low_memory" product="watch" msgid="3479447988234030194">"El almacenamiento del reloj está completo. Elimina algunos archivos para liberar espacio."</string>
<string name="low_memory" product="tv" msgid="6663680413790323318">"El almacenamiento del dispositivo Android TV está lleno. Borra algunos archivos para liberar espacio."</string>
<string name="low_memory" product="default" msgid="2539532364144025569">"Se ha agotado el espacio de almacenamiento del dispositivo. Elimina algunos archivos para liberar espacio."</string>
- <string name="ssl_ca_cert_warning" msgid="7233573909730048571">"{count,plural, =1{Se instaló la autoridad certificadora}other{Se instalaron las autoridades certificadoras}}"</string>
+ <string name="ssl_ca_cert_warning" msgid="7233573909730048571">"{count,plural, =1{Se instaló la autoridad certificadora}many{Se instalaron las autoridades certificadoras}other{Se instalaron las autoridades certificadoras}}"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4961102218216815242">"Por un tercero desconocido"</string>
<string name="ssl_ca_cert_noti_by_administrator" msgid="4564941950768783879">"Por parte de tu administrador del perfil de trabajo"</string>
<string name="ssl_ca_cert_noti_managed" msgid="217337232273211674">"Por <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
@@ -254,7 +255,7 @@
<string name="bugreport_option_interactive_summary" msgid="8493795476325339542">"Usa esta opción en la mayoría de los casos. Te permite realizar un seguimiento del progreso del informe, ingresar más detalles acerca del problema y tomar capturas de pantalla. Es posible que se omitan secciones menos usadas cuyos informes demoran más en completarse."</string>
<string name="bugreport_option_full_title" msgid="7681035745950045690">"Informe completo"</string>
<string name="bugreport_option_full_summary" msgid="1975130009258435885">"Usa esta opción para reducir al mínimo la interferencia del sistema cuando tu dispositivo no responde o funciona muy lento, o cuando necesitas todas las secciones del informe. No permite ingresar más detalles ni tomar capturas de pantalla adicionales."</string>
- <string name="bugreport_countdown" msgid="6418620521782120755">"{count,plural, =1{Se tomará una captura de pantalla para el informe de errores en # segundo.}other{Se tomará una captura de pantalla para el informe de errores en # segundos.}}"</string>
+ <string name="bugreport_countdown" msgid="6418620521782120755">"{count,plural, =1{Se tomará una captura de pantalla para el informe de errores en # segundo.}many{Se tomará una captura de pantalla para el informe de errores en # segundos.}other{Se tomará una captura de pantalla para el informe de errores en # segundos.}}"</string>
<string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Se tomó la captura de pantalla con el informe de errores"</string>
<string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"No se pudo tomar la captura de pantalla con el informe de errores"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Modo silencioso"</string>
@@ -608,7 +609,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"Se canceló la operación de huella dactilar."</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"El usuario canceló la operación de huella dactilar."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"Demasiados intentos. Vuelve a intentarlo más tarde."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Realizaste demasiados intentos. Se inhabilitó el sensor de huellas dactilares."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Demasiados intentos. Utiliza el bloqueo de pantalla en su lugar."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Vuelve a intentarlo."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"No se registraron huellas digitales."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Este dispositivo no tiene sensor de huellas dactilares."</string>
@@ -637,7 +638,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Consulta a un proveedor de reparaciones."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"No se puede crear modelo de rostro. Reinténtalo."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Demasiado brillante. Prueba con menos iluminación."</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"Prueba con más iluminación"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"Aleja el teléfono un poco más"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"Acerca el teléfono"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"Mueve el teléfono hacia arriba"</string>
@@ -1087,7 +1089,7 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="4312979647356179250">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> desea activar la exploración táctil. Cuando esta función esté activada, podrás escuchar o ver descripciones del contenido seleccionado o usar gestos para interactuar con el dispositivo."</string>
<string name="oneMonthDurationPast" msgid="4538030857114635777">"Hace 1 mes."</string>
<string name="beforeOneMonthDurationPast" msgid="8315149541372065392">"Anterior a 1 mes atrás"</string>
- <string name="last_num_days" msgid="2393660431490280537">"{count,plural, =1{Último # día}other{Últimos # días}}"</string>
+ <string name="last_num_days" msgid="2393660431490280537">"{count,plural, =1{Último # día}many{Últimos # días}other{Últimos # días}}"</string>
<string name="last_month" msgid="1528906781083518683">"Último mes"</string>
<string name="older" msgid="1645159827884647400">"Antiguos"</string>
<string name="preposition_for_date" msgid="2780767868832729599">"activado <xliff:g id="DATE">%s</xliff:g>"</string>
@@ -1114,14 +1116,14 @@
<string name="duration_hours_shortest_future" msgid="2979276794547981674">"en <xliff:g id="COUNT">%d</xliff:g> h"</string>
<string name="duration_days_shortest_future" msgid="3392722163935571543">"en <xliff:g id="COUNT">%d</xliff:g> d"</string>
<string name="duration_years_shortest_future" msgid="5537464088352970388">"en <xliff:g id="COUNT">%d</xliff:g> años"</string>
- <string name="duration_minutes_relative" msgid="8620337701051015593">"{count,plural, =1{Hace # minuto}other{Hace # minutos}}"</string>
- <string name="duration_hours_relative" msgid="4836449961693180253">"{count,plural, =1{Hace # hora}other{Hace # horas}}"</string>
- <string name="duration_days_relative" msgid="621965767567258302">"{count,plural, =1{Hace # día}other{Hace # días}}"</string>
- <string name="duration_years_relative" msgid="8731202348869424370">"{count,plural, =1{Hace # año}other{Hace # años}}"</string>
- <string name="duration_minutes_relative_future" msgid="5259574171747708115">"{count,plural, =1{# minuto}other{# minutos}}"</string>
- <string name="duration_hours_relative_future" msgid="6670440478481140565">"{count,plural, =1{# hora}other{# horas}}"</string>
- <string name="duration_days_relative_future" msgid="8870658635774250746">"{count,plural, =1{# día}other{# días}}"</string>
- <string name="duration_years_relative_future" msgid="8855853883925918380">"{count,plural, =1{# año}other{# años}}"</string>
+ <string name="duration_minutes_relative" msgid="8620337701051015593">"{count,plural, =1{Hace # minuto}many{Hace # minutos}other{Hace # minutos}}"</string>
+ <string name="duration_hours_relative" msgid="4836449961693180253">"{count,plural, =1{Hace # hora}many{Hace # horas}other{Hace # horas}}"</string>
+ <string name="duration_days_relative" msgid="621965767567258302">"{count,plural, =1{Hace # día}many{Hace # días}other{Hace # días}}"</string>
+ <string name="duration_years_relative" msgid="8731202348869424370">"{count,plural, =1{Hace # año}many{Hace # años}other{Hace # años}}"</string>
+ <string name="duration_minutes_relative_future" msgid="5259574171747708115">"{count,plural, =1{# minuto}many{# minutos}other{# minutos}}"</string>
+ <string name="duration_hours_relative_future" msgid="6670440478481140565">"{count,plural, =1{# hora}many{# horas}other{# horas}}"</string>
+ <string name="duration_days_relative_future" msgid="8870658635774250746">"{count,plural, =1{# día}many{# días}other{# días}}"</string>
+ <string name="duration_years_relative_future" msgid="8855853883925918380">"{count,plural, =1{# año}many{# años}other{# años}}"</string>
<string name="VideoView_error_title" msgid="5750686717225068016">"Problemas de video"</string>
<string name="VideoView_error_text_invalid_progressive_playback" msgid="3782449246085134720">"No es posible transmitir este video al dispositivo."</string>
<string name="VideoView_error_text_unknown" msgid="7658683339707607138">"No se puede reproducir el video."</string>
@@ -1426,7 +1428,7 @@
<string name="ext_media_unmount_action" msgid="966992232088442745">"Expulsar"</string>
<string name="ext_media_browse_action" msgid="344865351947079139">"Explorar"</string>
<string name="ext_media_seamless_action" msgid="8837030226009268080">"Cambiar salida"</string>
- <string name="ext_media_missing_title" msgid="3209472091220515046">"No se encuentra dispositivo <xliff:g id="NAME">%s</xliff:g>."</string>
+ <string name="ext_media_missing_title" msgid="3209472091220515046">"Falta <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="ext_media_missing_message" msgid="4408988706227922909">"Vuelve a insertar dispositivo"</string>
<string name="ext_media_move_specific_title" msgid="8492118544775964250">"Transfiriendo la aplicación <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="ext_media_move_title" msgid="2682741525619033637">"Transfiriendo los datos"</string>
@@ -1508,7 +1510,7 @@
<string name="skip_button_label" msgid="3566599811326688389">"Omitir"</string>
<string name="no_matches" msgid="6472699895759164599">"Sin coincidencias"</string>
<string name="find_on_page" msgid="5400537367077438198">"Buscar en la página"</string>
- <string name="matches_found" msgid="2296462299979507689">"{count,plural, =1{# coincidencia}other{# de {total}}}"</string>
+ <string name="matches_found" msgid="2296462299979507689">"{count,plural, =1{# coincidencia}many{# de {total}}other{# de {total}}}"</string>
<string name="action_mode_done" msgid="2536182504764803222">"Listo"</string>
<string name="progress_erasing" msgid="6891435992721028004">"Borrando almacenamiento compartido…"</string>
<string name="share" msgid="4157615043345227321">"Compartir"</string>
@@ -1861,14 +1863,14 @@
<string name="data_saver_description" msgid="4995164271550590517">"Para reducir el uso de datos, el modo Ahorro de datos evita que algunas apps envíen y reciban datos en segundo plano. La app que estés usando podrá acceder a los datos, pero con menor frecuencia. De esta forma, por ejemplo, las imágenes no se mostrarán hasta que las presiones."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"¿Deseas activar Ahorro de datos?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Activar"</string>
- <string name="zen_mode_duration_minutes_summary" msgid="4555514757230849789">"{count,plural, =1{Por un minuto (hasta {formattedTime})}other{Por # minutos (hasta {formattedTime})}}"</string>
- <string name="zen_mode_duration_minutes_summary_short" msgid="1187553788355486950">"{count,plural, =1{Durante 1 min (hasta {formattedTime})}other{Durante # min (hasta {formattedTime})}}"</string>
- <string name="zen_mode_duration_hours_summary" msgid="3866333100793277211">"{count,plural, =1{Durante 1 hora (hasta {formattedTime})}other{Durante # horas (hasta {formattedTime})}}"</string>
- <string name="zen_mode_duration_hours_summary_short" msgid="687919813833347945">"{count,plural, =1{Durante 1 h (hasta {formattedTime})}other{Durante # h (hasta {formattedTime})}}"</string>
- <string name="zen_mode_duration_minutes" msgid="2340007982276569054">"{count,plural, =1{Durante un minuto}other{Durante # minutos}}"</string>
- <string name="zen_mode_duration_minutes_short" msgid="2435756450204526554">"{count,plural, =1{Durante 1 min}other{Durante # min}}"</string>
- <string name="zen_mode_duration_hours" msgid="7841806065034711849">"{count,plural, =1{Durante 1 hora}other{Durante # horas}}"</string>
- <string name="zen_mode_duration_hours_short" msgid="3666949653933099065">"{count,plural, =1{Durante 1 h}other{Durante # h}}"</string>
+ <string name="zen_mode_duration_minutes_summary" msgid="4555514757230849789">"{count,plural, =1{Por un minuto (hasta {formattedTime})}many{Por # minutos (hasta {formattedTime})}other{Por # minutos (hasta {formattedTime})}}"</string>
+ <string name="zen_mode_duration_minutes_summary_short" msgid="1187553788355486950">"{count,plural, =1{Durante 1 min (hasta {formattedTime})}many{Durante # min (hasta {formattedTime})}other{Durante # min (hasta {formattedTime})}}"</string>
+ <string name="zen_mode_duration_hours_summary" msgid="3866333100793277211">"{count,plural, =1{Durante 1 hora (hasta {formattedTime})}many{Durante # horas (hasta {formattedTime})}other{Durante # horas (hasta {formattedTime})}}"</string>
+ <string name="zen_mode_duration_hours_summary_short" msgid="687919813833347945">"{count,plural, =1{Durante 1 h (hasta {formattedTime})}many{Durante # h (hasta {formattedTime})}other{Durante # h (hasta {formattedTime})}}"</string>
+ <string name="zen_mode_duration_minutes" msgid="2340007982276569054">"{count,plural, =1{Durante un minuto}many{Durante # minutos}other{Durante # minutos}}"</string>
+ <string name="zen_mode_duration_minutes_short" msgid="2435756450204526554">"{count,plural, =1{Durante 1 min}many{Durante # min}other{Durante # min}}"</string>
+ <string name="zen_mode_duration_hours" msgid="7841806065034711849">"{count,plural, =1{Durante 1 hora}many{Durante # horas}other{Durante # horas}}"</string>
+ <string name="zen_mode_duration_hours_short" msgid="3666949653933099065">"{count,plural, =1{Durante 1 h}many{Durante # h}other{Durante # h}}"</string>
<string name="zen_mode_until_next_day" msgid="1403042784161725038">"Hasta las <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
<string name="zen_mode_until" msgid="2250286190237669079">"Hasta la(s) <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
<string name="zen_mode_alarm" msgid="7046911727540499275">"Hasta la hora <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (próxima alarma)"</string>
@@ -1926,8 +1928,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"Preferencia de región"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Nombre del idioma"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"Sugeridos"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Sugerencias"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"Todos los idiomas"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"Todas las regiones"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"Búsqueda"</string>
@@ -2000,7 +2001,7 @@
<string name="autofill_save_accessibility_title" msgid="1523225776218450005">"Guardar para Autocompletar"</string>
<string name="autofill_error_cannot_autofill" msgid="6528827648643138596">"El contenido no puede autocompletarse"</string>
<string name="autofill_picker_no_suggestions" msgid="1076022650427481509">"No hay sugerencias de Autocompletar"</string>
- <string name="autofill_picker_some_suggestions" msgid="5560549696296202701">"{count,plural, =1{Una sugerencia de autocompletar}other{# sugerencias de autocompletar}}"</string>
+ <string name="autofill_picker_some_suggestions" msgid="5560549696296202701">"{count,plural, =1{Una sugerencia de autocompletar}many{# sugerencias de autocompletar}other{# sugerencias de autocompletar}}"</string>
<string name="autofill_save_title" msgid="7719802414283739775">"¿Quieres guardar en "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"?"</string>
<string name="autofill_save_title_with_type" msgid="3002460014579799605">"¿Quieres guardar la <xliff:g id="TYPE">%1$s</xliff:g> en "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"?"</string>
<string name="autofill_save_title_with_2types" msgid="3783270967447869241">"¿Quieres guardar <xliff:g id="TYPE_0">%1$s</xliff:g> y <xliff:g id="TYPE_1">%2$s</xliff:g> en "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"?"</string>
@@ -2050,8 +2051,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"¿Quieres permitir que <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> acceda a todos los registros del dispositivo?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"Permitir acceso por única vez"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"No permitir"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"Los registros del dispositivo permiten documentar lo que sucede en él. Las apps pueden usar estos registros para encontrar y solucionar problemas.\n\nEs posible que algunos registros del dispositivo contengan información sensible, por lo que solo debes permitir que accedan a todos ellos las apps que sean de tu confianza. \n\nSi no permites que esta app acceda a todos los registros del dispositivo, aún puede acceder a sus propios registros. Además, es posible que el fabricante del dispositivo acceda a algunos registros o información en tu dispositivo."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"No volver a mostrar"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> quiere mostrar fragmentos de <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Editar"</string>
@@ -2111,7 +2111,7 @@
<string name="mime_type_presentation_ext" msgid="8761049335564371468">"Presentación <xliff:g id="EXTENSION">%1$s</xliff:g>"</string>
<string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"La conexión Bluetooth permanecerá activa durante el modo de avión"</string>
<string name="car_loading_profile" msgid="8219978381196748070">"Cargando"</string>
- <string name="file_count" msgid="3220018595056126969">"{count,plural, =1{{file_name} y # archivo más}other{{file_name} y # archivos más}}"</string>
+ <string name="file_count" msgid="3220018595056126969">"{count,plural, =1{{file_name} y # archivo más}many{{file_name} y # archivos más}other{{file_name} y # archivos más}}"</string>
<string name="chooser_no_direct_share_targets" msgid="1511722103987329028">"No hay personas recomendadas con quienes compartir"</string>
<string name="chooser_all_apps_button_label" msgid="3230427756238666328">"Lista de apps"</string>
<string name="usb_device_resolve_prompt_warn" msgid="325871329788064199">"Aunque no se le otorgó permiso de grabación a esta app, puede capturar audio con este dispositivo USB."</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index db3f51b..cdd602d 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -51,6 +51,7 @@
<string name="needPuk2" msgid="7032612093451537186">"Introduce el código PUK2 para desbloquear la tarjeta SIM."</string>
<string name="enablePin" msgid="2543771964137091212">"Error, habilitar bloqueo de SIM/RUIM."</string>
<plurals name="pinpuk_attempts" formatted="false" msgid="1619867269012213584">
+ <item quantity="many">You have <xliff:g id="NUMBER_1">%d</xliff:g> remaining attempts before SIM is locked.</item>
<item quantity="other">Te quedan <xliff:g id="NUMBER_1">%d</xliff:g> intentos para bloquear la tarjeta SIM.</item>
<item quantity="one">Te queda <xliff:g id="NUMBER_0">%d</xliff:g> intento para bloquear la tarjeta SIM.</item>
</plurals>
@@ -180,7 +181,7 @@
<string name="low_memory" product="watch" msgid="3479447988234030194">"El almacenamiento del reloj está lleno. Elimina algunos archivos para liberar espacio."</string>
<string name="low_memory" product="tv" msgid="6663680413790323318">"El espacio de almacenamiento de tu dispositivo Android TV está lleno. Elimina algunos archivos para liberar espacio."</string>
<string name="low_memory" product="default" msgid="2539532364144025569">"Se ha agotado el espacio de almacenamiento del teléfono. Elimina algunos archivos para liberar espacio."</string>
- <string name="ssl_ca_cert_warning" msgid="7233573909730048571">"{count,plural, =1{Autoridad de certificación instalada}other{Autoridades de certificación instaladas}}"</string>
+ <string name="ssl_ca_cert_warning" msgid="7233573909730048571">"{count,plural, =1{Autoridad de certificación instalada}many{Autoridades de certificación instaladas}other{Autoridades de certificación instaladas}}"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4961102218216815242">"Por un tercero desconocido"</string>
<string name="ssl_ca_cert_noti_by_administrator" msgid="4564941950768783879">"Por el administrador de tu perfil de trabajo"</string>
<string name="ssl_ca_cert_noti_managed" msgid="217337232273211674">"Por <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
@@ -254,7 +255,7 @@
<string name="bugreport_option_interactive_summary" msgid="8493795476325339542">"Usa esta opción en la mayoría de los casos. Te permite realizar un seguimiento del progreso del informe, introducir más información sobre el problema y hacer capturas de pantalla. Es posible que se omitan algunas secciones menos utilizadas y que requieran más tiempo."</string>
<string name="bugreport_option_full_title" msgid="7681035745950045690">"Informe completo"</string>
<string name="bugreport_option_full_summary" msgid="1975130009258435885">"Utiliza esta opción para que la interferencia del sistema sea mínima cuando el dispositivo no responda o funcione demasiado lento, o bien cuando necesites todas las secciones del informe. No permite introducir más detalles ni hacer más capturas de pantalla."</string>
- <string name="bugreport_countdown" msgid="6418620521782120755">"{count,plural, =1{La captura de pantalla para el informe de errores se hará en # segundo.}other{La captura de pantalla para el informe de errores se hará en # segundos.}}"</string>
+ <string name="bugreport_countdown" msgid="6418620521782120755">"{count,plural, =1{La captura de pantalla para el informe de errores se hará en # segundo.}many{La captura de pantalla para el informe de errores se hará en # segundos.}other{La captura de pantalla para el informe de errores se hará en # segundos.}}"</string>
<string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Se ha hecho la captura de pantalla con el informe de errores"</string>
<string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"No se ha podido hacer la captura de pantalla con el informe de errores"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Modo Silencio"</string>
@@ -608,7 +609,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"Se ha cancelado la operación de huella digital."</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"El usuario ha cancelado la operación de huella digital."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"Demasiados intentos. Vuelve a intentarlo más tarde."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Demasiados intentos. Se ha inhabilitado el sensor de huellas digitales."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Demasiados intentos. Usa el bloqueo de pantalla."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Vuelve a intentarlo."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"No se ha registrado ninguna huella digital."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Este dispositivo no tiene sensor de huellas digitales."</string>
@@ -637,7 +638,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Visita un proveedor de reparaciones."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"No se puede crear tu modelo. Inténtalo de nuevo."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Hay demasiada luz. Busca un sitio menos iluminado."</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"Prueba en un lugar con más luz"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"Aleja el teléfono"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"Acerca el teléfono"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"Sube el teléfono"</string>
@@ -1087,7 +1089,7 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="4312979647356179250">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> quiere habilitar la exploración táctil. Cuando esta función esté activada, podrás escuchar o ver descripciones del contenido seleccionado o usar gestos para interactuar con el teléfono."</string>
<string name="oneMonthDurationPast" msgid="4538030857114635777">"Hace un mes"</string>
<string name="beforeOneMonthDurationPast" msgid="8315149541372065392">"Hace más de un mes"</string>
- <string name="last_num_days" msgid="2393660431490280537">"{count,plural, =1{Último día (#)}other{Últimos # días}}"</string>
+ <string name="last_num_days" msgid="2393660431490280537">"{count,plural, =1{Último día (#)}many{Últimos # días}other{Últimos # días}}"</string>
<string name="last_month" msgid="1528906781083518683">"El mes pasado"</string>
<string name="older" msgid="1645159827884647400">"Anterior"</string>
<string name="preposition_for_date" msgid="2780767868832729599">"<xliff:g id="DATE">%s</xliff:g>"</string>
@@ -1114,14 +1116,14 @@
<string name="duration_hours_shortest_future" msgid="2979276794547981674">"en <xliff:g id="COUNT">%d</xliff:g>h"</string>
<string name="duration_days_shortest_future" msgid="3392722163935571543">"en <xliff:g id="COUNT">%d</xliff:g> d"</string>
<string name="duration_years_shortest_future" msgid="5537464088352970388">"en <xliff:g id="COUNT">%d</xliff:g>a"</string>
- <string name="duration_minutes_relative" msgid="8620337701051015593">"{count,plural, =1{Hace # minuto}other{Hace # minutos}}"</string>
- <string name="duration_hours_relative" msgid="4836449961693180253">"{count,plural, =1{Hace # hora}other{Hace # horas}}"</string>
- <string name="duration_days_relative" msgid="621965767567258302">"{count,plural, =1{Hace # día}other{Hace # días}}"</string>
- <string name="duration_years_relative" msgid="8731202348869424370">"{count,plural, =1{Hace # año}other{Hace # años}}"</string>
- <string name="duration_minutes_relative_future" msgid="5259574171747708115">"{count,plural, =1{# minuto}other{# minutos}}"</string>
- <string name="duration_hours_relative_future" msgid="6670440478481140565">"{count,plural, =1{# hora}other{# horas}}"</string>
- <string name="duration_days_relative_future" msgid="8870658635774250746">"{count,plural, =1{# día}other{# días}}"</string>
- <string name="duration_years_relative_future" msgid="8855853883925918380">"{count,plural, =1{# año}other{# años}}"</string>
+ <string name="duration_minutes_relative" msgid="8620337701051015593">"{count,plural, =1{Hace # minuto}many{Hace # minutos}other{Hace # minutos}}"</string>
+ <string name="duration_hours_relative" msgid="4836449961693180253">"{count,plural, =1{Hace # hora}many{Hace # horas}other{Hace # horas}}"</string>
+ <string name="duration_days_relative" msgid="621965767567258302">"{count,plural, =1{Hace # día}many{Hace # días}other{Hace # días}}"</string>
+ <string name="duration_years_relative" msgid="8731202348869424370">"{count,plural, =1{Hace # año}many{Hace # años}other{Hace # años}}"</string>
+ <string name="duration_minutes_relative_future" msgid="5259574171747708115">"{count,plural, =1{# minuto}many{# minutos}other{# minutos}}"</string>
+ <string name="duration_hours_relative_future" msgid="6670440478481140565">"{count,plural, =1{# hora}many{# horas}other{# horas}}"</string>
+ <string name="duration_days_relative_future" msgid="8870658635774250746">"{count,plural, =1{# día}many{# días}other{# días}}"</string>
+ <string name="duration_years_relative_future" msgid="8855853883925918380">"{count,plural, =1{# año}many{# años}other{# años}}"</string>
<string name="VideoView_error_title" msgid="5750686717225068016">"Incidencias con el vídeo"</string>
<string name="VideoView_error_text_invalid_progressive_playback" msgid="3782449246085134720">"Este vídeo no se puede transmitir al dispositivo."</string>
<string name="VideoView_error_text_unknown" msgid="7658683339707607138">"No se puede reproducir el vídeo."</string>
@@ -1508,7 +1510,7 @@
<string name="skip_button_label" msgid="3566599811326688389">"Saltar"</string>
<string name="no_matches" msgid="6472699895759164599">"No hay coincidencias."</string>
<string name="find_on_page" msgid="5400537367077438198">"Buscar en la página"</string>
- <string name="matches_found" msgid="2296462299979507689">"{count,plural, =1{# coincidencia}other{# de {total}}}"</string>
+ <string name="matches_found" msgid="2296462299979507689">"{count,plural, =1{# coincidencia}many{# de {total}}other{# de {total}}}"</string>
<string name="action_mode_done" msgid="2536182504764803222">"Hecho"</string>
<string name="progress_erasing" msgid="6891435992721028004">"Borrando almacenamiento compartido…"</string>
<string name="share" msgid="4157615043345227321">"Compartir"</string>
@@ -1861,14 +1863,14 @@
<string name="data_saver_description" msgid="4995164271550590517">"Para reducir el uso de datos, Ahorro de datos evita que algunas aplicaciones envíen o reciban datos en segundo plano. Si estás usando una aplicación, podrá acceder a datos, pero con menos frecuencia. Esto significa que es posible que, por ejemplo, algunas imágenes no se muestren hasta que las toques."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"¿Activar Ahorro de datos?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Activar"</string>
- <string name="zen_mode_duration_minutes_summary" msgid="4555514757230849789">"{count,plural, =1{Durante un minuto (hasta las {formattedTime})}other{Durante # minutos (hasta las {formattedTime})}}"</string>
- <string name="zen_mode_duration_minutes_summary_short" msgid="1187553788355486950">"{count,plural, =1{Durante 1 min (hasta las {formattedTime})}other{Durante # min (hasta las {formattedTime})}}"</string>
- <string name="zen_mode_duration_hours_summary" msgid="3866333100793277211">"{count,plural, =1{Durante 1 hora (hasta las {formattedTime})}other{Durante # horas (hasta las {formattedTime})}}"</string>
- <string name="zen_mode_duration_hours_summary_short" msgid="687919813833347945">"{count,plural, =1{Durante 1 h (hasta las {formattedTime})}other{Durante # h (hasta las {formattedTime})}}"</string>
- <string name="zen_mode_duration_minutes" msgid="2340007982276569054">"{count,plural, =1{Durante 1 minuto}other{Durante # minutos}}"</string>
- <string name="zen_mode_duration_minutes_short" msgid="2435756450204526554">"{count,plural, =1{Durante 1 min}other{Durante # min}}"</string>
- <string name="zen_mode_duration_hours" msgid="7841806065034711849">"{count,plural, =1{Durante 1 hora}other{Durante # horas}}"</string>
- <string name="zen_mode_duration_hours_short" msgid="3666949653933099065">"{count,plural, =1{Durante 1 h}other{Durante # h}}"</string>
+ <string name="zen_mode_duration_minutes_summary" msgid="4555514757230849789">"{count,plural, =1{Durante un minuto (hasta las {formattedTime})}many{Durante # minutos (hasta las {formattedTime})}other{Durante # minutos (hasta las {formattedTime})}}"</string>
+ <string name="zen_mode_duration_minutes_summary_short" msgid="1187553788355486950">"{count,plural, =1{Durante 1 min (hasta las {formattedTime})}many{Durante # min (hasta las {formattedTime})}other{Durante # min (hasta las {formattedTime})}}"</string>
+ <string name="zen_mode_duration_hours_summary" msgid="3866333100793277211">"{count,plural, =1{Durante 1 hora (hasta las {formattedTime})}many{Durante # horas (hasta las {formattedTime})}other{Durante # horas (hasta las {formattedTime})}}"</string>
+ <string name="zen_mode_duration_hours_summary_short" msgid="687919813833347945">"{count,plural, =1{Durante 1 h (hasta las {formattedTime})}many{Durante # h (hasta las {formattedTime})}other{Durante # h (hasta las {formattedTime})}}"</string>
+ <string name="zen_mode_duration_minutes" msgid="2340007982276569054">"{count,plural, =1{Durante 1 minuto}many{Durante # minutos}other{Durante # minutos}}"</string>
+ <string name="zen_mode_duration_minutes_short" msgid="2435756450204526554">"{count,plural, =1{Durante 1 min}many{Durante # min}other{Durante # min}}"</string>
+ <string name="zen_mode_duration_hours" msgid="7841806065034711849">"{count,plural, =1{Durante 1 hora}many{Durante # horas}other{Durante # horas}}"</string>
+ <string name="zen_mode_duration_hours_short" msgid="3666949653933099065">"{count,plural, =1{Durante 1 h}many{Durante # h}other{Durante # h}}"</string>
<string name="zen_mode_until_next_day" msgid="1403042784161725038">"Hasta las <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
<string name="zen_mode_until" msgid="2250286190237669079">"Hasta <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
<string name="zen_mode_alarm" msgid="7046911727540499275">"Hasta las <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (próxima alarma)"</string>
@@ -1926,8 +1928,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"Preferencia de región"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Nombre de idioma"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"Sugeridos"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Sugerencias"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"Todos los idiomas"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"Todas las regiones"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"Buscar"</string>
@@ -2000,7 +2001,7 @@
<string name="autofill_save_accessibility_title" msgid="1523225776218450005">"Guardar en la función Autocompletar"</string>
<string name="autofill_error_cannot_autofill" msgid="6528827648643138596">"El contenido no se puede autocompletar"</string>
<string name="autofill_picker_no_suggestions" msgid="1076022650427481509">"No hay sugerencias de Autocompletar"</string>
- <string name="autofill_picker_some_suggestions" msgid="5560549696296202701">"{count,plural, =1{1 sugerencia de Autocompletar}other{# sugerencias de Autocompletar}}"</string>
+ <string name="autofill_picker_some_suggestions" msgid="5560549696296202701">"{count,plural, =1{1 sugerencia de Autocompletar}many{# sugerencias de Autocompletar}other{# sugerencias de Autocompletar}}"</string>
<string name="autofill_save_title" msgid="7719802414283739775">"¿Guardar en "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"?"</string>
<string name="autofill_save_title_with_type" msgid="3002460014579799605">"¿Guardar <xliff:g id="TYPE">%1$s</xliff:g> en "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"?"</string>
<string name="autofill_save_title_with_2types" msgid="3783270967447869241">"¿Guardar <xliff:g id="TYPE_0">%1$s</xliff:g> y <xliff:g id="TYPE_1">%2$s</xliff:g> en "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"?"</string>
@@ -2050,8 +2051,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"¿Permitir que <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> acceda a todos los registros del dispositivo?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"Permitir el acceso una vez"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"No permitir"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"Los registros del dispositivo documentan lo que sucede en tu dispositivo. Las aplicaciones pueden usar estos registros para encontrar y solucionar problemas.\n\nComo algunos registros pueden contener información sensible, es mejor que solo permitas que accedan a ellos las aplicaciones en las que confíes. \n\nAunque no permitas que esta aplicación acceda a todos los registros del dispositivo, aún podrá acceder a sus propios registros. El fabricante de tu dispositivo aún puede acceder a algunos registros o información de tu dispositivo."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"No volver a mostrar"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> quiere mostrar fragmentos de <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Editar"</string>
@@ -2111,7 +2111,7 @@
<string name="mime_type_presentation_ext" msgid="8761049335564371468">"Presentación <xliff:g id="EXTENSION">%1$s</xliff:g>"</string>
<string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"El Bluetooth seguirá activado en el modo Avión"</string>
<string name="car_loading_profile" msgid="8219978381196748070">"Cargando"</string>
- <string name="file_count" msgid="3220018595056126969">"{count,plural, =1{{file_name} y # archivo más}other{{file_name} y # archivos más}}"</string>
+ <string name="file_count" msgid="3220018595056126969">"{count,plural, =1{{file_name} y # archivo más}many{{file_name} y # archivos más}other{{file_name} y # archivos más}}"</string>
<string name="chooser_no_direct_share_targets" msgid="1511722103987329028">"No hay sugerencias de personas con las que compartir"</string>
<string name="chooser_all_apps_button_label" msgid="3230427756238666328">"Lista de aplicaciones"</string>
<string name="usb_device_resolve_prompt_warn" msgid="325871329788064199">"Esta aplicación no tiene permiso para grabar, pero podría capturar audio con este dispositivo USB."</string>
@@ -2292,7 +2292,6 @@
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Consultar aplicaciones activas"</string>
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"No se puede acceder a la cámara del teléfono desde tu <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"No se puede acceder a la cámara del tablet desde tu <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
- <!-- no translation found for vdm_secure_window (161700398158812314) -->
- <skip />
+ <string name="vdm_secure_window" msgid="161700398158812314">"No se puede acceder a este contenido durante una emisión. Prueba en tu teléfono."</string>
<string name="system_locale_title" msgid="711882686834677268">"Predeterminado del sistema"</string>
</resources>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 319b56c..f44120a 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -608,7 +608,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"Sõrmejälje toiming tühistati."</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Kasutaja tühistas sõrmejälje kasutamise."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"Liiga palju katseid. Proovige hiljem uuesti."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Liiga palju katseid. Sõrmejäljeandur on keelatud."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Liiga palju katseid. Kasutage selle asemel ekraanilukku."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Proovige uuesti."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Ühtegi sõrmejälge pole registreeritud."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Selles seadmes pole sõrmejäljeandurit."</string>
@@ -637,7 +637,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Külastage remonditeenuse pakkujat."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"Teie näomudelit ei saa luua. Proovige uuesti."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Liiga ere. Proovige hämaramat valgust."</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"Proovige parema valgustusega kohas"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"Liigutage telefoni kaugemale"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"Liigutage telefoni lähemale"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"Liigutage telefoni kõrgemale"</string>
@@ -1423,8 +1424,8 @@
<string name="ext_media_unmounting_notification_title" msgid="4147986383917892162">"Üksuse <xliff:g id="NAME">%s</xliff:g> väljutamine …"</string>
<string name="ext_media_unmounting_notification_message" msgid="5717036261538754203">"Ärge eemaldage"</string>
<string name="ext_media_init_action" msgid="2312974060585056709">"Seadistus"</string>
- <string name="ext_media_unmount_action" msgid="966992232088442745">"Eemaldamine"</string>
- <string name="ext_media_browse_action" msgid="344865351947079139">"Avastamine"</string>
+ <string name="ext_media_unmount_action" msgid="966992232088442745">"Eemalda"</string>
+ <string name="ext_media_browse_action" msgid="344865351947079139">"Avasta"</string>
<string name="ext_media_seamless_action" msgid="8837030226009268080">"Vahetage väljundit"</string>
<string name="ext_media_missing_title" msgid="3209472091220515046">"Üksust <xliff:g id="NAME">%s</xliff:g> pole"</string>
<string name="ext_media_missing_message" msgid="4408988706227922909">"Sisestage seade uuesti"</string>
@@ -1567,9 +1568,9 @@
<string name="action_bar_home_subtitle_description_format" msgid="4346835454749569826">"%1$s, %2$s, %3$s"</string>
<string name="storage_internal" msgid="8490227947584914460">"Sisemine jagatud mäluruum"</string>
<string name="storage_sd_card" msgid="3404740277075331881">"SD-kaart"</string>
- <string name="storage_sd_card_label" msgid="7526153141147470509">"Tootja <xliff:g id="MANUFACTURER">%s</xliff:g> SD-kaart"</string>
+ <string name="storage_sd_card_label" msgid="7526153141147470509">"<xliff:g id="MANUFACTURER">%s</xliff:g> SD-kaart"</string>
<string name="storage_usb_drive" msgid="448030813201444573">"USB-ketas"</string>
- <string name="storage_usb_drive_label" msgid="6631740655876540521">"Tootja <xliff:g id="MANUFACTURER">%s</xliff:g> USB-ketas"</string>
+ <string name="storage_usb_drive_label" msgid="6631740655876540521">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB-ketas"</string>
<string name="storage_usb" msgid="2391213347883616886">"USB-mäluseade"</string>
<string name="extract_edit_menu_button" msgid="63954536535863040">"Muuda"</string>
<string name="data_usage_warning_title" msgid="9034893717078325845">"Andmekasutuse hoiatus"</string>
@@ -1926,8 +1927,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"Piirkonnaeelistus"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Sisestage keele nimi"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"Soovitatud"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Soovitatud"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"Kõik keeled"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"Kõik piirkonnad"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"Otsing"</string>
@@ -2050,8 +2050,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Kas anda rakendusele <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> juurdepääs kõigile seadmelogidele?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"Luba ühekordne juurdepääs"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Ära luba"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"Seadmelogid jäädvustavad, mis teie seadmes toimub. Rakendused saavad neid logisid kasutada probleemide tuvastamiseks ja lahendamiseks.\n\nMõned logid võivad sisaldada tundlikku teavet, seega lubage juurdepääs kõigile seadmelogidele ainult rakendustele, mida usaldate. \n\nKui te ei luba sellel rakendusel kõigile seadmelogidele juurde pääseda, pääseb see siiski juurde oma logidele. Teie seadme tootja võib teie seadmes siiski teatud logidele või teabele juurde pääseda."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Ära kuva uuesti"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"Rakendus <xliff:g id="APP_0">%1$s</xliff:g> soovib näidata rakenduse <xliff:g id="APP_2">%2$s</xliff:g> lõike"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Muuda"</string>
@@ -2292,7 +2291,6 @@
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Vaadake aktiivseid rakendusi"</string>
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Teie seadmest <xliff:g id="DEVICE">%1$s</xliff:g> ei pääse telefoni kaamerale juurde"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Teie seadmest <xliff:g id="DEVICE">%1$s</xliff:g> ei pääse tahvelarvuti kaamerale juurde"</string>
- <!-- no translation found for vdm_secure_window (161700398158812314) -->
- <skip />
+ <string name="vdm_secure_window" msgid="161700398158812314">"Sellele ei pääse voogesituse ajal juurde. Proovige juurde pääseda oma telefonis."</string>
<string name="system_locale_title" msgid="711882686834677268">"Süsteemi vaikeseade"</string>
</resources>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 400e9e4..cf2bf17 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -57,7 +57,7 @@
<string name="imei" msgid="2157082351232630390">"IMEIa"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"Sarrerako deien identifikazio-zerbitzua"</string>
- <string name="ClirMmi" msgid="6752346475055446417">"Ezkutatu irteerako deitzailearen IDa"</string>
+ <string name="ClirMmi" msgid="6752346475055446417">"Ezkutatu irteerako deitzailearen identitatea"</string>
<string name="ColpMmi" msgid="4736462893284419302">"Konektatutako linearen IDa"</string>
<string name="ColrMmi" msgid="5889782479745764278">"Konektatutako linearen ID murriztapena"</string>
<string name="CfMmi" msgid="8390012691099787178">"Dei-desbideratzea"</string>
@@ -608,7 +608,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"Hatz-markaren eragiketa bertan behera utzi da."</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Erabiltzaileak bertan behera utzi du hatz-marka bidezko eragiketa."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"Saiakera gehiegi egin dituzu. Saiatu berriro geroago."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Saiakera gehiegi egin dituzu. Desgaitu egin da hatz-marken sentsorea."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Saiakera gehiegi egin dira. Erabili pantailaren blokeoa."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Saiatu berriro."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Ez da erregistratu hatz-markarik."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Gailu honek ez du hatz-marken sentsorerik."</string>
@@ -637,7 +637,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Jarri harremanetan konponketak egiten dituen hornitzaile batekin."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"Ezin da sortu aurpegi-eredua. Saiatu berriro."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Argi gehiegi dago. Joan toki ilunago batera."</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"Erabili argi gehiago"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"Urrundu telefonoa"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"Hurbildu telefonoa"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"Igo telefonoa"</string>
@@ -1926,8 +1927,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"Lurralde-hobespena"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Adierazi hizkuntza"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"Iradokitakoak"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Iradokitakoak"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"Hizkuntza guztiak"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"Lurralde guztiak"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"Bilaketa"</string>
@@ -2050,8 +2050,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Gailuko erregistro guztiak atzitzeko baimena eman nahi diozu <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> aplikazioari?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"Eman behin erabiltzeko baimena"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Ez eman baimenik"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"Gailuko erregistroetan gailuan gertatzen den guztia gordetzen da. Arazoak bilatu eta konpontzeko erabil ditzakete aplikazioek erregistro horiek.\n\nBaliteke erregistro batzuek kontuzko informazioa edukitzea. Beraz, eman gailuko erregistro guztiak atzitzeko baimena fidagarritzat jotzen dituzun aplikazioei bakarrik. \n\nNahiz eta gailuko erregistro guztiak atzitzeko baimena ez eman aplikazio honi, aplikazioak hari dagozkion erregistroak atzitu ahalko ditu. Gainera, baliteke gailuaren fabrikatzaileak gailuko erregistro edo datu batzuk atzitu ahal izatea."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Ez erakutsi berriro"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> aplikazioak <xliff:g id="APP_2">%2$s</xliff:g> aplikazioaren zatiak erakutsi nahi ditu"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Editatu"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 8081367..77fb376 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -608,7 +608,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"عملکرد اثر انگشت لغو شد."</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"کاربر عملیات اثر انگشت را لغو کرد"</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"تلاشهای زیادی انجام شده است. بعداً دوباره امتحان کنید."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"تلاشهای بسیاری زیادی انجام شده است. حسگر اثر انگشت غیرفعال شد."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"تلاشهای بیشازحد. حالا از قفل صفحه استفاده کنید."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"دوباره امتحان کنید."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"اثر انگشتی ثبت نشده است."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"این دستگاه حسگر اثر انگشت ندارد."</string>
@@ -637,7 +637,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"به ارائهدهنده خدمات تعمیر مراجعه کنید."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"مدل چهره ایجاد نشد. دوباره امتحان کنید."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"خیلی روشن است. روشناییاش را ملایمتر کنید."</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"نور را بیشتر کنید"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"تلفن را دورتر ببرید"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"تلفن را نزدیکتر بیاورید"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"تلفن را بالاتر ببرید"</string>
@@ -1423,7 +1424,7 @@
<string name="ext_media_unmounting_notification_title" msgid="4147986383917892162">"درحال بیرون راندن <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="ext_media_unmounting_notification_message" msgid="5717036261538754203">"جدا نکنید"</string>
<string name="ext_media_init_action" msgid="2312974060585056709">"راهاندازی"</string>
- <string name="ext_media_unmount_action" msgid="966992232088442745">"بیرون راندن"</string>
+ <string name="ext_media_unmount_action" msgid="966992232088442745">"خارج کردن"</string>
<string name="ext_media_browse_action" msgid="344865351947079139">"کاوش"</string>
<string name="ext_media_seamless_action" msgid="8837030226009268080">"تغییر خروجی"</string>
<string name="ext_media_missing_title" msgid="3209472091220515046">"<xliff:g id="NAME">%s</xliff:g> وجود ندارد"</string>
@@ -1926,8 +1927,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"اولویتهای منطقه"</string>
<string name="search_language_hint" msgid="7004225294308793583">"نام زبان را تایپ کنید"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"پیشنهادی"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"پیشنهادی"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"همه زبانها"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"همه منطقهها"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"جستجو"</string>
@@ -2050,8 +2050,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"به <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> اجازه میدهید به همه گزارشهای دستگاه دسترسی داشته باشد؟"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"مجاز کردن دسترسی یکباره"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"اجازه ندادن"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"گزارشهای دستگاه آنچه را در دستگاهتان رخ میدهد ثبت میکند. برنامهها میتوانند از این گزارشها برای پیدا کردن مشکلات و رفع آنها استفاده کنند.\n\nبرخیاز گزارشها ممکن است حاوی اطلاعات حساس باشند، بنابراین فقط به برنامههای مورداعتمادتان اجازه دسترسی به همه گزارشهای دستگاه را بدهید. \n\nاگر به این برنامه اجازه ندهید به همه گزارشهای دستگاه دسترسی داشته باشد، همچنان میتواند به گزارشهای خودش دسترسی داشته باشد. سازنده دستگاه نیز ممکن است همچنان بتواند به برخیاز گزارشها یا اطلاعات دستگاهتان دسترسی داشته باشد."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"دوباره نشان داده نشود"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> میخواهد تکههای <xliff:g id="APP_2">%2$s</xliff:g> را نشان دهد"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"ویرایش"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 3bc81d9..4bb12b5 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -608,7 +608,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"Sormenjälkitoiminto peruutettiin."</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Käyttäjä peruutti sormenjälkitoiminnon."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"Liian monta yritystä. Yritä myöhemmin uudelleen."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Liian monta yritystä. Sormenjälkitunnistin poistettu käytöstä."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Liian monta yritystä. Käytä näytön lukituksen avaustapaa."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Yritä uudelleen."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Sormenjälkiä ei ole otettu käyttöön."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Laitteessa ei ole sormenjälkitunnistinta."</string>
@@ -637,7 +637,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Ota yhteys korjauspalveluun."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"Kasvomallia ei voi luoda. Yritä uudelleen."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Liian kirkasta. Kokeile pehmeämpää valaistusta."</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"Kokeile kirkkaampaa valaistusta"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"Vie puhelin kauemmas"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"Tuo puhelin lähemmäs"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"Siirrä puhelinta ylemmäs"</string>
@@ -1926,8 +1927,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"Alueasetus"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Anna kielen nimi"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"Ehdotukset"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Ehdotettu"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"Kaikki kielet"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"Kaikki alueet"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"Haku"</string>
@@ -2050,8 +2050,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Saako <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> pääsyn kaikkiin laitelokeihin?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"Salli kertaluonteinen pääsy"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Älä salli"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"Laitteen tapahtumat tallentuvat laitelokeihin. Niiden avulla sovellukset voivat löytää ja korjata ongelmia.\n\nJotkin lokit voivat sisältää arkaluontoista tietoa, joten salli pääsy kaikkiin laitelokeihin vain sovelluksille, joihin luotat. \n\nJos et salli tälle sovellukselle pääsyä kaikkiin laitelokeihin, sillä on kuitenkin pääsy sen omiin lokeihin. Laitteen valmistajalla voi olla pääsy joihinkin lokeihin tai tietoihin laitteella."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Älä näytä uudelleen"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> haluaa näyttää osia sovelluksesta <xliff:g id="APP_2">%2$s</xliff:g>."</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Muokkaa"</string>
@@ -2292,7 +2291,6 @@
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Tarkista aktiiviset sovellukset"</string>
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"<xliff:g id="DEVICE">%1$s</xliff:g> ei pääse puhelimen kameraan"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"<xliff:g id="DEVICE">%1$s</xliff:g> ei pääse tabletin kameraan"</string>
- <!-- no translation found for vdm_secure_window (161700398158812314) -->
- <skip />
+ <string name="vdm_secure_window" msgid="161700398158812314">"Sisältöön ei saa pääsyä striimauksen aikana. Kokeile striimausta puhelimella."</string>
<string name="system_locale_title" msgid="711882686834677268">"Järjestelmän oletusarvo"</string>
</resources>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index f6fc2ed..ec15c9d 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -52,6 +52,7 @@
<string name="enablePin" msgid="2543771964137091212">"Opération infructueuse. Activez le verrouillage SIM/RUIM."</string>
<plurals name="pinpuk_attempts" formatted="false" msgid="1619867269012213584">
<item quantity="one">Il vous reste <xliff:g id="NUMBER_1">%d</xliff:g> tentative avant que votre carte SIM soit verrouillée.</item>
+ <item quantity="many">You have <xliff:g id="NUMBER_1">%d</xliff:g> remaining attempts before SIM is locked.</item>
<item quantity="other">Il vous reste <xliff:g id="NUMBER_1">%d</xliff:g> tentatives avant que votre carte SIM soit verrouillée.</item>
</plurals>
<string name="imei" msgid="2157082351232630390">"Code IIEM"</string>
@@ -180,7 +181,7 @@
<string name="low_memory" product="watch" msgid="3479447988234030194">"La mémoire de la montre est pleine. Supprimez des fichiers pour libérer de l\'espace."</string>
<string name="low_memory" product="tv" msgid="6663680413790323318">"L\'espace de stockage de l\'appareil Android TV est plein. Supprimez des fichiers pour libérer de l\'espace."</string>
<string name="low_memory" product="default" msgid="2539532364144025569">"La mémoire du téléphone est pleine. Veuillez supprimer des fichiers pour libérer de l\'espace."</string>
- <string name="ssl_ca_cert_warning" msgid="7233573909730048571">"{count,plural, =1{Autorité de certification installée}one{Autorité de certification installée}other{Autorités de certification installées}}"</string>
+ <string name="ssl_ca_cert_warning" msgid="7233573909730048571">"{count,plural, =1{Autorité de certification installée}one{Autorité de certification installée}many{Autorités de certification installées}other{Autorités de certification installées}}"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4961102218216815242">"Par un tiers inconnu"</string>
<string name="ssl_ca_cert_noti_by_administrator" msgid="4564941950768783879">"Par l\'administrateur de votre profil professionnel"</string>
<string name="ssl_ca_cert_noti_managed" msgid="217337232273211674">"Par <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
@@ -254,7 +255,7 @@
<string name="bugreport_option_interactive_summary" msgid="8493795476325339542">"Utilisez cette option dans la plupart des circonstances. Elle vous permet de suivre la progression du rapport, d\'entrer plus d\'information sur le problème et d\'effectuer des saisies d\'écran. Certaines sections moins utilisées et dont le remplissage demande beaucoup de temps peuvent être omises."</string>
<string name="bugreport_option_full_title" msgid="7681035745950045690">"Rapport complet"</string>
<string name="bugreport_option_full_summary" msgid="1975130009258435885">"Utilisez cette option pour qu\'il y ait le moins d\'interférences système possible lorsque votre appareil ne répond pas ou qu\'il est trop lent, ou lorsque vous avez besoin de toutes les sections du rapport de bogue. Aucune capture d\'écran supplémentaire ne peut être capturée, et vous ne pouvez entrer aucune autre information."</string>
- <string name="bugreport_countdown" msgid="6418620521782120755">"{count,plural, =1{Saisie d\'une capture d\'écran pour le rapport de bogue dans # seconde.}one{Saisie d\'une capture d\'écran pour le rapport de bogue dans # seconde.}other{Saisie d\'une capture d\'écran pour le rapport de bogue dans # secondes.}}"</string>
+ <string name="bugreport_countdown" msgid="6418620521782120755">"{count,plural, =1{Saisie d\'une capture d\'écran pour le rapport de bogue dans # seconde.}one{Saisie d\'une capture d\'écran pour le rapport de bogue dans # seconde.}many{Saisie d\'une capture d\'écran pour le rapport de bogue dans # secondes.}other{Saisie d\'une capture d\'écran pour le rapport de bogue dans # secondes.}}"</string>
<string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Capture d\'écran prise avec le rapport de bogue"</string>
<string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Échec de la prise de capture d\'écran avec le rapport de bogue"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Mode silencieux"</string>
@@ -608,7 +609,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"Opération d\'empreinte digitale numérique annulée."</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"L\'opération d\'empreinte digitale a été annulée par l\'utilisateur."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"Trop de tentatives. Veuillez réessayer plus tard."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Trop de tentatives. Capteur d\'empreintes digitales désactivé."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Trop de tentatives. Utilisez plutôt le verrouillage de l\'écran."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Réessayer."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Aucune empreinte digitale enregistrée."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Cet appareil ne possède pas de capteur d\'empreintes digitales."</string>
@@ -637,7 +638,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Consultez un fournisseur de services de réparation."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"Impossible de créer votre modèle facial. Réessayez."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Trop lumineux. Essayez un éclairage plus faible."</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"Essayez avec un éclairage plus fort"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"Éloignez le téléphone"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"Rapprochez le téléphone"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"Tenez le téléphone plus haut"</string>
@@ -1087,7 +1089,7 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="4312979647356179250">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> souhaite activer la fonctionnalité \"Explorer au toucher\". Lorsque celle-ci est activée, vous pouvez entendre ou voir les descriptions des éléments que vous sélectionnez, ou bien interagir avec le téléphone en effectuant certains gestes."</string>
<string name="oneMonthDurationPast" msgid="4538030857114635777">"Il y a 1 mois"</string>
<string name="beforeOneMonthDurationPast" msgid="8315149541372065392">"Il y a plus d\'un mois"</string>
- <string name="last_num_days" msgid="2393660431490280537">"{count,plural, =1{# dernier jour}one{# dernier jour}other{# derniers jours}}"</string>
+ <string name="last_num_days" msgid="2393660431490280537">"{count,plural, =1{# dernier jour}one{# dernier jour}many{# derniers jours}other{# derniers jours}}"</string>
<string name="last_month" msgid="1528906781083518683">"Le mois dernier"</string>
<string name="older" msgid="1645159827884647400">"Précédent"</string>
<string name="preposition_for_date" msgid="2780767868832729599">"le <xliff:g id="DATE">%s</xliff:g>"</string>
@@ -1114,14 +1116,14 @@
<string name="duration_hours_shortest_future" msgid="2979276794547981674">"dans <xliff:g id="COUNT">%d</xliff:g> h"</string>
<string name="duration_days_shortest_future" msgid="3392722163935571543">"dans <xliff:g id="COUNT">%d</xliff:g> j"</string>
<string name="duration_years_shortest_future" msgid="5537464088352970388">"dans <xliff:g id="COUNT">%d</xliff:g> a"</string>
- <string name="duration_minutes_relative" msgid="8620337701051015593">"{count,plural, =1{Il y a # minute}one{Il y a # minute}other{Il y a # minutes}}"</string>
- <string name="duration_hours_relative" msgid="4836449961693180253">"{count,plural, =1{Il y a # heure}one{Il y a # heure}other{Il y a # heures}}"</string>
- <string name="duration_days_relative" msgid="621965767567258302">"{count,plural, =1{Il y a # jour}one{Il y a # jour}other{Il y a # jours}}"</string>
- <string name="duration_years_relative" msgid="8731202348869424370">"{count,plural, =1{Il y a # an}one{Il y a # an}other{Il y a # ans}}"</string>
- <string name="duration_minutes_relative_future" msgid="5259574171747708115">"{count,plural, =1{# minute}one{# minute}other{# minutes}}"</string>
- <string name="duration_hours_relative_future" msgid="6670440478481140565">"{count,plural, =1{# heure}one{# heure}other{# heures}}"</string>
- <string name="duration_days_relative_future" msgid="8870658635774250746">"{count,plural, =1{# jour}one{# jour}other{# jours}}"</string>
- <string name="duration_years_relative_future" msgid="8855853883925918380">"{count,plural, =1{# an}one{# an}other{# ans}}"</string>
+ <string name="duration_minutes_relative" msgid="8620337701051015593">"{count,plural, =1{Il y a # minute}one{Il y a # minute}many{Il y a # minutes}other{Il y a # minutes}}"</string>
+ <string name="duration_hours_relative" msgid="4836449961693180253">"{count,plural, =1{Il y a # heure}one{Il y a # heure}many{Il y a # heures}other{Il y a # heures}}"</string>
+ <string name="duration_days_relative" msgid="621965767567258302">"{count,plural, =1{Il y a # jour}one{Il y a # jour}many{Il y a # jours}other{Il y a # jours}}"</string>
+ <string name="duration_years_relative" msgid="8731202348869424370">"{count,plural, =1{Il y a # an}one{Il y a # an}many{Il y a # ans}other{Il y a # ans}}"</string>
+ <string name="duration_minutes_relative_future" msgid="5259574171747708115">"{count,plural, =1{# minute}one{# minute}many{# minutes}other{# minutes}}"</string>
+ <string name="duration_hours_relative_future" msgid="6670440478481140565">"{count,plural, =1{# heure}one{# heure}many{# heures}other{# heures}}"</string>
+ <string name="duration_days_relative_future" msgid="8870658635774250746">"{count,plural, =1{# jour}one{# jour}many{# jours}other{# jours}}"</string>
+ <string name="duration_years_relative_future" msgid="8855853883925918380">"{count,plural, =1{# an}one{# an}many{# ans}other{# ans}}"</string>
<string name="VideoView_error_title" msgid="5750686717225068016">"Problème vidéo"</string>
<string name="VideoView_error_text_invalid_progressive_playback" msgid="3782449246085134720">"Impossible de lire cette vidéo en continu sur cet appareil."</string>
<string name="VideoView_error_text_unknown" msgid="7658683339707607138">"Impossible de lire la vidéo."</string>
@@ -1424,7 +1426,7 @@
<string name="ext_media_unmounting_notification_message" msgid="5717036261538754203">"Ne pas retirer"</string>
<string name="ext_media_init_action" msgid="2312974060585056709">"Configurer"</string>
<string name="ext_media_unmount_action" msgid="966992232088442745">"Éjecter"</string>
- <string name="ext_media_browse_action" msgid="344865351947079139">"Découvrir"</string>
+ <string name="ext_media_browse_action" msgid="344865351947079139">"Explorer"</string>
<string name="ext_media_seamless_action" msgid="8837030226009268080">"Changer de sortie"</string>
<string name="ext_media_missing_title" msgid="3209472091220515046">"Mémoire de stockage <xliff:g id="NAME">%s</xliff:g> manquante"</string>
<string name="ext_media_missing_message" msgid="4408988706227922909">"Insérez l\'appareil de nouveau"</string>
@@ -1508,7 +1510,7 @@
<string name="skip_button_label" msgid="3566599811326688389">"Ignorer"</string>
<string name="no_matches" msgid="6472699895759164599">"Aucune partie"</string>
<string name="find_on_page" msgid="5400537367077438198">"Rechercher sur la page"</string>
- <string name="matches_found" msgid="2296462299979507689">"{count,plural, =1{# correspondance}one{# sur {total}}other{# sur {total}}}"</string>
+ <string name="matches_found" msgid="2296462299979507689">"{count,plural, =1{# correspondance}one{# sur {total}}many{# sur {total}}other{# sur {total}}}"</string>
<string name="action_mode_done" msgid="2536182504764803222">"Terminé"</string>
<string name="progress_erasing" msgid="6891435992721028004">"Effacement du stockage partagé en cours…"</string>
<string name="share" msgid="4157615043345227321">"Partager"</string>
@@ -1861,14 +1863,14 @@
<string name="data_saver_description" msgid="4995164271550590517">"Pour aider à diminuer l\'utilisation des données, la fonctionnalité Économiseur de données empêche certaines applications d\'envoyer ou de recevoir des données en arrière-plan. Une application que vous utilisez actuellement peut accéder à des données, mais peut le faire moins souvent. Cela peut signifier, par exemple, que les images ne s\'affichent pas jusqu\'à ce que vous les touchiez."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Activer l\'économiseur de données?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Activer"</string>
- <string name="zen_mode_duration_minutes_summary" msgid="4555514757230849789">"{count,plural, =1{Pendant une minute (jusqu\'à {formattedTime})}one{Pendant # minute (jusqu\'à {formattedTime})}other{Pendant # minutes (jusqu\'à {formattedTime})}}"</string>
- <string name="zen_mode_duration_minutes_summary_short" msgid="1187553788355486950">"{count,plural, =1{Pendant 1 m (jusqu\'à {formattedTime})}one{Pendant # m (jusqu\'à {formattedTime})}other{Pendant # m (jusqu\'à {formattedTime})}}"</string>
- <string name="zen_mode_duration_hours_summary" msgid="3866333100793277211">"{count,plural, =1{Pendant 1 heure (jusqu\'à {formattedTime})}one{Pendant # heure (jusqu\'à {formattedTime})}other{Pendant # heures (jusqu\'à {formattedTime})}}"</string>
- <string name="zen_mode_duration_hours_summary_short" msgid="687919813833347945">"{count,plural, =1{Pendant 1 h (jusqu\'à {formattedTime})}one{Pendant # h (jusqu\'à {formattedTime})}other{Pendant # h (jusqu\'à {formattedTime})}}"</string>
- <string name="zen_mode_duration_minutes" msgid="2340007982276569054">"{count,plural, =1{Pendant une minute}one{Pendant # minute}other{Pendant # minutes}}"</string>
- <string name="zen_mode_duration_minutes_short" msgid="2435756450204526554">"{count,plural, =1{Pendant 1 m}one{Pendant # m}other{Pendant # m}}"</string>
- <string name="zen_mode_duration_hours" msgid="7841806065034711849">"{count,plural, =1{Pendant 1 heure}one{Pendant # heure}other{Pendant # heures}}"</string>
- <string name="zen_mode_duration_hours_short" msgid="3666949653933099065">"{count,plural, =1{Pendant 1 h}one{Pendant # h}other{Pendant # h}}"</string>
+ <string name="zen_mode_duration_minutes_summary" msgid="4555514757230849789">"{count,plural, =1{Pendant une minute (jusqu\'à {formattedTime})}one{Pendant # minute (jusqu\'à {formattedTime})}many{Pendant # minutes (jusqu\'à {formattedTime})}other{Pendant # minutes (jusqu\'à {formattedTime})}}"</string>
+ <string name="zen_mode_duration_minutes_summary_short" msgid="1187553788355486950">"{count,plural, =1{Pendant 1 m (jusqu\'à {formattedTime})}one{Pendant # m (jusqu\'à {formattedTime})}many{Pendant # m (jusqu\'à {formattedTime})}other{Pendant # m (jusqu\'à {formattedTime})}}"</string>
+ <string name="zen_mode_duration_hours_summary" msgid="3866333100793277211">"{count,plural, =1{Pendant 1 heure (jusqu\'à {formattedTime})}one{Pendant # heure (jusqu\'à {formattedTime})}many{Pendant # heures (jusqu\'à {formattedTime})}other{Pendant # heures (jusqu\'à {formattedTime})}}"</string>
+ <string name="zen_mode_duration_hours_summary_short" msgid="687919813833347945">"{count,plural, =1{Pendant 1 h (jusqu\'à {formattedTime})}one{Pendant # h (jusqu\'à {formattedTime})}many{Pendant # h (jusqu\'à {formattedTime})}other{Pendant # h (jusqu\'à {formattedTime})}}"</string>
+ <string name="zen_mode_duration_minutes" msgid="2340007982276569054">"{count,plural, =1{Pendant une minute}one{Pendant # minute}many{Pendant # minutes}other{Pendant # minutes}}"</string>
+ <string name="zen_mode_duration_minutes_short" msgid="2435756450204526554">"{count,plural, =1{Pendant 1 m}one{Pendant # m}many{Pendant # m}other{Pendant # m}}"</string>
+ <string name="zen_mode_duration_hours" msgid="7841806065034711849">"{count,plural, =1{Pendant 1 heure}one{Pendant # heure}many{Pendant # heures}other{Pendant # heures}}"</string>
+ <string name="zen_mode_duration_hours_short" msgid="3666949653933099065">"{count,plural, =1{Pendant 1 h}one{Pendant # h}many{Pendant # h}other{Pendant # h}}"</string>
<string name="zen_mode_until_next_day" msgid="1403042784161725038">"Jusqu\'à <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
<string name="zen_mode_until" msgid="2250286190237669079">"Jusqu\'à <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
<string name="zen_mode_alarm" msgid="7046911727540499275">"Jusqu\'à <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (alarme suivante)"</string>
@@ -1926,8 +1928,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"Préférences régionales"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Entrez la langue"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"Suggestions"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Suggestions"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"Toutes les langues"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"Toutes les régions"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"Rechercher"</string>
@@ -2000,7 +2001,7 @@
<string name="autofill_save_accessibility_title" msgid="1523225776218450005">"Enregistrer pour le remplissage automatique"</string>
<string name="autofill_error_cannot_autofill" msgid="6528827648643138596">"Le contenu ne peut pas être entré automatiquement"</string>
<string name="autofill_picker_no_suggestions" msgid="1076022650427481509">"Aucune suggestion de remplissage automatique"</string>
- <string name="autofill_picker_some_suggestions" msgid="5560549696296202701">"{count,plural, =1{Une suggestion de remplissage automatique}one{# suggestion de remplissage automatique}other{# suggestions de remplissage automatique}}"</string>
+ <string name="autofill_picker_some_suggestions" msgid="5560549696296202701">"{count,plural, =1{Une suggestion de remplissage automatique}one{# suggestion de remplissage automatique}many{# suggestions de remplissage automatique}other{# suggestions de remplissage automatique}}"</string>
<string name="autofill_save_title" msgid="7719802414283739775">"Enregistrer sous "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"?"</string>
<string name="autofill_save_title_with_type" msgid="3002460014579799605">"Enregistrer <xliff:g id="TYPE">%1$s</xliff:g> sous "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"?"</string>
<string name="autofill_save_title_with_2types" msgid="3783270967447869241">"Enregistrer <xliff:g id="TYPE_0">%1$s</xliff:g> et <xliff:g id="TYPE_1">%2$s</xliff:g> sous "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"?"</string>
@@ -2050,8 +2051,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Autoriser <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> à accéder à l\'ensemble des journaux de l\'appareil?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"Autoriser un accès unique"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Ne pas autoriser"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"Les journaux de l\'appareil enregistrent ce qui se passe sur celui-ci. Les applications peuvent utiliser ces journaux pour trouver et résoudre des problèmes.\n\nCertains journaux peuvent contenir des renseignements confidentiels. N\'autorisez donc que les applications auxquelles vous faites confiance puisque celles-ci pourront accéder à l\'ensemble des journaux de l\'appareil. \n\nMême si vous n\'autorisez pas cette application à accéder à l\'ensemble des journaux de l\'appareil, elle aura toujours accès à ses propres journaux. Le fabricant de votre appareil pourrait toujours être en mesure d\'accéder à certains journaux ou renseignements sur votre appareil."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Ne plus afficher"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> souhaite afficher <xliff:g id="APP_2">%2$s</xliff:g> tranches"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Modifier"</string>
@@ -2111,7 +2111,7 @@
<string name="mime_type_presentation_ext" msgid="8761049335564371468">"Présentation <xliff:g id="EXTENSION">%1$s</xliff:g>"</string>
<string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"Le Bluetooth restera activé en mode Avion"</string>
<string name="car_loading_profile" msgid="8219978381196748070">"Chargement en cours…"</string>
- <string name="file_count" msgid="3220018595056126969">"{count,plural, =1{{file_name} + # fichier}one{{file_name} + # fichier}other{{file_name} + # fichiers}}"</string>
+ <string name="file_count" msgid="3220018595056126969">"{count,plural, =1{{file_name} + # fichier}one{{file_name} + # fichier}many{{file_name} + # fichiers}other{{file_name} + # fichiers}}"</string>
<string name="chooser_no_direct_share_targets" msgid="1511722103987329028">"Aucune recommandation de personnes avec lesquelles effectuer un partage"</string>
<string name="chooser_all_apps_button_label" msgid="3230427756238666328">"Liste des applications"</string>
<string name="usb_device_resolve_prompt_warn" msgid="325871329788064199">"Cette application n\'a pas été autorisée à effectuer des enregistrements, mais elle pourrait capturer du contenu audio par l\'intermédiaire de cet appareil USB."</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 787590c..d410b6d 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -52,6 +52,7 @@
<string name="enablePin" msgid="2543771964137091212">"Échec de l\'opération. Veuillez activer le verrouillage de la carte SIM/RUIM."</string>
<plurals name="pinpuk_attempts" formatted="false" msgid="1619867269012213584">
<item quantity="one">Il vous reste <xliff:g id="NUMBER_1">%d</xliff:g> tentative avant que votre carte SIM ne soit verrouillée.</item>
+ <item quantity="many">You have <xliff:g id="NUMBER_1">%d</xliff:g> remaining attempts before SIM is locked.</item>
<item quantity="other">Il vous reste <xliff:g id="NUMBER_1">%d</xliff:g> tentatives avant que votre carte SIM ne soit verrouillée.</item>
</plurals>
<string name="imei" msgid="2157082351232630390">"Code IMEI"</string>
@@ -180,7 +181,7 @@
<string name="low_memory" product="watch" msgid="3479447988234030194">"La mémoire de la montre est saturée. Veuillez supprimer des fichiers pour libérer de l\'espace."</string>
<string name="low_memory" product="tv" msgid="6663680413790323318">"L\'espace de stockage de l\'appareil Android TV est saturé. Supprimez certains fichiers pour libérer de l\'espace."</string>
<string name="low_memory" product="default" msgid="2539532364144025569">"La mémoire du téléphone est pleine. Veuillez supprimer des fichiers pour libérer de l\'espace."</string>
- <string name="ssl_ca_cert_warning" msgid="7233573909730048571">"{count,plural, =1{Autorité de certification installée}one{Autorité de certification installée}other{Autorités de certification installées}}"</string>
+ <string name="ssl_ca_cert_warning" msgid="7233573909730048571">"{count,plural, =1{Autorité de certification installée}one{Autorité de certification installée}many{Autorités de certification installées}other{Autorités de certification installées}}"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4961102218216815242">"Par un tiers inconnu"</string>
<string name="ssl_ca_cert_noti_by_administrator" msgid="4564941950768783879">"Par l\'administrateur de votre profil professionnel"</string>
<string name="ssl_ca_cert_noti_managed" msgid="217337232273211674">"Par <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
@@ -254,7 +255,7 @@
<string name="bugreport_option_interactive_summary" msgid="8493795476325339542">"Utilisez cette option dans la plupart des circonstances. Elle vous permet de suivre la progression du rapport, de saisir plus d\'informations sur le problème et d\'effectuer des captures d\'écran. Certaines sections moins utilisées et dont le remplissage demande beaucoup de temps peuvent être omises."</string>
<string name="bugreport_option_full_title" msgid="7681035745950045690">"Rapport complet"</string>
<string name="bugreport_option_full_summary" msgid="1975130009258435885">"Utilisez cette option pour qu\'il y ait le moins d\'interférences système possible lorsque votre appareil ne répond pas ou qu\'il est trop lent, ou lorsque vous avez besoin de toutes les sections du rapport de bug. Aucune capture d\'écran supplémentaire ne peut être prise, et vous ne pouvez saisir aucune autre information."</string>
- <string name="bugreport_countdown" msgid="6418620521782120755">"{count,plural, =1{Capture d\'écran pour le rapport de bug dans # seconde.}one{Capture d\'écran pour le rapport de bug dans # seconde.}other{Capture d\'écran pour le rapport de bug dans # secondes.}}"</string>
+ <string name="bugreport_countdown" msgid="6418620521782120755">"{count,plural, =1{Capture d\'écran pour le rapport de bug dans # seconde.}one{Capture d\'écran pour le rapport de bug dans # seconde.}many{Capture d\'écran pour le rapport de bug dans # secondes.}other{Capture d\'écran pour le rapport de bug dans # secondes.}}"</string>
<string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Capture d\'écran avec rapport de bug effectuée"</string>
<string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Échec de la capture d\'écran avec le rapport de bug"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Mode silencieux"</string>
@@ -608,7 +609,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"Opération d\'empreinte digitale annulée."</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Opération d\'authentification par empreinte digitale annulée par l\'utilisateur."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"Trop de tentatives. Veuillez réessayer plus tard."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Trop de tentatives. Lecteur d\'empreinte digitale désactivé."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Trop de tentatives. Utilisez plutôt le verrouillage de l\'écran."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Veuillez réessayer."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Aucune empreinte digitale enregistrée."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Aucun lecteur d\'empreinte digitale n\'est installé sur cet appareil."</string>
@@ -637,7 +638,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Contactez un réparateur."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"Impossible de créer l\'empreinte faciale. Réessayez."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Trop lumineux. Essayez de baisser la lumière."</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"Essayez un éclairage plus lumineux"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"Éloignez le téléphone."</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"Rapprochez le téléphone"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"Déplacez le téléphone vers le haut"</string>
@@ -1087,7 +1089,7 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="4312979647356179250">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> souhaite activer la fonctionnalité \"Explorer au toucher\". Lorsque celle-ci est activée, vous pouvez entendre ou voir les descriptions des éléments que vous sélectionnez, ou bien interagir avec le téléphone en effectuant certains gestes."</string>
<string name="oneMonthDurationPast" msgid="4538030857114635777">"Il y a 1 mois"</string>
<string name="beforeOneMonthDurationPast" msgid="8315149541372065392">"Il y a plus d\'un mois"</string>
- <string name="last_num_days" msgid="2393660431490280537">"{count,plural, =1{Dernier jour (#)}one{Dernier jour (#)}other{# derniers jours}}"</string>
+ <string name="last_num_days" msgid="2393660431490280537">"{count,plural, =1{Dernier jour (#)}one{Dernier jour (#)}many{# derniers jours}other{# derniers jours}}"</string>
<string name="last_month" msgid="1528906781083518683">"Le mois dernier"</string>
<string name="older" msgid="1645159827884647400">"Préc."</string>
<string name="preposition_for_date" msgid="2780767868832729599">"le <xliff:g id="DATE">%s</xliff:g>"</string>
@@ -1114,14 +1116,14 @@
<string name="duration_hours_shortest_future" msgid="2979276794547981674">"dans <xliff:g id="COUNT">%d</xliff:g> h"</string>
<string name="duration_days_shortest_future" msgid="3392722163935571543">"dans <xliff:g id="COUNT">%d</xliff:g> j"</string>
<string name="duration_years_shortest_future" msgid="5537464088352970388">"dans <xliff:g id="COUNT">%d</xliff:g> an"</string>
- <string name="duration_minutes_relative" msgid="8620337701051015593">"{count,plural, =1{Il y a # minute}one{Il y a # minute}other{Il y a # minutes}}"</string>
- <string name="duration_hours_relative" msgid="4836449961693180253">"{count,plural, =1{Il y a # heure}one{Il y a # heure}other{Il y a # heures}}"</string>
- <string name="duration_days_relative" msgid="621965767567258302">"{count,plural, =1{Il y a # jour}one{Il y a # jour}other{Il y a # jours}}"</string>
- <string name="duration_years_relative" msgid="8731202348869424370">"{count,plural, =1{Il y a # an}one{Il y a # an}other{Il y a # ans}}"</string>
- <string name="duration_minutes_relative_future" msgid="5259574171747708115">"{count,plural, =1{# minute}one{# minute}other{# minutes}}"</string>
- <string name="duration_hours_relative_future" msgid="6670440478481140565">"{count,plural, =1{# heure}one{# heure}other{# heures}}"</string>
- <string name="duration_days_relative_future" msgid="8870658635774250746">"{count,plural, =1{# jour}one{# jour}other{# jours}}"</string>
- <string name="duration_years_relative_future" msgid="8855853883925918380">"{count,plural, =1{# an}one{# an}other{# ans}}"</string>
+ <string name="duration_minutes_relative" msgid="8620337701051015593">"{count,plural, =1{Il y a # minute}one{Il y a # minute}many{Il y a # minutes}other{Il y a # minutes}}"</string>
+ <string name="duration_hours_relative" msgid="4836449961693180253">"{count,plural, =1{Il y a # heure}one{Il y a # heure}many{Il y a # heures}other{Il y a # heures}}"</string>
+ <string name="duration_days_relative" msgid="621965767567258302">"{count,plural, =1{Il y a # jour}one{Il y a # jour}many{Il y a # jours}other{Il y a # jours}}"</string>
+ <string name="duration_years_relative" msgid="8731202348869424370">"{count,plural, =1{Il y a # an}one{Il y a # an}many{Il y a # ans}other{Il y a # ans}}"</string>
+ <string name="duration_minutes_relative_future" msgid="5259574171747708115">"{count,plural, =1{# minute}one{# minute}many{# minutes}other{# minutes}}"</string>
+ <string name="duration_hours_relative_future" msgid="6670440478481140565">"{count,plural, =1{# heure}one{# heure}many{# heures}other{# heures}}"</string>
+ <string name="duration_days_relative_future" msgid="8870658635774250746">"{count,plural, =1{# jour}one{# jour}many{# jours}other{# jours}}"</string>
+ <string name="duration_years_relative_future" msgid="8855853883925918380">"{count,plural, =1{# an}one{# an}many{# ans}other{# ans}}"</string>
<string name="VideoView_error_title" msgid="5750686717225068016">"Problème vidéo"</string>
<string name="VideoView_error_text_invalid_progressive_playback" msgid="3782449246085134720">"Impossible de lire cette vidéo en streaming sur cet appareil."</string>
<string name="VideoView_error_text_unknown" msgid="7658683339707607138">"Impossible de lire la vidéo."</string>
@@ -1426,7 +1428,7 @@
<string name="ext_media_unmount_action" msgid="966992232088442745">"Éjecter"</string>
<string name="ext_media_browse_action" msgid="344865351947079139">"Parcourir"</string>
<string name="ext_media_seamless_action" msgid="8837030226009268080">"Changer de sortie"</string>
- <string name="ext_media_missing_title" msgid="3209472091220515046">"Mémoire de stockage \"<xliff:g id="NAME">%s</xliff:g>\" manquante"</string>
+ <string name="ext_media_missing_title" msgid="3209472091220515046">"Support \"<xliff:g id="NAME">%s</xliff:g>\" manquant"</string>
<string name="ext_media_missing_message" msgid="4408988706227922909">"Insérez le périphérique"</string>
<string name="ext_media_move_specific_title" msgid="8492118544775964250">"Transfert de l\'application <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="ext_media_move_title" msgid="2682741525619033637">"Déplacement des données en cours"</string>
@@ -1508,7 +1510,7 @@
<string name="skip_button_label" msgid="3566599811326688389">"Ignorer"</string>
<string name="no_matches" msgid="6472699895759164599">"Aucune correspondance"</string>
<string name="find_on_page" msgid="5400537367077438198">"Rechercher sur la page"</string>
- <string name="matches_found" msgid="2296462299979507689">"{count,plural, =1{# correspondance}one{# sur {total}}other{# sur {total}}}"</string>
+ <string name="matches_found" msgid="2296462299979507689">"{count,plural, =1{# correspondance}one{# sur {total}}many{# sur {total}}other{# sur {total}}}"</string>
<string name="action_mode_done" msgid="2536182504764803222">"OK"</string>
<string name="progress_erasing" msgid="6891435992721028004">"Suppression de l\'espace de stockage partagé…"</string>
<string name="share" msgid="4157615043345227321">"Partager"</string>
@@ -1861,14 +1863,14 @@
<string name="data_saver_description" msgid="4995164271550590517">"Pour réduire la consommation des données, l\'Économiseur de données empêche certaines applis d\'envoyer ou de recevoir des données en arrière-plan. Les applis que vous utiliserez pourront toujours accéder aux données, mais le feront moins fréquemment. Par exemple, les images pourront ne pas s\'afficher tant que vous n\'aurez pas appuyé dessus."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Activer l\'Économiseur de données ?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Activer"</string>
- <string name="zen_mode_duration_minutes_summary" msgid="4555514757230849789">"{count,plural, =1{Pendant 1 minute (jusqu\'à {formattedTime})}one{Pendant # minute (jusqu\'à {formattedTime})}other{Pendant # minutes (jusqu\'à {formattedTime})}}"</string>
- <string name="zen_mode_duration_minutes_summary_short" msgid="1187553788355486950">"{count,plural, =1{Pendant 1 min (jusqu\'à {formattedTime})}one{Pendant # min (jusqu\'à {formattedTime})}other{Pendant # min (jusqu\'à {formattedTime})}}"</string>
- <string name="zen_mode_duration_hours_summary" msgid="3866333100793277211">"{count,plural, =1{Pendant 1 heure (jusqu\'à {formattedTime})}one{Pendant # heure (jusqu\'à {formattedTime})}other{Pendant # heures (jusqu\'à {formattedTime})}}"</string>
- <string name="zen_mode_duration_hours_summary_short" msgid="687919813833347945">"{count,plural, =1{Pendant 1 h (jusqu\'à {formattedTime})}one{Pendant # h (jusqu\'à {formattedTime})}other{Pendant # h (jusqu\'à {formattedTime})}}"</string>
- <string name="zen_mode_duration_minutes" msgid="2340007982276569054">"{count,plural, =1{Pendant 1 minute}one{Pendant # minute}other{Pendant # minutes}}"</string>
- <string name="zen_mode_duration_minutes_short" msgid="2435756450204526554">"{count,plural, =1{Pendant 1 min}one{Pendant # min}other{Pendant # min}}"</string>
- <string name="zen_mode_duration_hours" msgid="7841806065034711849">"{count,plural, =1{Pendant 1 heure}one{Pendant # heure}other{Pendant # heures}}"</string>
- <string name="zen_mode_duration_hours_short" msgid="3666949653933099065">"{count,plural, =1{Pendant 1 h}one{Pendant # h}other{Pendant # h}}"</string>
+ <string name="zen_mode_duration_minutes_summary" msgid="4555514757230849789">"{count,plural, =1{Pendant 1 minute (jusqu\'à {formattedTime})}one{Pendant # minute (jusqu\'à {formattedTime})}many{Pendant # minutes (jusqu\'à {formattedTime})}other{Pendant # minutes (jusqu\'à {formattedTime})}}"</string>
+ <string name="zen_mode_duration_minutes_summary_short" msgid="1187553788355486950">"{count,plural, =1{Pendant 1 min (jusqu\'à {formattedTime})}one{Pendant # min (jusqu\'à {formattedTime})}many{Pendant # min (jusqu\'à {formattedTime})}other{Pendant # min (jusqu\'à {formattedTime})}}"</string>
+ <string name="zen_mode_duration_hours_summary" msgid="3866333100793277211">"{count,plural, =1{Pendant 1 heure (jusqu\'à {formattedTime})}one{Pendant # heure (jusqu\'à {formattedTime})}many{Pendant # heures (jusqu\'à {formattedTime})}other{Pendant # heures (jusqu\'à {formattedTime})}}"</string>
+ <string name="zen_mode_duration_hours_summary_short" msgid="687919813833347945">"{count,plural, =1{Pendant 1 h (jusqu\'à {formattedTime})}one{Pendant # h (jusqu\'à {formattedTime})}many{Pendant # h (jusqu\'à {formattedTime})}other{Pendant # h (jusqu\'à {formattedTime})}}"</string>
+ <string name="zen_mode_duration_minutes" msgid="2340007982276569054">"{count,plural, =1{Pendant 1 minute}one{Pendant # minute}many{Pendant # minutes}other{Pendant # minutes}}"</string>
+ <string name="zen_mode_duration_minutes_short" msgid="2435756450204526554">"{count,plural, =1{Pendant 1 min}one{Pendant # min}many{Pendant # min}other{Pendant # min}}"</string>
+ <string name="zen_mode_duration_hours" msgid="7841806065034711849">"{count,plural, =1{Pendant 1 heure}one{Pendant # heure}many{Pendant # heures}other{Pendant # heures}}"</string>
+ <string name="zen_mode_duration_hours_short" msgid="3666949653933099065">"{count,plural, =1{Pendant 1 h}one{Pendant # h}many{Pendant # h}other{Pendant # h}}"</string>
<string name="zen_mode_until_next_day" msgid="1403042784161725038">"Jusqu\'à <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
<string name="zen_mode_until" msgid="2250286190237669079">"Jusqu\'à <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
<string name="zen_mode_alarm" msgid="7046911727540499275">"Jusqu\'à <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (alarme suivante)"</string>
@@ -1926,8 +1928,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"Préférences régionales"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Saisissez la langue"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"Suggestions"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Suggestions"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"Toutes les langues"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"Toutes les régions"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"Rechercher"</string>
@@ -2000,7 +2001,7 @@
<string name="autofill_save_accessibility_title" msgid="1523225776218450005">"Enregistrer pour la saisie automatique"</string>
<string name="autofill_error_cannot_autofill" msgid="6528827648643138596">"Le contenu ne peut pas être saisi automatiquement"</string>
<string name="autofill_picker_no_suggestions" msgid="1076022650427481509">"Aucune suggestion de saisie automatique"</string>
- <string name="autofill_picker_some_suggestions" msgid="5560549696296202701">"{count,plural, =1{1 suggestion de saisie automatique}one{# suggestion de saisie automatique}other{# suggestions de saisie automatique}}"</string>
+ <string name="autofill_picker_some_suggestions" msgid="5560549696296202701">"{count,plural, =1{1 suggestion de saisie automatique}one{# suggestion de saisie automatique}many{# suggestions de saisie automatique}other{# suggestions de saisie automatique}}"</string>
<string name="autofill_save_title" msgid="7719802414283739775">"Enregistrer dans "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>" ?"</string>
<string name="autofill_save_title_with_type" msgid="3002460014579799605">"Enregistrer la <xliff:g id="TYPE">%1$s</xliff:g> dans "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>" ?"</string>
<string name="autofill_save_title_with_2types" msgid="3783270967447869241">"Enregistrer <xliff:g id="TYPE_0">%1$s</xliff:g> et <xliff:g id="TYPE_1">%2$s</xliff:g> dans "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>" ?"</string>
@@ -2050,8 +2051,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Autoriser <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> à accéder à tous les journaux de l\'appareil ?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"Autoriser un accès unique"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Ne pas autoriser"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"Les journaux enregistrent ce qui se passe sur votre appareil. Les applis peuvent les utiliser pour rechercher et résoudre les problèmes.\n\nCertains journaux pouvant contenir des infos sensibles, autorisez uniquement les applis de confiance à accéder à tous les journaux de l\'appareil. \n\nSi vous refusez à cette appli l\'accès à tous les journaux de l\'appareil, elle a quand même accès aux siens. Le fabricant de l\'appareil peut accéder à certains journaux ou certaines infos sur votre appareil."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Ne plus afficher"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> souhaite afficher des éléments de <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Modifier"</string>
@@ -2111,7 +2111,7 @@
<string name="mime_type_presentation_ext" msgid="8761049335564371468">"Présentation <xliff:g id="EXTENSION">%1$s</xliff:g>"</string>
<string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"Le Bluetooth restera activé en mode Avion"</string>
<string name="car_loading_profile" msgid="8219978381196748070">"Chargement…"</string>
- <string name="file_count" msgid="3220018595056126969">"{count,plural, =1{{file_name} + # fichier}one{{file_name} + # fichier}other{{file_name} + # fichiers}}"</string>
+ <string name="file_count" msgid="3220018595056126969">"{count,plural, =1{{file_name} + # fichier}one{{file_name} + # fichier}many{{file_name} + # fichiers}other{{file_name} + # fichiers}}"</string>
<string name="chooser_no_direct_share_targets" msgid="1511722103987329028">"Aucune recommandation de personnes avec lesquelles effectuer un partage"</string>
<string name="chooser_all_apps_button_label" msgid="3230427756238666328">"Liste des applications"</string>
<string name="usb_device_resolve_prompt_warn" msgid="325871329788064199">"Cette application n\'a pas reçu l\'autorisation d\'enregistrer des contenus audio, mais peut le faire via ce périphérique USB."</string>
@@ -2292,7 +2292,6 @@
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Vérifier les applis actives"</string>
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Impossible d\'accéder à l\'appareil photo du téléphone depuis votre <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Impossible d\'accéder à l\'appareil photo de la tablette depuis votre <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
- <!-- no translation found for vdm_secure_window (161700398158812314) -->
- <skip />
+ <string name="vdm_secure_window" msgid="161700398158812314">"Impossible d\'accéder à cela pendant le streaming. Essayez plutôt sur votre téléphone."</string>
<string name="system_locale_title" msgid="711882686834677268">"Paramètre système par défaut"</string>
</resources>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 4fa41681a..c7a1911 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -608,7 +608,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"Cancelouse a operación da impresión dixital."</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"O usuario cancelou a operación da impresión dixital."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"Demasiados intentos. Téntao de novo máis tarde."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Demasiados intentos. Desactivouse o sensor de impresión dixital."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Demasiados intentos. Mellor usa o bloqueo de pantalla."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Téntao de novo."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Non se rexistraron impresións dixitais."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Este dispositivo non ten sensor de impresión dixital."</string>
@@ -637,7 +637,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Visita un provedor de reparacións."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"Non se puido crear o modelo facial. Téntao de novo."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Hai demasiada iluminación. Proba cunha máis suave."</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"Proba con máis luz"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"Afasta o teléfono"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"Achega o teléfono"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"Sube o teléfono"</string>
@@ -1926,8 +1927,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"Preferencia de rexión"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Escribe o nome do idioma"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"Suxeridos"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Rexións suxeridas"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"Todos os idiomas"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"Todas as rexións"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"Buscar"</string>
@@ -2050,8 +2050,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Queres permitir que a aplicación <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> acceda a todos os rexistros do dispositivo?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"Permitir acceso unha soa vez"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Non permitir"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"Os rexistros do dispositivo dan conta do que ocorre neste. As aplicacións poden usalos para buscar problemas e solucionalos.\n\nAlgúns poden conter información confidencial, polo que che recomendamos que só permitas que accedan a todos os rexistros do dispositivo as aplicacións nas que confíes. \n\nEsta aplicación pode acceder aos seus propios rexistros aínda que non lle permitas acceder a todos. É posible que o fabricante do dispositivo teña acceso a algúns rexistros ou á información do teu dispositivo."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Non amosar outra vez"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> quere mostrar fragmentos de aplicación de <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Editar"</string>
@@ -2292,7 +2291,6 @@
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Comprobar aplicacións activas"</string>
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Non se puido acceder á cámara do teléfono desde o teu dispositivo (<xliff:g id="DEVICE">%1$s</xliff:g>)"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Non se puido acceder á cámara da tableta desde o teu dispositivo (<xliff:g id="DEVICE">%1$s</xliff:g>)"</string>
- <!-- no translation found for vdm_secure_window (161700398158812314) -->
- <skip />
+ <string name="vdm_secure_window" msgid="161700398158812314">"Non se puido acceder a este contido durante a reprodución en tempo real. Téntao desde o teléfono."</string>
<string name="system_locale_title" msgid="711882686834677268">"Opción predeterminada do sistema"</string>
</resources>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index b75f731..3ec552a 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -608,7 +608,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"ફિંગરપ્રિન્ટ ઓપરેશન રદ કર્યું."</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"ફિંગરપ્રિન્ટ ચકાસવાની પ્રક્રિયા વપરાશકર્તાએ રદ કરી."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"ઘણા બધા પ્રયત્નો. પછીથી ફરી પ્રયાસ કરો."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"ઘણા વધુ પ્રયત્નો. ફિંગરપ્રિન્ટ સેન્સર અક્ષમ કરવામાં આવ્યું છે."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"ઘણા બધા પ્રયાસો. વિકલ્પ તરીકે સ્ક્રીન લૉકનો ઉપયોગ કરો."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"ફરી પ્રયાસ કરો."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"કોઈ ફિંગરપ્રિન્ટની નોંધણી કરવામાં આવી નથી."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"આ ડિવાઇસમાં કોઈ ફિંગરપ્રિન્ટ સેન્સર નથી."</string>
@@ -637,7 +637,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"રિપેર કરવાની સેવા આપતા પ્રદાતાની મુલાકાત લો."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"તમારા ચહેરાનું મૉડલ ન બનાવી શકાય. ફરી પ્રયાસ કરો."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"અતિશય પ્રકાશિત. થોડો હળવો પ્રકાશ અજમાવી જુઓ."</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"વધુ પ્રકાશિત લાઇટિંગ અજમાવો"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"ફોનને વધુ દૂર લઈ જાઓ"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"ફોનને વધુ નજીક લાવો"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"ફોનને વધુ ઊંચે લઈ જાઓ"</string>
@@ -1427,7 +1428,7 @@
<string name="ext_media_browse_action" msgid="344865351947079139">"અન્વેષણ કરો"</string>
<string name="ext_media_seamless_action" msgid="8837030226009268080">"આઉટપુટ સ્વિચ કરો"</string>
<string name="ext_media_missing_title" msgid="3209472091220515046">"<xliff:g id="NAME">%s</xliff:g> ખૂટે છે"</string>
- <string name="ext_media_missing_message" msgid="4408988706227922909">"ફરીથી ઉપકરણ દાખલ કરો"</string>
+ <string name="ext_media_missing_message" msgid="4408988706227922909">"ફરીથી ડિવાઇસ દાખલ કરો"</string>
<string name="ext_media_move_specific_title" msgid="8492118544775964250">"<xliff:g id="NAME">%s</xliff:g> ખસેડી રહ્યાં છીએ"</string>
<string name="ext_media_move_title" msgid="2682741525619033637">"ડેટાને ખસેડી રહ્યાં છીએ"</string>
<string name="ext_media_move_success_title" msgid="4901763082647316767">"કન્ટેન્ટ ટ્રાન્સફર કરવાનું પૂર્ણ થયું"</string>
@@ -1926,8 +1927,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"પ્રદેશ પસંદગી"</string>
<string name="search_language_hint" msgid="7004225294308793583">"ભાષાનું નામ ટાઇપ કરો"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"સૂચવેલી ભાષા"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"સૂચવેલા"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"બધી ભાષાઓ"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"તમામ પ્રદેશ"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"શોધ"</string>
@@ -2050,8 +2050,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g>ને ડિવાઇસનો બધો લૉગ ઍક્સેસ કરવાની મંજૂરી આપવી છે?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"એક-વખતના ઍક્સેસની મંજૂરી આપો"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"મંજૂરી આપશો નહીં"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"તમારા ડિવાઇસ પર થતી કામગીરીને ડિવાઇસ લૉગ રેકોર્ડ કરે છે. ઍપ આ લૉગનો ઉપયોગ સમસ્યાઓ શોધી તેનું નિરાકરણ કરવા માટે કરી શકે છે.\n\nઅમુક લૉગમાં સંવેદનશીલ માહિતી હોઈ શકે, આથી ડિવાઇસનો બધો લૉગ ઍક્સેસ કરવાની મંજૂરી માત્ર તમારી વિશ્વાસપાત્ર ઍપને જ આપો. \n\nજો તમે આ ઍપને ડિવાઇસનો બધો લૉગ ઍક્સેસ કરવાની મંજૂરી ન આપો, તો પણ તે તેના પોતાના લૉગ ઍક્સેસ કરી શકે છે. તમારા ડિવાઇસના નિર્માતા હજુ પણ કદાચ તમારા ડિવાઇસ પર અમુક લૉગ અથવા માહિતી ઍક્સેસ કરી શકે છે."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"ફરીથી બતાવશો નહીં"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g>એ <xliff:g id="APP_2">%2$s</xliff:g> સ્લાઇસ બતાવવા માગે છે"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"ફેરફાર કરો"</string>
@@ -2292,7 +2291,6 @@
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"સક્રિય ઍપ ચેક કરો"</string>
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"તમારા <xliff:g id="DEVICE">%1$s</xliff:g> પરથી ફોનના કૅમેરાનો ઍક્સેસ કરી શકતાં નથી"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"તમારા <xliff:g id="DEVICE">%1$s</xliff:g> પરથી ટૅબ્લેટના કૅમેરાનો ઍક્સેસ કરી શકતાં નથી"</string>
- <!-- no translation found for vdm_secure_window (161700398158812314) -->
- <skip />
+ <string name="vdm_secure_window" msgid="161700398158812314">"સ્ટ્રીમ કરતી વખતે આ ઍક્સેસ કરી શકાતું નથી. તેના બદલે તમારા ફોન પર પ્રયાસ કરો."</string>
<string name="system_locale_title" msgid="711882686834677268">"સિસ્ટમ ડિફૉલ્ટ"</string>
</resources>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 70058fa..fc8b10d 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -307,7 +307,7 @@
<string name="permgroupdesc_sms" msgid="5726462398070064542">"मैसेज (एसएमएस) भेजें और देखें"</string>
<string name="permgrouplab_storage" msgid="17339216290379241">"फ़ाइलें"</string>
<string name="permgroupdesc_storage" msgid="5378659041354582769">"अपने डिवाइस में मौजूद फ़ाइलों का ऐक्सेस दें"</string>
- <string name="permgrouplab_readMediaAural" msgid="1858331312624942053">"संगीत और ऑडियो के ऐक्सेस"</string>
+ <string name="permgrouplab_readMediaAural" msgid="1858331312624942053">"संगीत और ऑडियो"</string>
<string name="permgroupdesc_readMediaAural" msgid="7565467343667089595">"आपके डिवाइस पर संगीत और ऑडियो को ऐक्सेस करने की अनुमति"</string>
<string name="permgrouplab_readMediaVisual" msgid="4724874717811908660">"फ़ोटो और वीडियो के ऐक्सेस"</string>
<string name="permgroupdesc_readMediaVisual" msgid="4080463241903508688">"आपके डिवाइस पर फ़ोटो और वीडियो को ऐक्सेस करने की अनुमति"</string>
@@ -608,7 +608,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"फ़िंगरप्रिंट ऑपरेशन रोक दिया गया."</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"उपयोगकर्ता ने फिंगरप्रिंट की पुष्टि की कार्रवाई रद्द कर दी है."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"बहुत ज़्यादा प्रयास कर लिए गए हैं. बाद में फिर से प्रयास करें."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"बहुत ज़्यादा कोशिशें. फ़िंगरप्रिंट सेंसर अक्षम है."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"इससे ज़्यादा बार कोशिश नहीं की जा सकती. इसके बजाय, स्क्रीन लॉक का इस्तेमाल करें."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"फिर से कोशिश करें."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"कोई फ़िंगरप्रिंट रजिस्टर नहीं किया गया है."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"इस डिवाइस में फ़िंगरप्रिंट सेंसर नहीं है."</string>
@@ -637,7 +637,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"फ़िंगरप्रिंट सेंसर को रिपेयर करने की सेवा देने वाली कंपनी से संपर्क करें."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"चेहरे का माॅडल नहीं बन सका. फिर से कोशिश करें."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"बहुत रोशनी है. हल्की रोशनी आज़माएं."</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"बेहतर रोशनी में कोशिश करें"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"फ़ोन को दूर ले जाएं"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"फ़ोन को नज़दीक लाएं"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"फ़ोन को थोड़ा और ऊपर ले जाएं"</string>
@@ -1426,7 +1427,7 @@
<string name="ext_media_unmount_action" msgid="966992232088442745">"निकालें"</string>
<string name="ext_media_browse_action" msgid="344865351947079139">"एक्सप्लोर करें"</string>
<string name="ext_media_seamless_action" msgid="8837030226009268080">"आउटपुट बदलें"</string>
- <string name="ext_media_missing_title" msgid="3209472091220515046">"<xliff:g id="NAME">%s</xliff:g> गुम है"</string>
+ <string name="ext_media_missing_title" msgid="3209472091220515046">"<xliff:g id="NAME">%s</xliff:g> नहीं मिल रहा है"</string>
<string name="ext_media_missing_message" msgid="4408988706227922909">"डिवाइस को दोबारा लगाएं"</string>
<string name="ext_media_move_specific_title" msgid="8492118544775964250">"<xliff:g id="NAME">%s</xliff:g> को ले जाया जा रहा है"</string>
<string name="ext_media_move_title" msgid="2682741525619033637">"डेटा ले जाया जा रहा है"</string>
@@ -1856,8 +1857,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"आपके व्यवस्थापक ने अपडेट किया है"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"आपके व्यवस्थापक ने हटा दिया है"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ठीक है"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"बैटरी सेवर, गहरे रंग वाली थीम को चालू करता है. साथ ही, यह बैकग्राउंड की गतिविधि, कुछ विज़ुअल इफ़ेक्ट, कुछ खास सुविधाओं, और कुछ खास तरह के इंटरनेट कनेक्शन इस्तेमाल करने से डिवाइस को रोकता है या इन्हें बंद कर देता है."</string>
- <string name="battery_saver_description" msgid="8518809702138617167">"बैटरी सेवर, गहरे रंग वाली थीम को चालू करता है. साथ ही, यह बैकग्राउंड की गतिविधि, कुछ विज़ुअल इफ़ेक्ट, कुछ खास सुविधाओं, और कुछ खास तरह के इंटरनेट कनेक्शन इस्तेमाल करने से डिवाइस को रोकता है या इन्हें बंद कर देता है."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"बैटरी सेवर, गहरे रंग वाली थीम को चालू करता है. साथ ही, इस मोड में बैकग्राउंड की गतिविधि, कुछ विज़ुअल इफ़ेक्ट, और कुछ खास सुविधाएं कम या बंद हो जाती हैं. कुछ इंटरनेट कनेक्शन भी पूरी तरह काम नहीं करते."</string>
+ <string name="battery_saver_description" msgid="8518809702138617167">"बैटरी सेवर, गहरे रंग वाली थीम को चालू करता है. साथ ही, इस मोड में बैकग्राउंड की गतिविधि, कुछ विज़ुअल इफ़ेक्ट, और कुछ सुविधाएं सीमित या बंद हो जाती हैं. कुछ इंटरनेट कनेक्शन भी पूरी तरह काम नहीं करते."</string>
<string name="data_saver_description" msgid="4995164271550590517">"डेटा खर्च को कम करने के लिए, डेटा बचाने की सेटिंग कुछ ऐप्लिकेशन को बैकग्राउंड में डेटा भेजने या डेटा पाने से रोकती है. फ़िलहाल, जिस ऐप्लिकेशन का इस्तेमाल किया जा रहा है वह डेटा ऐक्सेस कर सकता है, लेकिन ऐसा कभी-कभी ही हो पाएगा. उदाहरण के लिए, इमेज तब तक दिखाई नहीं देंगी, जब तक उन पर टैप नहीं किया जाएगा."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"डेटा बचाने की सेटिंग चालू करें?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"चालू करें"</string>
@@ -1926,8 +1927,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"क्षेत्र प्राथमिकता"</string>
<string name="search_language_hint" msgid="7004225294308793583">"भाषा का नाम लिखें"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"दिए गए सुझाव"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"सुझाए गए देश/इलाके"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"सभी भाषाएं"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"सभी क्षेत्र"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"खोजें"</string>
@@ -2050,8 +2050,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"क्या <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> को डिवाइस लॉग का ऐक्सेस देना है?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"एक बार ऐक्सेस करने की अनुमति दें"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"अनुमति न दें"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"डिवाइस लॉग में, आपके डिवाइस पर की गई कार्रवाइयां रिकॉर्ड होती हैं. ऐप्लिकेशन, इन लॉग का इस्तेमाल गड़बड़ियां ढूंढने और उन्हें ठीक करने के लिए करते हैं.\n\nकुछ लॉग में संवेदनशील जानकारी हो सकती है. इसलिए, सिर्फ़ भरोसेमंद ऐप्लिकेशन को डिवाइस लॉग का ऐक्सेस दें. \n\nअगर इस ऐप्लिकेशन को डिवाइस के सभी लॉग का ऐक्सेस नहीं दिया जाता है, तब भी यह डिवाइस पर अपने लॉग को ऐक्सेस कर सकता है. डिवाइस को बनाने वाली कंपनी अब भी डिवाइस के कुछ लॉग या जानकारी को ऐक्सेस कर सकती है."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"फिर से न दिखाएं"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g>, <xliff:g id="APP_2">%2$s</xliff:g> के हिस्से (स्लाइस) दिखाना चाहता है"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"बदलाव करें"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 2e659e5..c4f6f48 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -609,7 +609,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"Radnja otiska prsta otkazana je."</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Radnju s otiskom prsta otkazao je korisnik."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"Previše pokušaja. Pokušajte ponovo kasnije."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Senzor otiska prsta onemogućen je zbog previše pokušaja."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Previše pokušaja. Umjesto toga upotrijebite zaključavanje zaslona."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Pokušajte ponovo."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nije registriran nijedan otisak prsta."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Ovaj uređaj nema senzor otiska prsta."</string>
@@ -638,7 +638,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Posjetite davatelja usluga popravaka."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"Izrada modela lica nije uspjela. Pokušajte ponovo."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Presvijetlo je. Pokušajte sa slabijim svjetlom."</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"Pokušajte s jačim osvjetljenjem"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"Udaljite telefon"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"Približite telefon"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"Pomaknite telefon prema gore"</string>
@@ -1927,8 +1928,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"Postavke regije"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Unesite naziv jezika"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"Predloženo"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Predloženo"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"Svi jezici"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"Sve regije"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"Pretraži"</string>
@@ -2051,8 +2051,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Želite li dopustiti aplikaciji <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> da pristupa svim zapisnicima uređaja?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"Omogući jednokratni pristup"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Nemoj dopustiti"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"U zapisnicima uređaja bilježi se što se događa na uređaju. Aplikacije mogu koristiti te zapisnike kako bi pronašle i riješile poteškoće.\n\nNeki zapisnici mogu sadržavati osjetljive podatke, pa pristup svim zapisnicima uređaja odobrite samo pouzdanim aplikacijama. \n\nAko ne dopustite ovoj aplikaciji da pristupa svim zapisnicima uređaja, ona i dalje može pristupati svojim zapisnicima. Proizvođač vašeg uređaja i dalje može pristupati nekim zapisnicima ili podacima na vašem uređaju."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Ne prikazuj ponovo"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> želi prikazivati isječke aplikacije <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Uredi"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index a300434..4aa2f7e 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -608,7 +608,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"Ujjlenyomattal kapcsolatos művelet megszakítva"</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Az ujjlenyomattal kapcsolatos műveletet a felhasználó megszakította."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"Túl sok próbálkozás. Próbálja újra később."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Túl sok próbálkozás. Ujjlenyomat-érzékelő letiltva."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Túl sok próbálkozás. Használja inkább a képernyőzárat."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Próbálkozzon újra."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nincsenek regisztrált ujjlenyomatok."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Ez az eszköz nem rendelkezik ujjlenyomat-érzékelővel."</string>
@@ -637,7 +637,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Keresse fel a szervizt."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"Nem lehet létrehozni az arcmodellt. Próbálja újra."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Túl világos. Próbálja kevésbé erős világítással."</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"Próbálja jobb megvilágítás mellett"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"Tartsa távolabb a telefont"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"Tartsa közelebb a telefont"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"Emelje magasabbra a telefont"</string>
@@ -1926,8 +1927,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"Régió beállítása"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Adja meg a nyelvet"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"Javasolt"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Javasolt"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"Minden nyelv"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"Minden régió"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"Keresés"</string>
@@ -2050,8 +2050,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Engedélyezi a(z) <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> számára, hogy hozzáférjen az összes eszköznaplóhoz?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"Egyszeri hozzáférés engedélyezése"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Tiltás"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"Az eszköznaplók rögzítik, hogy mi történik az eszközén. Az alkalmazások ezeket a naplókat használhatják a problémák megkeresésére és kijavítására.\n\nBizonyos naplók bizalmas adatokat is tartalmazhatnak, ezért csak olyan alkalmazások számára engedélyezze az összes eszköznaplóhoz való hozzáférést, amelyekben megbízik. \n\nHa nem engedélyezi ennek az alkalmazásnak, hogy hozzáférjen az összes eszköznaplójához, az app továbbra is hozzáférhet a saját naplóihoz. Előfordulhat, hogy az eszköz gyártója továbbra is hozzáfér az eszközön található bizonyos naplókhoz és adatokhoz."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Ne jelenjen meg újra"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"A(z) <xliff:g id="APP_0">%1$s</xliff:g> alkalmazás részleteket szeretne megjeleníteni a(z) <xliff:g id="APP_2">%2$s</xliff:g> alkalmazásból"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Szerkesztés"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index 5fcf8ab..5761e0f 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -608,7 +608,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"Իսկորոշումը մատնահետքի միջոցով չեղարկվեց:"</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Մատնահետքով նույնականացման գործողությունը չեղարկվել է օգտատիրոջ կողմից:"</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"Չափից շատ փորձ եք կատարել: Փորձեք նորից քիչ հետո:"</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Չափից շատ փորձ եք կատարել: Մատնահետքերի սկաներն անջատվել է:"</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Չափազանց շատ փորձեր են արվել։ Օգտագործեք էկրանի կողպումը։"</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Փորձեք նորից:"</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Գրանցված մատնահետք չկա:"</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Այս սարքը չունի մատնահետքերի սկաներ։"</string>
@@ -637,7 +637,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Այցելեք սպասարկման կենտրոն։"</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"Չհաջողվեց ստեղծել ձեր դեմքի մոդելը։ Նորից փորձեք։"</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Շատ լուսավոր է։ Փորձեք ավելի թեթև լուսավորություն։"</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"Ավելի պայծառ դարձրեք լուսավորությունը"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"Փոքր-ինչ հեռու պահեք հեռախոսը"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"Մոտեցրեք հեռախոսը"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"Բարձրացրեք հեռախոսը"</string>
@@ -1423,7 +1424,7 @@
<string name="ext_media_unmounting_notification_title" msgid="4147986383917892162">"<xliff:g id="NAME">%s</xliff:g> հիշասարքն անջատվում է"</string>
<string name="ext_media_unmounting_notification_message" msgid="5717036261538754203">"Չհեռացնեք սարքը"</string>
<string name="ext_media_init_action" msgid="2312974060585056709">"Կարգավորել"</string>
- <string name="ext_media_unmount_action" msgid="966992232088442745">"Անջատել"</string>
+ <string name="ext_media_unmount_action" msgid="966992232088442745">"Հանել"</string>
<string name="ext_media_browse_action" msgid="344865351947079139">"Ուսումնասիրել"</string>
<string name="ext_media_seamless_action" msgid="8837030226009268080">"Աուդիոելքի սարքի փոխարկում"</string>
<string name="ext_media_missing_title" msgid="3209472091220515046">"<xliff:g id="NAME">%s</xliff:g>-ը տեղադրված չէ"</string>
@@ -1926,8 +1927,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"Նախընտրելի տարածաշրջան"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Մուտքագրեք լեզուն"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"Առաջարկվող"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Առաջարկվող"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"Բոլոր լեզուները"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"Բոլոր տարածաշրջանները"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"Որոնում"</string>
@@ -2050,8 +2050,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Հասանելի դարձնե՞լ <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> հավելվածին սարքի բոլոր մատյանները"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"Թույլատրել մեկանգամյա մուտքը"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Չթույլատրել"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"Այն, ինչ տեղի է ունենում ձեր սարքում, գրանցվում է սարքի մատյաններում։ Հավելվածները կարող են դրանք օգտագործել անսարքությունները հայտնաբերելու և վերացնելու նպատակով։\n\nՔանի որ որոշ մատյաններ անձնական տեղեկություններ են պարունակում, խորհուրդ ենք տալիս հասանելի դարձնել ձեր սարքի բոլոր մատյանները միայն այն հավելվածներին, որոնց վստահում եք։ \n\nԵթե այս հավելվածին նման թույլտվություն չեք տվել, դրան նախկինի պես հասանելի կլինեն իր մատյանները։ Հնարավոր է՝ ձեր սարքի արտադրողին ևս հասանելի լինեն սարքի որոշ մատյաններ և տեղեկություններ։"</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Այլևս ցույց չտալ"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> հավելվածն ուզում է ցուցադրել հատվածներ <xliff:g id="APP_2">%2$s</xliff:g> հավելվածից"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Փոփոխել"</string>
@@ -2292,7 +2291,6 @@
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Ստուգել ակտիվ հավելվածները"</string>
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Հնարավոր չէ օգտագործել հեռախոսի տեսախցիկը ձեր <xliff:g id="DEVICE">%1$s</xliff:g> սարքից"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Հնարավոր չէ օգտագործել պլանշետի տեսախցիկը ձեր <xliff:g id="DEVICE">%1$s</xliff:g> սարքից"</string>
- <!-- no translation found for vdm_secure_window (161700398158812314) -->
- <skip />
+ <string name="vdm_secure_window" msgid="161700398158812314">"Այս բովանդակությունը հասանելի չէ հեռարձակման ընթացքում։ Օգտագործեք ձեր հեռախոսը։"</string>
<string name="system_locale_title" msgid="711882686834677268">"Կանխադրված"</string>
</resources>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index de8b8dc..9e78443 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -608,7 +608,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"Operasi sidik jari dibatalkan."</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Operasi sidik jari dibatalkan oleh pengguna."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"Terlalu banyak upaya. Coba lagi nanti."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Terlalu sering dicoba. Sensor sidik jari dinonaktifkan."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Terlalu banyak upaya gagal. Gunakan kunci layar."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Coba lagi."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Tidak ada sidik jari yang terdaftar."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Perangkat ini tidak memiliki sensor sidik jari."</string>
@@ -637,7 +637,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Kunjungi penyedia reparasi."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"Tidak dapat membuat model wajah Anda. Coba lagi."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Terlalu terang. Coba cahaya yang lebih lembut."</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"Coba pencahayaan yang lebih cerah"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"Jauhkan ponsel"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"Dekatkan ponsel"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"Gerakkan ponsel ke atas"</string>
@@ -1926,8 +1927,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"Preferensi wilayah"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Ketik nama bahasa"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"Disarankan"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Disarankan"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"Semua bahasa"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"Semua wilayah"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"Telusuri"</string>
@@ -2050,8 +2050,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Izinkan <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> mengakses semua log perangkat?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"Izinkan akses satu kali"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Jangan izinkan"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"Log perangkat merekam hal-hal yang terjadi di perangkat Anda. Aplikasi dapat menggunakan log ini untuk menemukan dan memperbaiki masalah.\n\nBeberapa log mungkin berisi info sensitif, jadi hanya izinkan aplikasi yang Anda percayai untuk mengakses semua log perangkat. \n\nJika Anda tidak mengizinkan aplikasi ini mengakses semua log perangkat, aplikasi masih dapat mengakses log-nya sendiri. Produsen perangkat masih dapat mengakses beberapa log atau info di perangkat Anda."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Jangan tampilkan lagi"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> ingin menampilkan potongan <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Edit"</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 8265cf2..c1482d6 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -608,7 +608,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"Hætt við fingrafarsaðgerð."</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Notandi hætti við að nota fingrafar."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"Of margar tilraunir. Reyndu aftur síðar."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Of margar tilraunir. Fingrafaralesari gerður óvirkur."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Of margar tilraunir. Notaðu skjálás í staðinn."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Reyndu aftur."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Engin fingraför hafa verið skráð."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Þetta tæki er ekki með fingrafaralesara."</string>
@@ -637,7 +637,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Þú verður að fara á verkstæði."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"Ekki tekst að búa til andlitslíkan. Reyndu aftur."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Of bjart. Prófaðu mýkri lýsingu."</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"Prófaðu sterkari lýsingu"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"Færðu símann lengra frá"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"Færðu símann nær"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"Færðu símann hærra"</string>
@@ -1926,8 +1927,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"Svæðisval"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Sláðu inn heiti tungumáls"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"Tillögur"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Tillögur"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"Öll tungumál"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"Öll svæði"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"Leita"</string>
@@ -2050,8 +2050,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Veita <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> aðgang að öllum annálum í tækinu?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"Leyfa aðgang í eitt skipti"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Ekki leyfa"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"Annálar tækisins skrá það sem gerist í tækinu. Forrit geta notað þessa annála til að finna og lagfæra vandamál.\n\nTilteknir annálar innihalda viðkvæmar upplýsingar og því skaltu einungis veita forritum sem þú treystir aðgang að öllum annálum tækisins. \n\nEf þú veitir þessu forriti ekki aðgang að öllum annálum tækisins hefur það áfram aðgang að eigin annálum. Framleiðandi tækisins getur þó hugsanlega opnað tiltekna annála eða upplýsingar í tækinu."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Ekki sýna aftur"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> vill sýna sneiðar úr <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Breyta"</string>
@@ -2292,7 +2291,6 @@
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Skoða virk forrit"</string>
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Ekki er hægt að opna myndavél símans úr <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Ekki er hægt að opna myndavél spjaldtölvunnar úr <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
- <!-- no translation found for vdm_secure_window (161700398158812314) -->
- <skip />
+ <string name="vdm_secure_window" msgid="161700398158812314">"Ekki er hægt að opna þetta á meðan streymi stendur yfir. Prófaðu það í símanum í staðinn."</string>
<string name="system_locale_title" msgid="711882686834677268">"Sjálfgildi kerfis"</string>
</resources>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index e0c84a2..c462386 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -51,6 +51,7 @@
<string name="needPuk2" msgid="7032612093451537186">"Digita il PUK2 per sbloccare la SIM."</string>
<string name="enablePin" msgid="2543771964137091212">"Operazione non riuscita; attiva blocco SIM/RUIM."</string>
<plurals name="pinpuk_attempts" formatted="false" msgid="1619867269012213584">
+ <item quantity="many">You have <xliff:g id="NUMBER_1">%d</xliff:g> remaining attempts before SIM is locked.</item>
<item quantity="other">Hai ancora <xliff:g id="NUMBER_1">%d</xliff:g> tentativi a disposizione prima che la SIM venga bloccata.</item>
<item quantity="one">Hai ancora <xliff:g id="NUMBER_0">%d</xliff:g> tentativo a disposizione prima che la SIM venga bloccata.</item>
</plurals>
@@ -180,7 +181,7 @@
<string name="low_memory" product="watch" msgid="3479447988234030194">"La memoria dell\'orologio è piena. Elimina alcuni file per liberare spazio."</string>
<string name="low_memory" product="tv" msgid="6663680413790323318">"Lo spazio di archiviazione del dispositivo Android TV è pieno. Elimina alcuni file per liberare spazio."</string>
<string name="low_memory" product="default" msgid="2539532364144025569">"Spazio di archiviazione del telefono esaurito. Elimina alcuni file per liberare spazio."</string>
- <string name="ssl_ca_cert_warning" msgid="7233573909730048571">"{count,plural, =1{Autorità di certificazione installata}other{Autorità di certificazione installate}}"</string>
+ <string name="ssl_ca_cert_warning" msgid="7233573909730048571">"{count,plural, =1{Autorità di certificazione installata}many{Autorità di certificazione installate}other{Autorità di certificazione installate}}"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4961102218216815242">"Da una terza parte sconosciuta"</string>
<string name="ssl_ca_cert_noti_by_administrator" msgid="4564941950768783879">"Dall\'amministratore del tuo profilo di lavoro"</string>
<string name="ssl_ca_cert_noti_managed" msgid="217337232273211674">"Da <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
@@ -254,7 +255,7 @@
<string name="bugreport_option_interactive_summary" msgid="8493795476325339542">"Utilizza questa opzione nella maggior parte dei casi. Ti consente di monitorare l\'avanzamento della segnalazione, di inserire maggiori dettagli relativi al problema e di acquisire screenshot. Potrebbero essere omesse alcune sezioni meno utilizzate il cui inserimento nella segnalazione richiede molto tempo."</string>
<string name="bugreport_option_full_title" msgid="7681035745950045690">"Report completo"</string>
<string name="bugreport_option_full_summary" msgid="1975130009258435885">"Utilizza questa opzione per ridurre al minimo l\'interferenza di sistema quando il dispositivo non risponde, è troppo lento oppure quando ti servono tutte le sezioni della segnalazione. Non puoi inserire altri dettagli o acquisire altri screenshot."</string>
- <string name="bugreport_countdown" msgid="6418620521782120755">"{count,plural, =1{Lo screenshot per la segnalazione di bug verrà acquisito tra # secondo.}other{Lo screenshot per la segnalazione di bug verrà acquisito tra # secondi.}}"</string>
+ <string name="bugreport_countdown" msgid="6418620521782120755">"{count,plural, =1{Lo screenshot per la segnalazione di bug verrà acquisito tra # secondo.}many{Lo screenshot per la segnalazione di bug verrà acquisito tra # secondi.}other{Lo screenshot per la segnalazione di bug verrà acquisito tra # secondi.}}"</string>
<string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Screenshot con segnalazione di bug effettuato correttamente"</string>
<string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Impossibile acquisire screenshot con segnalazione di bug"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Modalità silenziosa"</string>
@@ -608,7 +609,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"Operazione associata all\'impronta annullata."</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Operazione di autenticazione dell\'impronta annullata dall\'utente."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"Troppi tentativi. Riprova più tardi."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Troppi tentativi. Sensore di impronte disattivato."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Troppi tentativi. Usa il blocco schermo."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Riprova."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nessuna impronta digitale registrata."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Questo dispositivo non dispone di sensore di impronte."</string>
@@ -637,7 +638,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Contatta un fornitore di servizi di riparazione."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"Impossibile creare il modello del volto. Riprova."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Troppa luce. Prova con una luce più soft."</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"Prova con più luce"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"Allontana il telefono"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"Avvicina il telefono"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"Sposta il telefono più in alto"</string>
@@ -1087,7 +1089,7 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="4312979647356179250">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> vuole attivare la funzione Esplora al tocco. Quando la funzione Esplora al tocco è attiva, puoi ascoltare o visualizzare le descrizioni di ciò che stai toccando oppure interagire con il telefono tramite gesti."</string>
<string name="oneMonthDurationPast" msgid="4538030857114635777">"1 mese fa"</string>
<string name="beforeOneMonthDurationPast" msgid="8315149541372065392">"Oltre 1 mese fa"</string>
- <string name="last_num_days" msgid="2393660431490280537">"{count,plural, =1{Ultimo giorno}other{Ultimi # giorni}}"</string>
+ <string name="last_num_days" msgid="2393660431490280537">"{count,plural, =1{Ultimo giorno}many{Ultimi # giorni}other{Ultimi # giorni}}"</string>
<string name="last_month" msgid="1528906781083518683">"Ultimo mese"</string>
<string name="older" msgid="1645159827884647400">"Precedente"</string>
<string name="preposition_for_date" msgid="2780767868832729599">"<xliff:g id="DATE">%s</xliff:g>"</string>
@@ -1114,14 +1116,14 @@
<string name="duration_hours_shortest_future" msgid="2979276794547981674">"tra <xliff:g id="COUNT">%d</xliff:g> h"</string>
<string name="duration_days_shortest_future" msgid="3392722163935571543">"tra <xliff:g id="COUNT">%d</xliff:g> g"</string>
<string name="duration_years_shortest_future" msgid="5537464088352970388">"tra <xliff:g id="COUNT">%d</xliff:g> a"</string>
- <string name="duration_minutes_relative" msgid="8620337701051015593">"{count,plural, =1{# minuto fa}other{# minuti fa}}"</string>
- <string name="duration_hours_relative" msgid="4836449961693180253">"{count,plural, =1{# ora fa}other{# ore fa}}"</string>
- <string name="duration_days_relative" msgid="621965767567258302">"{count,plural, =1{# giorno fa}other{# giorni fa}}"</string>
- <string name="duration_years_relative" msgid="8731202348869424370">"{count,plural, =1{# anno fa}other{# anni fa}}"</string>
- <string name="duration_minutes_relative_future" msgid="5259574171747708115">"{count,plural, =1{# minuto}other{# minuti}}"</string>
- <string name="duration_hours_relative_future" msgid="6670440478481140565">"{count,plural, =1{# ora}other{# ore}}"</string>
- <string name="duration_days_relative_future" msgid="8870658635774250746">"{count,plural, =1{# giorno}other{# giorni}}"</string>
- <string name="duration_years_relative_future" msgid="8855853883925918380">"{count,plural, =1{# anno}other{# anni}}"</string>
+ <string name="duration_minutes_relative" msgid="8620337701051015593">"{count,plural, =1{# minuto fa}many{# minuti fa}other{# minuti fa}}"</string>
+ <string name="duration_hours_relative" msgid="4836449961693180253">"{count,plural, =1{# ora fa}many{# ore fa}other{# ore fa}}"</string>
+ <string name="duration_days_relative" msgid="621965767567258302">"{count,plural, =1{# giorno fa}many{# giorni fa}other{# giorni fa}}"</string>
+ <string name="duration_years_relative" msgid="8731202348869424370">"{count,plural, =1{# anno fa}many{# anni fa}other{# anni fa}}"</string>
+ <string name="duration_minutes_relative_future" msgid="5259574171747708115">"{count,plural, =1{# minuto}many{# minuti}other{# minuti}}"</string>
+ <string name="duration_hours_relative_future" msgid="6670440478481140565">"{count,plural, =1{# ora}many{# ore}other{# ore}}"</string>
+ <string name="duration_days_relative_future" msgid="8870658635774250746">"{count,plural, =1{# giorno}many{# giorni}other{# giorni}}"</string>
+ <string name="duration_years_relative_future" msgid="8855853883925918380">"{count,plural, =1{# anno}many{# anni}other{# anni}}"</string>
<string name="VideoView_error_title" msgid="5750686717225068016">"Problemi video"</string>
<string name="VideoView_error_text_invalid_progressive_playback" msgid="3782449246085134720">"Questo video non è valido per lo streaming su questo dispositivo."</string>
<string name="VideoView_error_text_unknown" msgid="7658683339707607138">"Impossibile riprodurre il video."</string>
@@ -1508,7 +1510,7 @@
<string name="skip_button_label" msgid="3566599811326688389">"Salta"</string>
<string name="no_matches" msgid="6472699895759164599">"Nessuna corrispondenza"</string>
<string name="find_on_page" msgid="5400537367077438198">"Trova nella pagina"</string>
- <string name="matches_found" msgid="2296462299979507689">"{count,plural, =1{# corrispondenza}other{# di {total}}}"</string>
+ <string name="matches_found" msgid="2296462299979507689">"{count,plural, =1{# corrispondenza}many{# di {total}}other{# di {total}}}"</string>
<string name="action_mode_done" msgid="2536182504764803222">"Fine"</string>
<string name="progress_erasing" msgid="6891435992721028004">"Cancellazione archivio condiviso…"</string>
<string name="share" msgid="4157615043345227321">"Condividi"</string>
@@ -1861,14 +1863,14 @@
<string name="data_saver_description" msgid="4995164271550590517">"Per contribuire a ridurre l\'utilizzo dei dati, la funzionalità Risparmio dati impedisce ad alcune app di inviare o ricevere dati in background. Un\'app in uso può accedere ai dati, ma potrebbe farlo con meno frequenza. Per esempio, è possibile che le immagini non vengano visualizzate finché non le tocchi."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Attivare Risparmio dati?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Attiva"</string>
- <string name="zen_mode_duration_minutes_summary" msgid="4555514757230849789">"{count,plural, =1{Per un minuto (fino alle ore {formattedTime})}other{Per # minuti (fino alle ore {formattedTime})}}"</string>
- <string name="zen_mode_duration_minutes_summary_short" msgid="1187553788355486950">"{count,plural, =1{Per 1 min (fino alle ore {formattedTime})}other{Per # min (fino alle ore {formattedTime})}}"</string>
- <string name="zen_mode_duration_hours_summary" msgid="3866333100793277211">"{count,plural, =1{Per 1 ora (fino alle ore {formattedTime})}other{Per # ore (fino alle ore {formattedTime})}}"</string>
- <string name="zen_mode_duration_hours_summary_short" msgid="687919813833347945">"{count,plural, =1{Per 1 h (fino alle ore {formattedTime})}other{Per # h (fino alle ore {formattedTime})}}"</string>
- <string name="zen_mode_duration_minutes" msgid="2340007982276569054">"{count,plural, =1{Per un minuto}other{Per # minuti}}"</string>
- <string name="zen_mode_duration_minutes_short" msgid="2435756450204526554">"{count,plural, =1{Per 1 min}other{Per # min}}"</string>
- <string name="zen_mode_duration_hours" msgid="7841806065034711849">"{count,plural, =1{Per 1 ora}other{Per # ore}}"</string>
- <string name="zen_mode_duration_hours_short" msgid="3666949653933099065">"{count,plural, =1{Per 1 h}other{Per # h}}"</string>
+ <string name="zen_mode_duration_minutes_summary" msgid="4555514757230849789">"{count,plural, =1{Per un minuto (fino alle ore {formattedTime})}many{Per # minuti (fino alle ore {formattedTime})}other{Per # minuti (fino alle ore {formattedTime})}}"</string>
+ <string name="zen_mode_duration_minutes_summary_short" msgid="1187553788355486950">"{count,plural, =1{Per 1 min (fino alle ore {formattedTime})}many{Per # min (fino alle ore {formattedTime})}other{Per # min (fino alle ore {formattedTime})}}"</string>
+ <string name="zen_mode_duration_hours_summary" msgid="3866333100793277211">"{count,plural, =1{Per 1 ora (fino alle ore {formattedTime})}many{Per # ore (fino alle ore {formattedTime})}other{Per # ore (fino alle ore {formattedTime})}}"</string>
+ <string name="zen_mode_duration_hours_summary_short" msgid="687919813833347945">"{count,plural, =1{Per 1 h (fino alle ore {formattedTime})}many{Per # h (fino alle ore {formattedTime})}other{Per # h (fino alle ore {formattedTime})}}"</string>
+ <string name="zen_mode_duration_minutes" msgid="2340007982276569054">"{count,plural, =1{Per un minuto}many{Per # minuti}other{Per # minuti}}"</string>
+ <string name="zen_mode_duration_minutes_short" msgid="2435756450204526554">"{count,plural, =1{Per 1 min}many{Per # min}other{Per # min}}"</string>
+ <string name="zen_mode_duration_hours" msgid="7841806065034711849">"{count,plural, =1{Per 1 ora}many{Per # ore}other{Per # ore}}"</string>
+ <string name="zen_mode_duration_hours_short" msgid="3666949653933099065">"{count,plural, =1{Per 1 h}many{Per # h}other{Per # h}}"</string>
<string name="zen_mode_until_next_day" msgid="1403042784161725038">"Fino a: <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
<string name="zen_mode_until" msgid="2250286190237669079">"Fino a <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
<string name="zen_mode_alarm" msgid="7046911727540499275">"Fino a <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (prossima sveglia)"</string>
@@ -1926,8 +1928,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"Regione preferita"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Digita nome lingua"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"Suggerite"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Suggerite"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"Tutte le lingue"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"Tutte le regioni"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"Cerca"</string>
@@ -2000,7 +2001,7 @@
<string name="autofill_save_accessibility_title" msgid="1523225776218450005">"Salva per Compilazione automatica"</string>
<string name="autofill_error_cannot_autofill" msgid="6528827648643138596">"Impossibile compilare automaticamente i contenuti"</string>
<string name="autofill_picker_no_suggestions" msgid="1076022650427481509">"Nessun suggerimento di Compilazione automatica"</string>
- <string name="autofill_picker_some_suggestions" msgid="5560549696296202701">"{count,plural, =1{Un suggerimento di compilazione automatica}other{# suggerimenti di compilazione automatica}}"</string>
+ <string name="autofill_picker_some_suggestions" msgid="5560549696296202701">"{count,plural, =1{Un suggerimento di compilazione automatica}many{# suggerimenti di compilazione automatica}other{# suggerimenti di compilazione automatica}}"</string>
<string name="autofill_save_title" msgid="7719802414283739775">"Vuoi salvare su "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"?"</string>
<string name="autofill_save_title_with_type" msgid="3002460014579799605">"Vuoi salvare la <xliff:g id="TYPE">%1$s</xliff:g> su "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"?"</string>
<string name="autofill_save_title_with_2types" msgid="3783270967447869241">"Vuoi salvare <xliff:g id="TYPE_0">%1$s</xliff:g> e <xliff:g id="TYPE_1">%2$s</xliff:g> su "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"?"</string>
@@ -2050,8 +2051,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Consentire all\'app <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> di accedere a tutti i log del dispositivo?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"Consenti accesso una tantum"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Non consentire"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"I log del dispositivo registrano tutto ciò che succede sul tuo dispositivo. Le app possono usare questi log per individuare problemi e correggerli.\n\nAlcuni log potrebbero contenere informazioni sensibili, quindi concedi l\'accesso a tutti i log del dispositivo soltanto alle app attendibili. \n\nSe le neghi l\'accesso a tutti i log del dispositivo, questa app può comunque accedere ai propri log. Il produttore del tuo dispositivo potrebbe essere comunque in grado di accedere ad alcuni log o informazioni sul dispositivo."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Non mostrare più"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"L\'app <xliff:g id="APP_0">%1$s</xliff:g> vuole mostrare porzioni dell\'app <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Modifica"</string>
@@ -2111,7 +2111,7 @@
<string name="mime_type_presentation_ext" msgid="8761049335564371468">"Presentazione <xliff:g id="EXTENSION">%1$s</xliff:g>"</string>
<string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"Il Bluetooth rimane attivo durante l\'uso della modalità aereo"</string>
<string name="car_loading_profile" msgid="8219978381196748070">"Caricamento"</string>
- <string name="file_count" msgid="3220018595056126969">"{count,plural, =1{{file_name} + # file}other{{file_name} + # file}}"</string>
+ <string name="file_count" msgid="3220018595056126969">"{count,plural, =1{{file_name} + # file}many{{file_name} + # file}other{{file_name} + # file}}"</string>
<string name="chooser_no_direct_share_targets" msgid="1511722103987329028">"Nessuna persona consigliata per la condivisione"</string>
<string name="chooser_all_apps_button_label" msgid="3230427756238666328">"Elenco di app"</string>
<string name="usb_device_resolve_prompt_warn" msgid="325871329788064199">"A questa app non è stata concessa l\'autorizzazione di registrazione, ma l\'app potrebbe acquisire l\'audio tramite questo dispositivo USB."</string>
@@ -2292,7 +2292,6 @@
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Verifica le app attive"</string>
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Impossibile accedere alla fotocamera del telefono dal tuo <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Impossibile accedere alla fotocamera del tablet dal tuo <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
- <!-- no translation found for vdm_secure_window (161700398158812314) -->
- <skip />
+ <string name="vdm_secure_window" msgid="161700398158812314">"Impossibile accedere a questi contenuti durante lo streaming. Prova a usare il telefono."</string>
<string name="system_locale_title" msgid="711882686834677268">"Predefinita di sistema"</string>
</resources>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 2fef45f..891ef6c 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -610,7 +610,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"פעולת טביעת האצבע בוטלה."</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"פעולת טביעת האצבע בוטלה על ידי המשתמש."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"יותר מדי ניסיונות. יש לנסות שוב מאוחר יותר."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"יותר מדי ניסיונות. חיישן טביעות האצבע הושבת."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"בוצעו יותר מדי ניסיונות. יש להשתמש בנעילת המסך במקום זאת."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"כדאי לנסות שוב."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"לא נסרקו טביעות אצבע."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"במכשיר הזה אין חיישן טביעות אצבע."</string>
@@ -639,7 +639,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"צריך ליצור קשר עם ספק תיקונים."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"לא ניתן ליצור את התבנית לזיהוי הפנים. יש לנסות שוב."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"בהירה מדי. צריך תאורה עדינה יותר."</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"כדאי לנסות בתאורה חזקה יותר"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"צריך להרחיק את הטלפון"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"צריך לקרב את הטלפון"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"צריך להגביה את הטלפון"</string>
@@ -1928,8 +1929,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"העדפת אזור"</string>
<string name="search_language_hint" msgid="7004225294308793583">"יש להקליד את שם השפה"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"הצעות"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"הצעות"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"כל השפות"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"כל האזורים"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"חיפוש"</string>
@@ -2052,8 +2052,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"לתת לאפליקציה <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> הרשאת גישה לכל יומני המכשיר?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"הרשאת גישה חד-פעמית"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"אין אישור"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"ביומני המכשיר מתועדת הפעילות במכשיר. האפליקציות יכולות להשתמש ביומנים האלה כדי למצוא בעיות ולפתור אותן.\n\nהמידע בחלק מהיומנים יכול להיות רגיש, לכן יש לתת הרשאת גישה לכל יומני המכשיר רק לאפליקציות מהימנות. \n\nגם אם האפליקציה הזו לא תקבל הרשאת גישה לכל יומני המכשיר, היא תוכל לגשת ליומנים שלה. יכול להיות שליצרן המכשיר עדיין תהיה גישה לחלק מהיומנים או למידע במכשיר שלך."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"אין להציג שוב"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> רוצה להציג חלקים מ-<xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"עריכה"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index e57b0d5..e37528a 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -608,7 +608,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"指紋の操作をキャンセルしました。"</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"指紋の操作がユーザーによりキャンセルされました。"</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"所定の回数以上間違えました。しばらくしてからもう一度お試しください。"</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"試行回数が上限を超えました。指紋認証センサーを無効にしました。"</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"試行回数が上限を超えました。代わりに画面ロックを使用してください。"</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"もう一度お試しください。"</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"指紋が登録されていません。"</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"このデバイスには指紋認証センサーがありません。"</string>
@@ -637,7 +637,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"修理業者に調整を依頼してください。"</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"顔モデルを作成できません。もう一度お試しください。"</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"明るすぎます。もっと暗い場所でお試しください。"</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"もっと明るい場所でお試しください"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"スマートフォンをもっと離してください"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"スマートフォンをもっと近づけてください"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"スマートフォンをもっと上げてください"</string>
@@ -1926,8 +1927,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"地域設定"</string>
<string name="search_language_hint" msgid="7004225294308793583">"言語名を入力"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"言語の候補"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"候補"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"すべての言語"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"すべての地域"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"検索"</string>
@@ -2050,8 +2050,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> にすべてのデバイスログへのアクセスを許可しますか?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"1 回限りのアクセスを許可"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"許可しない"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"デバイスのログに、このデバイスで発生したことが記録されます。アプリは問題を検出、修正するためにこれらのログを使用することができます。\n\nログによっては機密性の高い情報が含まれている可能性があるため、すべてのデバイスログへのアクセスは信頼できるアプリにのみ許可してください。\n\nすべてのデバイスログへのアクセスを許可しなかった場合も、このアプリはアプリ独自のログにアクセスできます。また、デバイスのメーカーもデバイスの一部のログや情報にアクセスできる可能性があります。"</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"次回から表示しない"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"「<xliff:g id="APP_0">%1$s</xliff:g>」が「<xliff:g id="APP_2">%2$s</xliff:g>」のスライスの表示をリクエストしています"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"編集"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 059ab27..a1140c1 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -608,7 +608,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"თითის ანაბეჭდის აღების ოპერაცია გაუქმდა."</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"თითის ანაბეჭდის ოპერაცია გააუქმა მომხმარებელმა."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"ძალიან ბევრი მცდელობა იყო. სცადეთ მოგვიანებით."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"დაფიქსირდა მეტისმეტად ბევრი მცდელობა. თითის ანაბეჭდის სენსორი გათიშულია."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"მეტისმეტად ბევრი მცდელობა იყო. სანაცვლოდ გამოიყენეთ ეკრანის დაბლოკვა."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"ხელახლა სცადეთ"</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"თითის ანაბეჭდები რეგისტრირებული არ არის."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ამ მოწყობილობას არ აქვს თითის ანაბეჭდის სენსორი."</string>
@@ -637,7 +637,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"ეწვიეთ შეკეთების სერვისის პროვაიდერს."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"თქვენი სახის მოდელი ვერ იქმნება. ცადეთ ხელახლა."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"მეტისმეტად ნათელია. ცადეთ უფრო სუსტი განათება."</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"ცადეთ უფრო ძლიერი განათება"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"გაწიეთ ტელეფონი უფრო შორს"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"მიიტანეთ ტელეფონი უფრო ახლოს"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"აწიეთ ტელეფონი ზემოთ"</string>
@@ -1926,8 +1927,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"რეგიონის პარამეტრები"</string>
<string name="search_language_hint" msgid="7004225294308793583">"აკრიფეთ ენის სახელი"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"რეკომენდებული"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"რეკომენდებული"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"ყველა ენა"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"ყველა რეგიონი"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"ძიება"</string>
@@ -2050,8 +2050,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"გსურთ <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g>-ს მიანიჭოთ მოწყობილობის ყველა ჟურნალზე წვდომა?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"ერთჯერადი წვდომის დაშვება"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"არ დაიშვას"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"მოწყობილობის ჟურნალში იწერება, რა ხდება ამ მოწყობილობაზე. აპებს შეუძლია ამ ჟურნალების გამოყენება პრობლემების აღმოსაჩენად და მოსაგვარებლად.\n\nზოგი ჟურნალი შეიძლება სენსიტიური ინფორმაციის მატარებელი იყოს, ამიტომაც მოწყობილობის ყველა ჟურნალზე წვდომა მხოლოდ სანდო აპებს მიანიჭეთ. \n\nთუ ამ აპს მოწყობილობის ყველა ჟურნალზე წვდომას არ მიანიჭებთ, მას მაინც ექნება წვდომა თქვენს ჟურნალებზე. თქვენი მოწყობილობის მწარმოებელს მაინც შეეძლება თქვენი მოწყობილობის ზოგიერთ ჟურნალსა თუ ინფორმაციაზე წვდომა."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"აღარ გამოჩნდეს"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g>-ს სურს, გაჩვენოთ <xliff:g id="APP_2">%2$s</xliff:g>-ის ფრაგმენტები"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"რედაქტირება"</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 8a4c4ba..6b4f741 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -608,7 +608,8 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"Саусақ ізі операциясынан бас тартылған."</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Пайдаланушы саусақ ізі операциясынан бас тартты."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"Талпыныстар тым көп. Кейінірек қайталап көріңіз."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Тым көп әрекет жасалды. Саусақ ізін оқу сканері өшірілді."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Әрекетті қайталаңыз."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Саусақ іздері тіркелмеген."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Бұл құрылғыда саусақ ізін оқу сканері жоқ."</string>
@@ -637,7 +638,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Жөндеу қызметіне барыңыз."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"Бет үлгісі жасалмады. Қайталап көріңіз."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Тым ашық. Күңгірттеу жарық керек."</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"Жарық деңгейін арттырыңыз."</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"Телефонды алшақ ұстаңыз."</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"Телефонды жақынырақ ұстаңыз."</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"Телефонды жоғарырақ ұстаңыз."</string>
@@ -1926,8 +1928,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"Аймақ параметрі"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Тіл атауын теріңіз"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"Ұсынылған"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Ұсынылатын аймақтар"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"Барлық тілдер"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"Барлық аймақтар"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"Іздеу"</string>
@@ -2050,8 +2051,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> қолданбасына барлық құрылғының журналын пайдалануға рұқсат берілсін бе?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"Бір реттік пайдалану рұқсатын беру"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Рұқсат бермеу"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"Журналдарға құрылғыда не болып жатқаны жазылады. Қолданбалар осы журналдарды қате тауып, түзету үшін пайдаланады.\n\nКейбір журналдарда құпия ақпарат болуы мүмкін. Сондықтан барлық құрылғының журналын пайдалану рұқсаты тек сенімді қолданбаларға берілуі керек. \n\nБұл қолданбаға барлық құрылғының журналын пайдалануға рұқсат бермесеңіз де, ол өзінің журналдарын пайдалана береді. Құрылғы өндірушісі де құрылғыдағы кейбір журналдарды немесе ақпаратты пайдалануы мүмкін."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Қайта көрсетілмесін"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> қолданбасы <xliff:g id="APP_2">%2$s</xliff:g> қолданбасының үзінділерін көрсеткісі келеді"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Өзгерту"</string>
@@ -2292,7 +2292,6 @@
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Белсенді қолданбаларды тексеру"</string>
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"<xliff:g id="DEVICE">%1$s</xliff:g> құрылғысынан телефон камерасын пайдалану мүмкін емес."</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"<xliff:g id="DEVICE">%1$s</xliff:g> құрылғысынан планшет камерасын пайдалану мүмкін емес."</string>
- <!-- no translation found for vdm_secure_window (161700398158812314) -->
- <skip />
+ <string name="vdm_secure_window" msgid="161700398158812314">"Трансляция кезінде мазмұнды көру мүмкін емес. Оның орнына телефоннан көріңіз."</string>
<string name="system_locale_title" msgid="711882686834677268">"Жүйенің әдепкі параметрі"</string>
</resources>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 7edf42d..b0d4563 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -608,7 +608,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"បានបោះបង់ប្រតិបត្តិការស្នាមម្រាមដៃ។"</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"ប្រតិបត្តិការស្នាមម្រាមដៃត្រូវបានបោះបង់ដោយអ្នកប្រើប្រាស់។"</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"ព្យាយាមចូលច្រើនពេកហើយ។ សូមព្យាយាមម្តងទៀតពេលក្រោយ។"</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"ព្យាយាមចូលច្រើនដងពេកហើយ។ ឧបករណ៍ចាប់ស្នាមម្រាមដៃត្រូវបានបិទ។"</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"ព្យាយាមច្រើនដងពេក។ សូមប្រើការចាក់សោអេក្រង់ជំនួសវិញ។"</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"ព្យាយាមម្ដងទៀត។"</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"មិនមានការចុះឈ្មោះស្នាមម្រាមដៃទេ។"</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ឧបករណ៍នេះមិនមានឧបករណ៍ចាប់ស្នាមម្រាមដៃទេ។"</string>
@@ -637,7 +637,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"ទាក់ទងក្រុមហ៊ុនផ្ដល់ការជួសជុល។"</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"មិនអាចបង្កើតគំរូមុខរបស់អ្នកបានទេ។ សូមព្យាយាមម្ដងទៀត។"</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"ភ្លឺពេក។ សូមសាកល្បងប្រើពន្លឺស្រាលជាងនេះ។"</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"សាកល្បងប្រើពន្លឺភ្លឺជាងនេះ"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"ដាក់ទូរសព្ទឱ្យឆ្ងាយជាងមុន"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"ដាក់ទូរសព្ទឱ្យជិតជាងមុន"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"ដាក់ទូរសព្ទឱ្យខ្ពស់ជាងមុន"</string>
@@ -1426,7 +1427,7 @@
<string name="ext_media_unmount_action" msgid="966992232088442745">"ដកចេញ"</string>
<string name="ext_media_browse_action" msgid="344865351947079139">"រុករក"</string>
<string name="ext_media_seamless_action" msgid="8837030226009268080">"លទ្ធផល Switch"</string>
- <string name="ext_media_missing_title" msgid="3209472091220515046">"បាត់ <xliff:g id="NAME">%s</xliff:g>"</string>
+ <string name="ext_media_missing_title" msgid="3209472091220515046">"បាត់<xliff:g id="NAME">%s</xliff:g>"</string>
<string name="ext_media_missing_message" msgid="4408988706227922909">"បញ្ចូលឧបករណ៍ម្តងទៀត"</string>
<string name="ext_media_move_specific_title" msgid="8492118544775964250">"កំពុងផ្លាស់ទី <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="ext_media_move_title" msgid="2682741525619033637">"កំពុងផ្លាស់ទីទិន្នន័យ…"</string>
@@ -1566,7 +1567,7 @@
<string name="action_bar_home_description_format" msgid="5087107531331621803">"%1$s, %2$s"</string>
<string name="action_bar_home_subtitle_description_format" msgid="4346835454749569826">"%1$s, %2$s, %3$s"</string>
<string name="storage_internal" msgid="8490227947584914460">"ទំហំផ្ទុករួមខាងក្នុង"</string>
- <string name="storage_sd_card" msgid="3404740277075331881">"កាតអេសឌី"</string>
+ <string name="storage_sd_card" msgid="3404740277075331881">"កាត SD"</string>
<string name="storage_sd_card_label" msgid="7526153141147470509">"កាត SD <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
<string name="storage_usb_drive" msgid="448030813201444573">"ឧបករណ៍ផ្ទុក USB"</string>
<string name="storage_usb_drive_label" msgid="6631740655876540521">"ឧបករណ៍ផ្ទុក USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
@@ -1926,8 +1927,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"ចំណូលចិត្តតំបន់"</string>
<string name="search_language_hint" msgid="7004225294308793583">"វាយបញ្ចូលឈ្មោះភាសា"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"បានណែនាំ"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"បានណែនាំ"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"ភាសាទាំងអស់"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"តំបន់ទាំងអស់"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"ស្វែងរក"</string>
@@ -2050,8 +2050,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"អនុញ្ញាតឱ្យ <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> ចូលប្រើកំណត់ហេតុឧបករណ៍ទាំងអស់ឬ?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"អនុញ្ញាតឱ្យចូលប្រើម្ដង"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"មិនអនុញ្ញាត"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"កំណត់ហេតុឧបករណ៍កត់ត្រាអ្វីដែលកើតឡើងនៅលើឧបករណ៍របស់អ្នក។ កម្មវិធីអាចប្រើកំណត់ហេតុទាំងនេះដើម្បីស្វែងរក និងដោះស្រាយបញ្ហាបាន។\n\nកំណត់ហេតុមួយចំនួនអាចមានព័ត៌មានរសើប ដូច្នេះគួរអនុញ្ញាតឱ្យចូលប្រើកំណត់ហេតុឧបករណ៍ទាំងអស់សម្រាប់តែកម្មវិធីដែលអ្នកទុកចិត្តប៉ុណ្ណោះ។ \n\nប្រសិនបើអ្នកមិនអនុញ្ញាតឱ្យកម្មវិធីនេះចូលប្រើកំណត់ហេតុឧបករណ៍ទាំងអស់ទេ វានៅតែអាចចូលប្រើកំណត់ហេតុរបស់វាផ្ទាល់បាន។ ក្រុមហ៊ុនផលិតឧបករណ៍របស់អ្នកប្រហែលជានៅតែអាចចូលប្រើកំណត់ហេតុ ឬព័ត៌មានមួយចំនួននៅលើឧបករណ៍របស់អ្នកបានដដែល។"</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"កុំបង្ហាញម្ដងទៀត"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> ចង់បង្ហាញស្ថិតិប្រើប្រាស់របស់ <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"កែ"</string>
@@ -2292,7 +2291,6 @@
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"ពិនិត្យមើលកម្មវិធីសកម្ម"</string>
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"មិនអាចចូលប្រើកាមេរ៉ាទូរសព្ទពី <xliff:g id="DEVICE">%1$s</xliff:g> របស់អ្នកបានទេ"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"មិនអាចចូលប្រើកាមេរ៉ាថេប្លេតពី <xliff:g id="DEVICE">%1$s</xliff:g> របស់អ្នកបានទេ"</string>
- <!-- no translation found for vdm_secure_window (161700398158812314) -->
- <skip />
+ <string name="vdm_secure_window" msgid="161700398158812314">"មិនអាចចូលប្រើប្រាស់ខ្លឹមសារនេះបានទេ ពេលផ្សាយ។ សូមសាកល្បងប្រើនៅលើទូរសព្ទរបស់អ្នកជំនួសវិញ។"</string>
<string name="system_locale_title" msgid="711882686834677268">"លំនាំដើមប្រព័ន្ធ"</string>
</resources>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 6d96007..db4331e 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -608,7 +608,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಕಾರ್ಯಾಚರಣೆಯನ್ನು ರದ್ದುಮಾಡಲಾಗಿದೆ."</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"ಬಳಕೆದಾರರು ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಕಾರ್ಯಾಚರಣೆಯನ್ನು ರದ್ದುಪಡಿಸಿದ್ದಾರೆ."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"ಹಲವಾರು ಪ್ರಯತ್ನಗಳು. ನಂತರ ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"ಹಲವು ಬಾರಿ ಪ್ರಯತ್ನಿಸಿದ್ದೀರಿ. ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಸೆನ್ಸರ್ ನಿಷ್ಕ್ರಿಯಗೊಂಡಿದೆ."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"ಹಲವು ಬಾರಿ ಪ್ರಯತ್ನಿಸಿದ್ದೀರಿ. ಬದಲಾಗಿ ಪರದೆಲಾಕ್ ಬಳಸಿ."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"ಯಾವುದೇ ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಅನ್ನು ನೋಂದಣಿ ಮಾಡಿಲ್ಲ."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ಈ ಸಾಧನವು ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಸೆನ್ಸರ್ ಅನ್ನು ಹೊಂದಿಲ್ಲ."</string>
@@ -637,7 +637,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"ರಿಪೇರಿ ಮಾಡುವವರನ್ನು ಸಂಪರ್ಕಿಸಿ."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"ಫೇಸ್ ಮಾಡೆಲ್ ರಚಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ. ಪುನಃ ಪ್ರಯತ್ನಿಸಿ."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"ತುಂಬಾ ಪ್ರಕಾಶಮಾನವಾಗಿದೆ ಮಂದ ಪ್ರಕಾಶಮಾನವಿರುವ ಲೈಟ್ ಬಳಸಿ"</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"ಪ್ರಕಾಶಮಾನವಾದ ಲೈಟಿಂಗ್ ಬಳಸಿ"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"ಫೋನ್ ಅನ್ನು ದೂರಕ್ಕೆ ಸರಿಸಿ"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"ಫೋನ್ ಅನ್ನು ಸಮೀಪಕ್ಕೆ ತನ್ನಿ"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"ಫೋನ್ ಅನ್ನು ಮೇಲಕ್ಕೆ ಎತ್ತಿ ಹಿಡಿಯಿರಿ."</string>
@@ -1926,8 +1927,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"ಪ್ರದೇಶ ಪ್ರಾಶಸ್ತ್ಯ"</string>
<string name="search_language_hint" msgid="7004225294308793583">"ಭಾಷೆ ಹೆಸರನ್ನು ಟೈಪ್ ಮಾಡಿ"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"ಸೂಚಿತ ಭಾಷೆ"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"ಸೂಚಿಸಲಾಗಿರುವುದು"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"ಎಲ್ಲಾ ಭಾಷೆಗಳು"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"ಎಲ್ಲಾ ಪ್ರದೇಶಗಳು"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"ಹುಡುಕಿ"</string>
@@ -2050,8 +2050,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"ಎಲ್ಲಾ ಸಾಧನದ ಲಾಗ್ಗಳನ್ನು ಆ್ಯಕ್ಸೆಸ್ ಮಾಡಲು <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> ಗೆ ಅನುಮತಿಸುವುದೇ?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"ಒಂದು ಬಾರಿಯ ಪ್ರವೇಶವನ್ನು ಅನುಮತಿಸಿ"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"ಅನುಮತಿಸಬೇಡಿ"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"ನಿಮ್ಮ ಸಾಧನದಲ್ಲಿನ ಕಾರ್ಯಾಚರಣೆಗಳನ್ನು ಸಾಧನದ ಲಾಗ್ಗಳು ರೆಕಾರ್ಡ್ ಮಾಡುತ್ತವೆ. ಸಮಸ್ಯೆಗಳನ್ನು ಪತ್ತೆಹಚ್ಚಲು ಮತ್ತು ಪರಿಹರಿಸಲು ಆ್ಯಪ್ಗಳು ಈ ಲಾಗ್ ಅನ್ನು ಬಳಸಬಹುದು.\n\nಕೆಲವು ಲಾಗ್ಗಳು ಸೂಕ್ಷ್ಮ ಮಾಹಿತಿಯನ್ನು ಒಳಗೊಂಡಿರಬಹುದು, ಆದ್ದರಿಂದ ನಿಮ್ಮ ವಿಶ್ವಾಸಾರ್ಹ ಆ್ಯಪ್ಗಳಿಗೆ ಮಾತ್ರ ಸಾಧನದ ಎಲ್ಲಾ ಲಾಗ್ಗಳಿಗೆ ಪ್ರವೇಶವನ್ನು ಅನುಮತಿಸಿ. \n\nಎಲ್ಲಾ ಸಾಧನ ಲಾಗ್ಗಳನ್ನು ಪ್ರವೇಶಿಸಲು ನೀವು ಈ ಆ್ಯಪ್ಗೆ ಅನುಮತಿಸದಿದ್ದರೆ, ಅದು ಆಗಲೂ ತನ್ನದೇ ಆದ ಲಾಗ್ಗಳನ್ನು ಪ್ರವೇಶಿಸಬಹುದು. ನಿಮ್ಮ ಸಾಧನ ತಯಾರಕರಿಗೆ ನಿಮ್ಮ ಸಾಧನದಲ್ಲಿನ ಕೆಲವು ಲಾಗ್ಗಳು ಅಥವಾ ಮಾಹಿತಿಯನ್ನು ಪ್ರವೇಶಿಸಲು ಈಗಲೂ ಸಾಧ್ಯವಾಗುತ್ತದೆ."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"ಮತ್ತೊಮ್ಮೆ ತೋರಿಸಬೇಡಿ"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_2">%2$s</xliff:g> ಸ್ಲೈಸ್ಗಳನ್ನು <xliff:g id="APP_0">%1$s</xliff:g> ತೋರಿಸಲು ಬಯಸಿದೆ"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"ಎಡಿಟ್"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 214dfa1..151e572 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -608,7 +608,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"지문 인식 작업이 취소되었습니다."</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"사용자가 지문 인식 작업을 취소했습니다."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"시도 횟수가 너무 많습니다. 나중에 다시 시도하세요."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"시도 횟수가 너무 많습니다. 지문 센서가 사용 중지되었습니다."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"시도 횟수가 너무 많습니다. 화면 잠금을 대신 사용하세요."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"다시 시도해 보세요."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"등록된 지문이 없습니다."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"기기에 지문 센서가 없습니다."</string>
@@ -637,7 +637,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"수리업체에 방문하세요."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"얼굴 모델을 만들 수 없습니다. 다시 시도해 주세요."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"너무 밝습니다. 조명 밝기를 조금 낮춰보세요."</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"조명을 밝게 해 보세요."</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"휴대전화를 얼굴에서 더 멀리 떨어뜨려 주세요."</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"휴대전화를 얼굴에 더 가까이 가져와 주세요."</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"휴대전화를 위로 이동하세요"</string>
@@ -650,9 +651,9 @@
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"얼굴을 다시 등록해 주세요."</string>
<string name="face_acquired_too_different" msgid="2520389515612972889">"얼굴을 인식할 수 없습니다. 다시 시도해 주세요."</string>
<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>
- <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"휴대전화를 좀 더 똑바로 바라봐 주세요."</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"휴대전화를 좀 더\\n똑바로 바라봐 주세요."</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"휴대전화를 좀 더\\n똑바로 바라봐 주세요."</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"휴대전화를 좀 더\\n똑바로 바라봐 주세요."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"얼굴이 가려지지 않도록 해 주세요."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"검은색 바를 포함한 화면 상단을 청소하세요."</string>
<!-- no translation found for face_acquired_dark_glasses_detected (5643703296620631986) -->
@@ -1423,7 +1424,7 @@
<string name="ext_media_unmounting_notification_title" msgid="4147986383917892162">"<xliff:g id="NAME">%s</xliff:g> 마운트 해제 중"</string>
<string name="ext_media_unmounting_notification_message" msgid="5717036261538754203">"외부 미디어를 제거하지 마세요."</string>
<string name="ext_media_init_action" msgid="2312974060585056709">"설정"</string>
- <string name="ext_media_unmount_action" msgid="966992232088442745">"마운트 해제"</string>
+ <string name="ext_media_unmount_action" msgid="966992232088442745">"꺼내기"</string>
<string name="ext_media_browse_action" msgid="344865351947079139">"둘러보기"</string>
<string name="ext_media_seamless_action" msgid="8837030226009268080">"출력 전환"</string>
<string name="ext_media_missing_title" msgid="3209472091220515046">"<xliff:g id="NAME">%s</xliff:g> 없음"</string>
@@ -1926,8 +1927,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"지역 환경설정"</string>
<string name="search_language_hint" msgid="7004225294308793583">"언어 이름 입력"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"추천"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"추천 지역"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"모든 언어"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"모든 지역"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"검색"</string>
@@ -2050,8 +2050,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g>에서 모든 기기 로그에 액세스하도록 허용하시겠습니까?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"일회성 액세스 허용"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"허용 안함"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"기기 로그에 기기에서 발생한 상황이 기록됩니다. 앱은 문제를 찾고 해결하는 데 이 로그를 사용할 수 있습니다.\n\n일부 로그는 민감한 정보를 포함할 수 있으므로 신뢰할 수 있는 앱만 모든 기기 로그에 액세스하도록 허용하세요. \n\n앱에 전체 기기 로그에 대한 액세스 권한을 부여하지 않아도 앱이 자체 로그에는 액세스할 수 있습니다. 기기 제조업체에서 일부 로그 또는 기기 내 정보에 액세스할 수도 있습니다."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"다시 표시 안함"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g>에서 <xliff:g id="APP_2">%2$s</xliff:g>의 슬라이스를 표시하려고 합니다"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"수정"</string>
@@ -2292,7 +2291,6 @@
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"활성 상태의 앱 확인"</string>
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"사용자의 <xliff:g id="DEVICE">%1$s</xliff:g>에서 휴대전화 카메라에 액세스할 수 없습니다."</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"사용자의 <xliff:g id="DEVICE">%1$s</xliff:g>에서 태블릿 카메라에 액세스할 수 없습니다."</string>
- <!-- no translation found for vdm_secure_window (161700398158812314) -->
- <skip />
+ <string name="vdm_secure_window" msgid="161700398158812314">"스트리밍 중에는 액세스할 수 없습니다. 대신 휴대전화에서 시도해 보세요."</string>
<string name="system_locale_title" msgid="711882686834677268">"시스템 기본값"</string>
</resources>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index ab671f3..c68a1ed 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -608,7 +608,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"Манжа изи иш-аракети жокко чыгарылды."</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Манжа изи операциясын колдонуучу жокко чыгарды."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"Аракеттер өтө көп болду. Бир аздан кийин кайталап көрүңүз."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Өтө көп жолу аракет жасадыңыз. Манжа изинин сенсору өчүрүлдү."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Өтө көп жолу аракет кылдыңыз. Экранды кулпулоо функциясын колдонуңуз."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Кайра бир аракеттениңиз."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Бир да манжа изи катталган эмес."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Бул түзмөктө манжа изинин сенсору жок."</string>
@@ -637,7 +637,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Тейлөө кызматына кайрылыңыз."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"Жүзүңүздүн үлгүсү түзүлгөн жок. Кайталаңыз."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Өтө жарык. Жарыктыкты азайтып көрүңүз."</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"Жарыгыраак жерге туруңуз"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"Телефонду алыстатыңыз"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"Телефонду жакындатыңыз"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"Телефонду жогору жылдырыңыз"</string>
@@ -1926,8 +1927,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"Чөлкөмдүк жөндөөлөр"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Тилди киргизиңиз"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"Сунушталгандар"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Сунушталган"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"Бардык тилдер"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"Бардык өлкөлөр"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"Издөө"</string>
@@ -2050,8 +2050,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> колдонмосуна түзмөктөгү бардык таржымалдарды жеткиликтүү кыласызбы?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"Бир жолу жеткиликтүү кылуу"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Жок"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"Түзмөктө аткарылган бардык аракеттер түзмөктүн таржымалдарында сакталып калат. Колдонмолор бул таржымалдарды колдонуп, маселелерди оңдошот.\n\nАйрым таржымалдарда купуя маалымат болушу мүмкүн, андыктан түзмөктөгү бардык таржымалдарды ишенимдүү колдонмолорго гана пайдаланууга уруксат бериңиз. \n\nЭгер бул колдонмого түзмөктөгү айрым таржымалдарга кирүүгө тыюу салсаңыз, ал өзүнүн таржымалдарын пайдалана берет. Түзмөктү өндүрүүчү түзмөгүңүздөгү айрым таржымалдарды же маалыматты көрө берет."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Экинчи көрүнбөсүн"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> колдонмосу <xliff:g id="APP_2">%2$s</xliff:g> үлгүлөрүн көрсөткөнү жатат"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Түзөтүү"</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index b63c413..a9a72da 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -608,7 +608,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"ຍົກເລີກການດຳເນີນການລາຍນີ້ວມືແລ້ວ."</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"ຜູ້ໃຊ້ໄດ້ຍົກເລີກຄຳສັ່ງລາຍນິ້ວມືແລ້ວ."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"ມີຄວາມພະຍາຍາມຫຼາຍຄັ້ງເກີນໄປ. ລອງໃໝ່ພາຍຫຼັງ."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"ພະຍາຍາມຫຼາຍເທື່ອເກີນໄປ. ລະບົບປິດການເຮັດວຽກຂອງເຊັນເຊີລາຍນິ້ວມືແລ້ວ."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"ພະຍາຍາມຫຼາຍເທື່ອເກີນໄປ. ກະລຸນາໃຊ້ການລອກໜ້າຈໍແທນ."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"ລອງໃໝ່ອີກຄັ້ງ."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"ບໍ່ມີການລົງທະບຽນລາຍນິ້ວມື."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ອຸປະກອນນີ້ບໍ່ມີເຊັນເຊີລາຍນິ້ວມື."</string>
@@ -637,7 +637,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"ກະລຸນາໄປຫາຜູ້ໃຫ້ບໍລິການສ້ອມແປງ."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"ບໍ່ສາມາດສ້າງຮູບແບບໃບໜ້າຂອງທ່ານໄດ້. ກະລຸນາລອງໃໝ່."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"ແຈ້ງເກີນໄປ. ລອງຄ່ອຍແສງໄຟລົງ."</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"ກະລຸນາລອງໃຊ້ສະພາບແສງທີ່ແຈ້ງຂຶ້ນ"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"ເລື່ອນໂທລະສັບອອກໄປໄກຂຶ້ນ"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"ເລື່ອນໂທລະສັບເຂົ້າໄປໃກ້ຂຶ້ນ"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"ຍົກໂທລະສັບໃຫ້ສູງຂຶ້ນ"</string>
@@ -1926,8 +1927,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"ການຕັ້ງຄ່າພາກພື້ນ"</string>
<string name="search_language_hint" msgid="7004225294308793583">"ພິມຊື່ພາສາ"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"ແນະນຳ"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"ແນະນຳ"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"ທຸກພາສາ"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"ທຸກຂົງເຂດ"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"ຄົ້ນຫາ"</string>
@@ -2050,8 +2050,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"ອະນຸຍາດໃຫ້ <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> ເຂົ້າເຖິງບັນທຶກອຸປະກອນທັງໝົດບໍ?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"ອະນຸຍາດການເຂົ້າເຖິງແບບເທື່ອດຽວ"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"ບໍ່ອະນຸຍາດ"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"ບັນທຶກອຸປະກອນຈະບັນທຶກສິ່ງທີ່ເກີດຂຶ້ນຢູ່ອຸປະກອນຂອງທ່ານ. ແອັບສາມາດໃຊ້ບັນທຶກເຫຼົ່ານີ້ເພື່ອຊອກຫາ ແລະ ແກ້ໄຂບັນຫາໄດ້.\n\nບັນທຶກບາງຢ່າງອາດມີຂໍ້ມູນລະອຽດອ່ອນ, ດັ່ງນັ້ນໃຫ້ອະນຸຍາດສະເພາະແອັບທີ່ທ່ານເຊື່ອຖືໃຫ້ເຂົ້າເຖິງບັນທຶກອຸປະກອນທັງໝົດເທົ່ານັ້ນ. \n\nຫາກທ່ານບໍ່ອະນຸຍາດແອັບນີ້ໃຫ້ເຂົ້າເຖິງບັນທຶກອຸປະກອນທັງໝົດ, ມັນຈະຍັງຄົງສາມາດເຂົ້າເຖິງບັນທຶກຂອງຕົວມັນເອງໄດ້ຢູ່. ຜູ້ຜະລິດອຸປະກອນຂອງທ່ານອາດຍັງຄົງສາມາດເຂົ້າເຖິງບັນທຶກ ຫຼື ຂໍ້ມູນບາງຢ່າງຢູ່ອຸປະກອນຂອງທ່ານໄດ້."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"ບໍ່ຕ້ອງສະແດງອີກ"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> ຕ້ອງການສະແດງ <xliff:g id="APP_2">%2$s</xliff:g> ສະໄລ້"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"ແກ້ໄຂ"</string>
@@ -2292,7 +2291,6 @@
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"ກວດສອບແອັບທີ່ເຄື່ອນໄຫວ"</string>
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"ບໍ່ສາມາດເຂົ້າເຖິງກ້ອງຖ່າຍຮູບຂອງໂທລະສັບຈາກ <xliff:g id="DEVICE">%1$s</xliff:g> ຂອງທ່ານໄດ້"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"ບໍ່ສາມາດເຂົ້າເຖິງກ້ອງຖ່າຍຮູບຂອງແທັບເລັດຈາກ <xliff:g id="DEVICE">%1$s</xliff:g> ຂອງທ່ານໄດ້"</string>
- <!-- no translation found for vdm_secure_window (161700398158812314) -->
- <skip />
+ <string name="vdm_secure_window" msgid="161700398158812314">"ບໍ່ສາມາດເຂົ້າເຖິງເນື້ອຫານີ້ໄດ້ໃນຂະນະທີ່ຍັງສະຕຣີມຢູ່. ກະລຸນາລອງຢູ່ໂທລະສັບຂອງທ່ານແທນ."</string>
<string name="system_locale_title" msgid="711882686834677268">"ຄ່າເລີ່ມຕົ້ນຂອງລະບົບ"</string>
</resources>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 038d107..a991bff 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -610,7 +610,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"Piršto antspaudo operacija atšaukta."</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Piršto antspaudo operaciją atšaukė naudotojas."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"Per daug bandymų. Vėliau bandykite dar kartą."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Per daug bandymų. Piršto antspaudo jutiklis išjungtas."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Per daug bandymų. Naudokite ekrano užraktą."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Bandykite dar kartą."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Neužregistruota jokių kontrolinių kodų."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Šiame įrenginyje nėra kontrolinio kodo jutiklio."</string>
@@ -639,7 +639,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Apsilankykite pas taisymo paslaugos teikėją."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"Nepavyko sukurti veido modelio. Band. dar kartą."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Per šviesu. Išbandykite mažesnį apšvietimą."</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"Išbandykite šviesesnį apšvietimą"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"Laikykite telefoną toliau"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"Laikykite telefoną arčiau"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"Laikykite telefoną aukščiau"</string>
@@ -1928,8 +1929,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"Regiono nuostata"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Įveskite kalbos pav."</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"Siūloma"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Siūloma"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"Visos kalbos"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"Visi regionai"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"Paieška"</string>
@@ -2052,8 +2052,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Leisti „<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g>“ pasiekti visus įrenginio žurnalus?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"Leisti vienkartinę prieigą"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Neleisti"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"Įrenginyje įrašoma, kas įvyksta jūsų įrenginyje. Programos gali naudoti šiuos žurnalus, kad surastų ir išspręstų problemas.\n\nKai kuriuose žurnaluose gali būti neskelbtinos informacijos, todėl visus įrenginio žurnalus leiskite pasiekti tik programoms, kuriomis pasitikite. \n\nJei neleisite šiai programai pasiekti visų įrenginio žurnalų, ji vis tiek galės pasiekti savo žurnalus. Įrenginio gamintojui vis tiek gali būti leidžiama pasiekti tam tikrus žurnalus ar informaciją jūsų įrenginyje."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Daugiau neberodyti"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"„<xliff:g id="APP_0">%1$s</xliff:g>“ nori rodyti „<xliff:g id="APP_2">%2$s</xliff:g>“ fragmentus"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Redaguoti"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index f985d99..93d2bd4 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -609,7 +609,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"Nospieduma darbība neizdevās."</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Lietotājs atcēla pirksta nospieduma darbību."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"Pārāk daudz mēģinājumu. Vēlāk mēģiniet vēlreiz."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Pārāk daudz mēģinājumu. Pirksta nospieduma sensors atspējots."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Pārāk daudz mēģinājumu. Izmantojiet ekrāna bloķēšanu."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Mēģiniet vēlreiz."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nav reģistrēts neviens pirksta nospiedums."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Šajā ierīcē nav pirksta nospieduma sensora."</string>
@@ -638,7 +638,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Sazinieties ar remonta pakalpojumu sniedzēju."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"Nevar izveidot sejas modeli. Mēģiniet vēlreiz."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Pārāk spilgts. Izmēģiniet maigāku apgaismojumu."</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"Izmēģiniet spožāku apgaismojumu"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"Pārvietojiet tālruni tālāk."</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"Pārvietojiet tālruni tuvāk."</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"Paceliet tālruni augstāk."</string>
@@ -1927,8 +1928,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"Reģiona preference"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Ierakstiet valodas nosaukumu"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"Ieteiktās"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Ieteiktie"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"Visas valodas"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"Visi reģioni"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"Meklēt"</string>
@@ -2051,8 +2051,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Vai atļaujat lietotnei <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> piekļūt visiem ierīces žurnāliem?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"Atļaut vienreizēju piekļuvi"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Neatļaut"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"Ierīces žurnālos tiek reģistrēti ierīces procesi un notikumi. Lietotņu izstrādātāji var izmantot šos žurnālus, lai atrastu un izlabotu problēmas savās lietotnēs.\n\nDažos žurnālos var būt ietverta sensitīva informācija, tāpēc atļaujiet tikai uzticamām lietotnēm piekļūt visiem ierīces žurnāliem. \n\nJa neatļausiet šai lietotnei piekļūt visiem ierīces žurnāliem, lietotnes izstrādātājs joprojām varēs piekļūt pašas lietotnes žurnāliem. Iespējams, ierīces ražotājs joprojām varēs piekļūt noteiktiem žurnāliem vai informācijai jūsu ierīcē."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Vairs nerādīt"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"Lietotne <xliff:g id="APP_0">%1$s</xliff:g> vēlas rādīt lietotnes <xliff:g id="APP_2">%2$s</xliff:g> sadaļas"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Rediģēt"</string>
@@ -2293,7 +2292,6 @@
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Pārbaudiet aktīvās lietotnes"</string>
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Nevar piekļūt tālruņa kamerai no jūsu ierīces (<xliff:g id="DEVICE">%1$s</xliff:g>)."</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Nevar piekļūt planšetdatora kamerai no jūsu ierīces (<xliff:g id="DEVICE">%1$s</xliff:g>)."</string>
- <!-- no translation found for vdm_secure_window (161700398158812314) -->
- <skip />
+ <string name="vdm_secure_window" msgid="161700398158812314">"Straumēšanas laikā nevar piekļūt šim saturam. Mēģiniet tam piekļūt savā tālrunī."</string>
<string name="system_locale_title" msgid="711882686834677268">"Sistēmas noklusējums"</string>
</resources>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index 5025ab6..9fb8937 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -608,7 +608,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"Операцијата со отпечаток се откажа."</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Корисникот ја откажа потврдата со отпечаток."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"Премногу обиди. Обидете се повторно подоцна."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Премногу обиди. Сензорот за отпечатоци е оневозможен."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Премногу обиди. Користете заклучување екран."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Обидете се повторно."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Не се запишани отпечатоци."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Уредов нема сензор за отпечатоци."</string>
@@ -637,7 +637,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Однесете го на поправка."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"Не може да создаде модел на лик. Обидете се пак."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Премногу светла. Пробајте со послабо осветлување."</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"Пробајте со посилно осветлување"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"Оддалечете го телефонот"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"Доближете го телефонот"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"Кренете го телефонот погоре"</string>
@@ -1566,8 +1567,8 @@
<string name="action_bar_home_description_format" msgid="5087107531331621803">"%1$s, %2$s"</string>
<string name="action_bar_home_subtitle_description_format" msgid="4346835454749569826">"%1$s, %2$s, %3$s"</string>
<string name="storage_internal" msgid="8490227947584914460">"Внатрешен споделен капацитет"</string>
- <string name="storage_sd_card" msgid="3404740277075331881">"СД картичка"</string>
- <string name="storage_sd_card_label" msgid="7526153141147470509">"<xliff:g id="MANUFACTURER">%s</xliff:g> СД-картичка"</string>
+ <string name="storage_sd_card" msgid="3404740277075331881">"SD-картичка"</string>
+ <string name="storage_sd_card_label" msgid="7526153141147470509">"<xliff:g id="MANUFACTURER">%s</xliff:g> SD-картичка"</string>
<string name="storage_usb_drive" msgid="448030813201444573">"USB-меморија"</string>
<string name="storage_usb_drive_label" msgid="6631740655876540521">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB-меморија"</string>
<string name="storage_usb" msgid="2391213347883616886">"USB меморија"</string>
@@ -1926,8 +1927,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"Претпочитувања за регион"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Внесете име на јазик"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"Предложени"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Предложени"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"Сите јазици"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"Сите региони"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"Пребарај"</string>
@@ -2050,8 +2050,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Да се дозволи <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> да пристапува до целата евиденција на уредот?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"Дозволи еднократен пристап"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Не дозволувај"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"Дневниците за евиденција на уредот снимаат што се случува на вашиот уред. Апликациите може да ги користат овие дневници за евиденција за да наоѓаат и поправаат проблеми.\n\nНекои дневници за евиденција може да содржат чувствителни податоци, па затоа дозволете им пристап до сите дневници за евиденција на уредот само на апликациите во кои имате доверба. \n\nАко не ѝ дозволите на апликацијава да пристапува до сите дневници за евиденција на уредот, таа сепак ќе може да пристапува до сопствените дневници за евиденција. Производителот на вашиот уред можеби сепак ќе може да пристапува до некои дневници за евиденција или податоци на уредот."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Не прикажувај повторно"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> сака да прикажува делови од <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Измени"</string>
@@ -2292,7 +2291,6 @@
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Проверете ги активните апликации"</string>
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Не може да се пристапи до камерата на вашиот телефон од <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Не може да се пристапи до камерата на вашиот таблет од <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
- <!-- no translation found for vdm_secure_window (161700398158812314) -->
- <skip />
+ <string name="vdm_secure_window" msgid="161700398158812314">"До ова не може да се пристапи при стриминг. Наместо тоа, пробајте на вашиот телефон."</string>
<string name="system_locale_title" msgid="711882686834677268">"Стандардно за системот"</string>
</resources>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index 7ff6940..328a3ab 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -608,7 +608,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"ഫിംഗർപ്രിന്റ് പ്രവർത്തനം റദ്ദാക്കി."</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"ഉപയോക്താവ് റദ്ദാക്കിയ ഫിംഗർപ്രിന്റ് പ്രവർത്തനം."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"നിരവധി തവണ ശ്രമിച്ചു. പിന്നീട് വീണ്ടും ശ്രമിക്കുക."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"നിരവധി തവണ ശ്രമിച്ചതിനാൽ, ഫിംഗർപ്രിന്റ് സെൻസർ പ്രവർത്തനരഹിതമായി."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"നിരവധി ശ്രമങ്ങൾ. പകരം സ്ക്രീൻ ലോക്ക് ഉപയോഗിക്കുക."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"വീണ്ടും ശ്രമിക്കൂ."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"വിരലടയാളങ്ങൾ എൻറോൾ ചെയ്തിട്ടില്ല."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ഈ ഉപകരണത്തിൽ ഫിംഗർപ്രിന്റ് സെൻസറില്ല."</string>
@@ -637,7 +637,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"റിപ്പയർ കേന്ദ്രം സന്ദർശിക്കുക."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"മുഖ മോഡൽ സൃഷ്ടിക്കാനാകുന്നില്ല. വീണ്ടും ശ്രമിക്കൂ."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"വളരെയധികം തെളിച്ചം. സൗമ്യതയേറിയ പ്രകാശം ശ്രമിക്കൂ."</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"കൂടുതൽ വെളിച്ചമുള്ളയിടത്ത് പരീക്ഷിച്ച് നോക്കൂ"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"ഫോൺ കൂടുതൽ ദൂരേയ്ക്ക് നീക്കുക"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"ഫോൺ അടുത്തേക്ക് നീക്കുക"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"ഫോൺ മുകളിലേക്ക് ഉയർത്തുക"</string>
@@ -1423,7 +1424,7 @@
<string name="ext_media_unmounting_notification_title" msgid="4147986383917892162">"<xliff:g id="NAME">%s</xliff:g> ഒഴിവാക്കുന്നു"</string>
<string name="ext_media_unmounting_notification_message" msgid="5717036261538754203">"നീക്കം ചെയ്യരുത്"</string>
<string name="ext_media_init_action" msgid="2312974060585056709">"സജ്ജമാക്കുക"</string>
- <string name="ext_media_unmount_action" msgid="966992232088442745">"നിരസിക്കുക"</string>
+ <string name="ext_media_unmount_action" msgid="966992232088442745">"ഒഴിവാക്കുക"</string>
<string name="ext_media_browse_action" msgid="344865351947079139">"അടുത്തറിയുക"</string>
<string name="ext_media_seamless_action" msgid="8837030226009268080">"ഔട്ട്പുട്ട് മാറുക"</string>
<string name="ext_media_missing_title" msgid="3209472091220515046">"<xliff:g id="NAME">%s</xliff:g> കാണുന്നില്ല"</string>
@@ -1926,8 +1927,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"മേഖലാ മുൻഗണന"</string>
<string name="search_language_hint" msgid="7004225294308793583">"ഭാഷ ടൈപ്പ് ചെയ്യുക"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"നിര്ദ്ദേശിച്ചത്"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"നിർദ്ദേശിച്ചവ"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"എല്ലാ ഭാഷകളും"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"എല്ലാ പ്രദേശങ്ങളും"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"തിരയുക"</string>
@@ -2050,8 +2050,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"എല്ലാ ഉപകരണ ലോഗുകളും ആക്സസ് ചെയ്യാൻ <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> എന്നതിനെ അനുവദിക്കണോ?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"ഒറ്റത്തവണ ആക്സസ് അനുവദിക്കുക"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"അനുവദിക്കരുത്"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"ഉപകരണ ലോഗുകൾ നിങ്ങളുടെ ഉപകരണത്തിൽ എന്തൊക്കെയാണ് സംഭവിക്കുന്നതെന്ന് റെക്കോർഡ് ചെയ്യുന്നു. പ്രശ്നങ്ങൾ കണ്ടെത്തി പരിഹരിക്കുന്നതിന് ആപ്പുകൾക്ക് ഈ ലോഗുകൾ ഉപയോഗിക്കാൻ കഴിയും.\n\nചില ലോഗുകളിൽ സൂക്ഷ്മമായി കൈകാര്യം ചെയ്യേണ്ട വിവരങ്ങൾ അടങ്ങിയിരിക്കാൻ സാധ്യതയുള്ളതിനാൽ, എല്ലാ ഉപകരണ ലോഗുകളും ആക്സസ് ചെയ്യാനുള്ള അനുമതി നിങ്ങൾക്ക് വിശ്വാസമുള്ള ആപ്പുകൾക്ക് മാത്രം നൽകുക. \n\nഎല്ലാ ഉപകരണ ലോഗുകളും ആക്സസ് ചെയ്യാനുള്ള അനുവാദം നൽകിയില്ലെങ്കിലും, ഈ ആപ്പിന് അതിന്റെ സ്വന്തം ലോഗുകൾ ആക്സസ് ചെയ്യാനാകും. നിങ്ങളുടെ ഉപകരണ നിർമ്മാതാവിന് തുടർന്നും നിങ്ങളുടെ ഉപകരണത്തിലെ ചില ലോഗുകളോ വിവരങ്ങളോ ആക്സസ് ചെയ്യാനായേക്കും."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"വീണ്ടും കാണിക്കരുത്"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_2">%2$s</xliff:g> സ്ലൈസുകൾ കാണിക്കാൻ <xliff:g id="APP_0">%1$s</xliff:g> താൽപ്പര്യപ്പെടുന്നു"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"എഡിറ്റ് ചെയ്യുക"</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index b70c985..0e567e9 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -608,7 +608,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"Хурууны хээний бүртгэл амжилтгүй боллоо."</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Хэрэглэгч хурууны хээний баталгаажуулалтыг цуцалсан байна."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"Хэтэрхий олон оролдлоо. Түр хүлээгээд дахин оролдоно уу."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Хэт олон удаа оролдсон тул хурууны хээ мэдрэгчийг идэвхгүй болголоо."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Хэт олон удаа оролдлоо. Оронд нь дэлгэцийн түгжээ ашиглана уу."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Дахин оролдно уу."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Бүртгүүлсэн хурууны хээ алга."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Энэ төхөөрөмжид хурууны хээ мэдрэгч алга."</string>
@@ -637,7 +637,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Засварын үйлчилгээ үзүүлэгчид зочилно уу."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"Нүүрний загвар үүсгэж чадсангүй. Дахин оролдоно уу."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Хэт цайвар байна. Гэрэл багатай газар оролдоно уу."</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"Гэрэлтэй орчинд туршина уу"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"Утсаа холдуулна уу"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"Утсаа ойртуулна уу"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"Утсаа дээшлүүлнэ үү"</string>
@@ -1926,8 +1927,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"Бүс нутгийн тохиргоо"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Улсын хэлийг бичнэ үү"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"Санал болгосон"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Санал болгосон"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"Бүх хэл"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"Бүх бүс нутаг"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"Хайх"</string>
@@ -2050,8 +2050,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g>-д төхөөрөмжийн бүх логт хандахыг зөвшөөрөх үү?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"Нэг удаагийн хандалтыг зөвшөөрнө үү"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Бүү зөвшөөр"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"Төхөөрөмжийн лог нь таны төхөөрөмж дээр юу болж байгааг бичдэг. Аппууд эдгээр логийг асуудлыг олох болон засахад ашиглах боломжтой.\n\nЗарим лог эмзэг мэдээлэл агуулж байж магадгүй тул та зөвхөн итгэдэг аппууддаа төхөөрөмжийн бүх логт хандахыг зөвшөөрнө үү. \n\nХэрэв та энэ аппад төхөөрөмжийн бүх логт хандахыг зөвшөөрөхгүй бол энэ нь өөрийн логт хандах боломжтой хэвээр байх болно. Tаны төхөөрөмж үйлдвэрлэгч таны төхөөрөмж дээрх зарим лог эсвэл мэдээлэлд хандах боломжтой хэвээр байж магадгүй."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Дахиж бүү харуул"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> <xliff:g id="APP_2">%2$s</xliff:g>-н хэсгүүдийг (slices) харуулах хүсэлтэй байна"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Засах"</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index d31fc9b..48420dd 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -608,7 +608,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"फिंगरप्रिंट ऑपरेशन रद्द झाले."</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"वापरकर्त्याने फिंगरप्रिंट ऑपरेशन रद्द केले."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"खूप प्रयत्न केले. नंतर पुन्हा प्रयत्न करा."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"खूप प्रयत्न करून झाले. फिंगरप्रिंट सेन्सर बंद आहे."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"खूप जास्त प्रयत्न. त्याऐवजी स्क्रीन लॉक वापरा."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"पुन्हा प्रयत्न करा."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"कोणत्याही फिंगरप्रिंटची नोंद झाली नाही"</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"या डिव्हाइसमध्ये फिंगरप्रिंट सेन्सर नाही."</string>
@@ -637,7 +637,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"दुरुस्तीच्या सेवा पुरवठादाराला भेट द्या."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"फेस मॉडेल तयार करू शकत नाही. पुन्हा प्रयत्न करा."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"खूप प्रखर. आणखी सौम्य प्रकाश वापरून पहा."</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"आणखी प्रखर प्रकाश वापरून पहा"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"फोन आणखी दूर हलवा"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"फोन आणखी जवळ हलवा"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"फोन आणखी वर हलवा"</string>
@@ -1926,8 +1927,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"प्रदेश प्राधान्य"</string>
<string name="search_language_hint" msgid="7004225294308793583">"भाषा नाव टाइप करा"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"सुचवलेल्या भाषा"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"सुचवलेले"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"सर्व भाषा"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"सर्व प्रदेश"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"शोध"</string>
@@ -2050,8 +2050,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> ला सर्व डिव्हाइस लॉग अॅक्सेस करण्याची अनुमती द्यायची आहे का?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"एक वेळ अॅक्सेसची अनुमती द्या"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"अनुमती देऊ नका"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"तुमच्या डिव्हाइसवर काय होते ते डिव्हाइस लॉग रेकॉर्ड करते. समस्या शोधण्यासाठी आणि त्यांचे निराकरण करण्याकरिता ॲप्स हे लॉग वापरू शकतात.\n\nकाही लॉगमध्ये संवेदनशील माहिती असू शकते, त्यामुळे फक्त तुमचा विश्वास असलेल्या ॲप्सना सर्व डिव्हाइस लॉग अॅक्सेस करण्याची अनुमती द्या. \n\nतुम्ही या ॲपला सर्व डिव्हाइस लॉग अॅक्सेस करण्याची अनुमती न दिल्यास, ते तरीही त्याचा स्वतःचा लॉग अॅक्सेस करू शकते. तुमच्या डिव्हाइसचा उत्पादक तरीही काही लॉग किंवा तुमच्या डिव्हाइसवरील माहिती अॅक्सेस करू शकतो."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"पुन्हा दाखवू नका"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> ला <xliff:g id="APP_2">%2$s</xliff:g> चे तुकडे दाखवायचे आहेत"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"संपादित करा"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 9f6c157..f38e6a5 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -608,7 +608,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"Pengendalian cap jari dibatalkan."</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Pengendalian cap jari dibatalkan oleh pengguna."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"Terlalu banyak percubaan. Cuba sebentar lagi."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Terlalu banyak percubaan. Penderia cap jari dilumpuhkan."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Terlalu banyak percubaan. Gunakan kunci skrin."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Cuba lagi."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Tiada cap jari didaftarkan."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Peranti ini tiada penderia cap jari."</string>
@@ -637,7 +637,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Lawati penyedia pembaikan."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"Tidak dapat membuat model wajah anda. Cuba lagi."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Terlalu terang. Cuba pencahayaan yang lebih lembut."</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"Cuba pencahayaan yang lebih cerah"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"Jauhkan telefon"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"Dekatkan telefon"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"Tinggikan lagi telefon"</string>
@@ -1926,8 +1927,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"Pilihan wilayah"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Taipkan nama bahasa"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"Dicadangkan"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Dicadangkan"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"Semua bahasa"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"Semua rantau"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"Cari"</string>
@@ -2050,8 +2050,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Benarkan <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> mengakses semua log peranti?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"Benarkan akses satu kali"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Jangan benarkan"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"Log peranti merekodkan perkara yang berlaku pada peranti anda. Apl dapat menggunakan log ini untuk menemukan dan membetulkan isu.\n\nSesetengah log mungkin mengandungi maklumat sensitif, jadi benarkan apl yang anda percaya sahaja untuk mengakses semua log peranti. \n\nJika anda tidak membenarkan apl ini mengakses semua log peranti, apl masih boleh mengakses log sendiri. Pengilang peranti anda mungkin masih dapat mengakses sesetengah log atau maklumat pada peranti anda."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Jangan tunjuk lagi"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> mahu menunjukkan <xliff:g id="APP_2">%2$s</xliff:g> hirisan"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Edit"</string>
@@ -2292,7 +2291,6 @@
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Semak apl aktif"</string>
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Tidak dapat mengakses kamera telefon daripada <xliff:g id="DEVICE">%1$s</xliff:g> anda"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Tidak dapat mengakses kamera tablet daripada <xliff:g id="DEVICE">%1$s</xliff:g> anda"</string>
- <!-- no translation found for vdm_secure_window (161700398158812314) -->
- <skip />
+ <string name="vdm_secure_window" msgid="161700398158812314">"Kandungan ini tidak boleh diakses semasa penstriman. Cuba pada telefon anda."</string>
<string name="system_locale_title" msgid="711882686834677268">"Lalai sistem"</string>
</resources>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index ba7eaa6..af9c07b 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -608,7 +608,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"လက်ဗွေယူခြင်း ပယ်ဖျက်လိုက်သည်။"</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"လက်ဗွေဖြင့် အထောက်အထားစိစစ်ခြင်းကို အသုံးပြုသူက ပယ်ဖျက်ထားသည်။"</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"ကြိုးစာမှု အကြိမ်များနေ၏။ နောက်မှ ထပ်မံကြိုးစားပါ။"</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"အကြိမ်အရေအတွက် အလွန်များနေပါပြီ။ လက်ဗွေအာရုံခံကိရိယာ ပိတ်ထားပါသည်။"</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"ကြိုးပမ်းမှုအကြိမ်ရေ များလွန်းသည်။ ဖန်သားပြင်လော့ခ်ချခြင်းကို အစားထိုးသုံးပါ။"</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"ပြန်ကြိုးစားပါ"</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"မည်သည့် လက်ဗွေကိုမျှ ထည့်သွင်းမထားပါ။"</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ဤစက်တွင် လက်ဗွေအာရုံခံကိရိယာ မရှိပါ။"</string>
@@ -637,7 +637,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"ပြုပြင်ရေး ဝန်ဆောင်မှုပေးသူထံသို့ သွားပါ။"</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"သင့်မျက်နှာနမူနာ ပြုလုပ်၍မရပါ။ ထပ်စမ်းကြည့်ပါ။"</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"အလွန် လင်းသည်။ အလင်းလျှော့ကြည့်ပါ။"</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"ပိုလင်းအောင် လုပ်ကြည့်ပါ"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"ဖုန်းကို အဝေးသို့ခွာပါ"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"ဖုန်းကို အနားသို့ပိုတိုးပါ"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"ဖုန်းကို ပိုမြှင့်လိုက်ပါ"</string>
@@ -1423,11 +1424,11 @@
<string name="ext_media_unmounting_notification_title" msgid="4147986383917892162">"<xliff:g id="NAME">%s</xliff:g> ကို ထုတ်နေသည်"</string>
<string name="ext_media_unmounting_notification_message" msgid="5717036261538754203">"မဖယ်ရှားပါနှင့်"</string>
<string name="ext_media_init_action" msgid="2312974060585056709">"သတ်မှတ်ရန်"</string>
- <string name="ext_media_unmount_action" msgid="966992232088442745">"ထုတ်မည်"</string>
+ <string name="ext_media_unmount_action" msgid="966992232088442745">"ထုတ်ရန်"</string>
<string name="ext_media_browse_action" msgid="344865351947079139">"စူးစမ်းရန်"</string>
<string name="ext_media_seamless_action" msgid="8837030226009268080">"မီဒီယာအထွက် ပြောင်းရန်"</string>
<string name="ext_media_missing_title" msgid="3209472091220515046">"<xliff:g id="NAME">%s</xliff:g> ပျောက်နေသည်"</string>
- <string name="ext_media_missing_message" msgid="4408988706227922909">"စက်ပစ္စည်းကို ထပ်မံထည့်သွင်းပါ"</string>
+ <string name="ext_media_missing_message" msgid="4408988706227922909">"ကတ်ကို ထပ်မံထည့်သွင်းပါ"</string>
<string name="ext_media_move_specific_title" msgid="8492118544775964250">"<xliff:g id="NAME">%s</xliff:g> ရွှေ့နေစဉ်"</string>
<string name="ext_media_move_title" msgid="2682741525619033637">"ဒေတာများ ရွှေ့နေစဉ်"</string>
<string name="ext_media_move_success_title" msgid="4901763082647316767">"အကြောင်းအရာ လွှဲပြောင်းပြီးပါပြီ"</string>
@@ -1926,8 +1927,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"ဒေသရွေးချယ်မှု"</string>
<string name="search_language_hint" msgid="7004225294308793583">"ဘာသာစကားအမည် ထည့်ပါ"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"အကြံပြုထားသည်"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"အကြံပြုထားသည်"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"ဘာသာစကားအားလုံး"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"ဒေသအားလုံး"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"ရှာဖွေရန်"</string>
@@ -2050,8 +2050,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> ကို စက်မှတ်တမ်းအားလုံး သုံးခွင့်ပြုမလား။"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"တစ်ခါသုံး ဝင်ခွင့်ပေးရန်"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"ခွင့်မပြုပါ"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"သင့်စက်ရှိ အဖြစ်အပျက်များကို စက်မှတ်တမ်းများက မှတ်တမ်းတင်သည်။ အက်ပ်များက ပြဿနာများ ရှာဖွေပြီးဖြေရှင်းရန် ဤမှတ်တမ်းများကို သုံးနိုင်သည်။\n\nအချို့မှတ်တမ်းများတွင် သတိထားရမည့်အချက်အလက်များ ပါဝင်နိုင်သဖြင့် စက်မှတ်တမ်းအားလုံးကို ယုံကြည်ရသည့် အက်ပ်များကိုသာ သုံးခွင့်ပြုပါ။ \n\nဤအက်ပ်ကို စက်မှတ်တမ်းအားလုံး သုံးခွင့်မပြုသော်လည်း ၎င်းက ၎င်း၏ကိုယ်ပိုင်မှတ်တမ်းကို သုံးနိုင်ဆဲဖြစ်သည်။ သင့်စက်ရှိ အချို့မှတ်တမ်းများ (သို့) အချက်အလက်များကို သင့်စက်ထုတ်လုပ်သူက သုံးနိုင်ပါသေးသည်။"</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"နောက်ထပ်မပြပါနှင့်"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> သည် <xliff:g id="APP_2">%2$s</xliff:g> ၏အချပ်များကို ပြသလိုသည်"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"တည်းဖြတ်ရန်"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 874ab40..085ec3b 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -608,7 +608,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"Fingeravtrykk-operasjonen ble avbrutt."</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Fingeravtrykk-operasjonen ble avbrutt av brukeren."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"For mange forsøk. Prøv på nytt senere."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"For mange forsøk. Fingeravtrykkssensoren er slått av."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"For mange forsøk. Bruk skjermlås i stedet."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Prøv på nytt."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Ingen fingeravtrykk er registrert."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Denne enheten har ikke fingeravtrykkssensor."</string>
@@ -637,7 +637,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Gå til en reparasjonsleverandør."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"Kan ikke lage ansiktsmodell. Prøv på nytt."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"For lyst. Prøv svakere belysning."</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"Prøv sterkere belysning"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"Flytt telefonen lengre unna"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"Flytt telefonen nærmere"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"Flytt telefonen høyere"</string>
@@ -1926,8 +1927,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"Regionsinnstilling"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Skriv inn språknavn"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"Foreslått"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Foreslått"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"Alle språk"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"Alle områder"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"Søk"</string>
@@ -2050,8 +2050,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Vil du gi <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> tilgang til alle enhetslogger?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"Gi éngangstilgang"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Ikke tillat"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"Enhetslogger registrerer det som skjer på enheten din. Apper kan bruke disse loggene til å finne og løse problemer.\n\nNoen logger kan inneholde sensitiv informasjon, så du bør bare gi tilgang til alle enhetslogger til apper du stoler på. \n\nHvis du ikke gir denne appen tilgang til alle enhetslogger, har den fortsatt tilgang til sine egne logger. Enhetsprodusenten kan fortsatt ha tilgang til visse logger eller noe informasjon på enheten din."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Ikke vis igjen"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> vil vise <xliff:g id="APP_2">%2$s</xliff:g>-utsnitt"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Endre"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index cbdaf38..5473edd 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -608,7 +608,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"फिंगरप्रिन्ट सञ्चालन रद्द गरियो।"</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"प्रयोगकर्ताले फिंगरप्रिन्टसम्बन्धी कारबाही रद्द गर्नुभयो।"</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"धेरै प्रयासहरू। केहि समय पछि पुन: प्रयास गर्नुहोला"</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"अत्यन्त धेरै प्रयासहरू। फिंगरप्रिन्ट सेन्सरलाई असक्षम पारियो।"</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"निकै धेरै पटक प्रयास गरिसकिएको छ। बरु स्क्रिन लक प्रयोग गर्नुहोस्।"</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"पुन: प्रयास गर्नुहोला।"</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"कुनै पनि फिंगरप्रिन्ट दर्ता गरिएको छैन।"</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"यो डिभाइसमा कुनै पनि फिंगरप्रिन्ट सेन्सर छैन।"</string>
@@ -637,7 +637,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"फिंगरप्रिन्ट सेन्सर मर्मत गर्ने सेवा प्रदायक कम्पनीमा सम्पर्क गर्नुहोस्।"</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"तपाईंको फेस मोडेल सिर्जना गर्न सकिएन। फेरि प्रयास गर्नुहोस्।"</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"ज्यादै चम्किलो। अझ मधुरो प्रकाश प्रयोग गरी हेर्नु…"</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"अझ उज्यालो ठाउँमा गएर फोटो खिची हेर्नुहोस्"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"फोन अझै पर सार्नुहोस्"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"फोन अझै नजिक सार्नुहोस्"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"फोन अझ माथि उठाउनुहोस्"</string>
@@ -1427,7 +1428,7 @@
<string name="ext_media_browse_action" msgid="344865351947079139">"अन्वेषण गर्नुहोस्"</string>
<string name="ext_media_seamless_action" msgid="8837030226009268080">"आउटपुट बदल्नुहोस्"</string>
<string name="ext_media_missing_title" msgid="3209472091220515046">"<xliff:g id="NAME">%s</xliff:g> हराइरहेको"</string>
- <string name="ext_media_missing_message" msgid="4408988706227922909">"यन्त्र फेरि घुसाउनुहोस्"</string>
+ <string name="ext_media_missing_message" msgid="4408988706227922909">"डिभाइस फेरि हाल्नुहोस्"</string>
<string name="ext_media_move_specific_title" msgid="8492118544775964250">"<xliff:g id="NAME">%s</xliff:g> सार्दै"</string>
<string name="ext_media_move_title" msgid="2682741525619033637">"डेटा सार्दै..."</string>
<string name="ext_media_move_success_title" msgid="4901763082647316767">"सामग्री स्थानान्तरण गरियो"</string>
@@ -1926,8 +1927,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"क्षेत्रको प्राथमिकता"</string>
<string name="search_language_hint" msgid="7004225294308793583">"भाषाको नाम टाइप गर्नुहोस्"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"सिफारिस गरिएको"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"सिफारिस गरिएको"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"सम्पूर्ण भाषाहरू"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"सबै क्षेत्रहरू"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"खोज"</string>
@@ -2050,8 +2050,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> लाई डिभाइसका सबै लग हेर्ने अनुमति दिने हो?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"एक पटक प्रयोग गर्ने अनुमति दिनुहोस्"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"अनुमति नदिनुहोस्"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"डिभाइसका लगले तपाईंको डिभाइसमा भएका विभिन्न गतिविधिको अभिलेख राख्छ। एपहरू यी लगका आधारमा समस्या पत्ता लगाउन र तिनको समाधान गर्न सक्छन्।\n\nकेही लगहरूमा संवेदनशील जानकारी समावेश हुन सक्ने भएकाले आफूले भरोसा गर्ने एपलाई मात्र डिभाइसका सबै लग हेर्ने अनुमति दिनुहोस्। \n\nतपाईंले यो एपलाई डिभाइसका सबै लग हेर्ने अनुमति दिनुभएन भने पनि यसले आफ्नै लग भने हेर्न सक्छ। तपाईंको डिभाइसको उत्पादकले पनि तपाईंको डिभाइसमा भएका केही लग वा जानकारी हेर्न सक्ने सम्भावना हुन्छ।"</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"फेरि नदेखाइयोस्"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> ले <xliff:g id="APP_2">%2$s</xliff:g> का स्लाइसहरू देखाउन चाहन्छ"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"सम्पादन गर्नुहोस्"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index d041de3..46d5362 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -608,7 +608,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"Vingerafdrukbewerking geannuleerd."</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Vingerafdrukverificatie geannuleerd door gebruiker."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"Te veel pogingen. Probeer het later opnieuw."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Te veel pogingen. Vingerafdruksensor staat uit."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Te veel pogingen. Gebruik in plaats daarvan de schermvergrendeling."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Probeer het opnieuw."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Geen vingerafdrukken geregistreerd."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Dit apparaat heeft geen vingerafdruksensor."</string>
@@ -637,7 +637,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Ga naar een reparateur."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"Kan gezichtsmodel niet maken. Probeer het opnieuw."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Overbelicht. Probeer een minder felle belichting."</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"Probeer fellere verlichting"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"Houd de telefoon verder weg"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"Houd de telefoon dichterbij"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"Houd de telefoon hoger"</string>
@@ -1427,7 +1428,7 @@
<string name="ext_media_browse_action" msgid="344865351947079139">"Verkennen"</string>
<string name="ext_media_seamless_action" msgid="8837030226009268080">"Uitvoer wijzigen"</string>
<string name="ext_media_missing_title" msgid="3209472091220515046">"<xliff:g id="NAME">%s</xliff:g> ontbreekt"</string>
- <string name="ext_media_missing_message" msgid="4408988706227922909">"Voer apparaat opnieuw in"</string>
+ <string name="ext_media_missing_message" msgid="4408988706227922909">"Voer het apparaat opnieuw in"</string>
<string name="ext_media_move_specific_title" msgid="8492118544775964250">"<xliff:g id="NAME">%s</xliff:g> verplaatsen"</string>
<string name="ext_media_move_title" msgid="2682741525619033637">"Gegevens verplaatsen"</string>
<string name="ext_media_move_success_title" msgid="4901763082647316767">"Contentoverdracht is voltooid"</string>
@@ -1926,8 +1927,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"Regiovoorkeur"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Typ de naam van een taal"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"Voorgesteld"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Voorgesteld"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"Alle talen"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"Alle regio\'s"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"Zoeken"</string>
@@ -2050,8 +2050,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> toegang geven tot alle apparaatlogboeken?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"Eenmalige toegang toestaan"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Niet toestaan"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"Apparaatlogboeken leggen vast wat er op je apparaat gebeurt. Apps kunnen deze logboeken gebruiken om problemen op te sporen en te verhelpen.\n\nSommige logboeken kunnen gevoelige informatie bevatten, dus geef alleen apps die je vertrouwt toegang tot alle apparaatlogboeken. \n\nAls je deze app geen toegang tot alle apparaatlogboeken geeft, heeft de app nog wel toegang tot de eigen logboeken. De fabrikant van je apparaat heeft misschien nog steeds toegang tot bepaalde logboeken of informatie op je apparaat."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Niet opnieuw tonen"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> wil segmenten van <xliff:g id="APP_2">%2$s</xliff:g> tonen"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Bewerken"</string>
@@ -2292,7 +2291,6 @@
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Actieve apps checken"</string>
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Kan geen toegang tot de camera van de telefoon krijgen vanaf je <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Kan geen toegang tot de camera van de tablet krijgen vanaf je <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
- <!-- no translation found for vdm_secure_window (161700398158812314) -->
- <skip />
+ <string name="vdm_secure_window" msgid="161700398158812314">"Je hebt hier geen toegang toe tijdens streaming. Probeer het in plaats daarvan op je telefoon."</string>
<string name="system_locale_title" msgid="711882686834677268">"Systeemstandaard"</string>
</resources>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index c3d4eff..d15bf59 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -216,7 +216,7 @@
<string name="silent_mode" msgid="8796112363642579333">"ସାଇଲେଣ୍ଟ ମୋଡ୍"</string>
<string name="turn_on_radio" msgid="2961717788170634233">"ୱେୟାରଲେସ୍କୁ ଚାଲୁ କରନ୍ତୁ"</string>
<string name="turn_off_radio" msgid="7222573978109933360">"ୱେୟାରଲେସ୍କୁ ବନ୍ଦ କରନ୍ତୁ"</string>
- <string name="screen_lock" msgid="2072642720826409809">"ସ୍କ୍ରୀନ୍ ଲକ୍"</string>
+ <string name="screen_lock" msgid="2072642720826409809">"ସ୍କ୍ରିନ ଲକ"</string>
<string name="power_off" msgid="4111692782492232778">"ପାୱାର ବନ୍ଦ ଅଛି"</string>
<string name="silent_mode_silent" msgid="5079789070221150912">"ରିଙ୍ଗର୍ ଅଫ୍ ଅଛି"</string>
<string name="silent_mode_vibrate" msgid="8821830448369552678">"ରିଙ୍ଗର୍ କମ୍ପନ"</string>
@@ -240,7 +240,7 @@
<string name="global_actions" product="tablet" msgid="4412132498517933867">"ଟାବଲେଟ ବିକଳ୍ପ"</string>
<string name="global_actions" product="tv" msgid="3871763739487450369">"Android TVର ବିକଳ୍ପଗୁଡ଼ିକ"</string>
<string name="global_actions" product="default" msgid="6410072189971495460">"ଫୋନ ବିକଳ୍ପ"</string>
- <string name="global_action_lock" msgid="6949357274257655383">"ସ୍କ୍ରୀନ୍ ଲକ୍"</string>
+ <string name="global_action_lock" msgid="6949357274257655383">"ସ୍କ୍ରିନ ଲକ"</string>
<string name="global_action_power_off" msgid="4404936470711393203">"ପାୱାର ବନ୍ଦ ଅଛି"</string>
<string name="global_action_power_options" msgid="1185286119330160073">"ପାୱାର"</string>
<string name="global_action_restart" msgid="4678451019561687074">"ରିଷ୍ଟାର୍ଟ କରନ୍ତୁ"</string>
@@ -608,7 +608,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"ଟିପଚିହ୍ନ କାର୍ଯ୍ୟ ବାତିଲ୍ କରାଗଲା।"</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"ଉପଯୋଗକର୍ତ୍ତା ଟିପଚିହ୍ନ କାର୍ଯ୍ୟ ବାତିଲ୍ କରିଛନ୍ତି।"</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"ବହୁତ ପ୍ରୟାସ କରାଗଲା। ପରେ ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"ବହୁଥର ପ୍ରୟାସ କରିଛନ୍ତି। ଟିପଚିହ୍ନ ସେନ୍ସର୍ ଅକ୍ଷମ କରାଯାଇଛି।"</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"ଅନେକଗୁଡ଼ିଏ ପ୍ରଚେଷ୍ଟା। ଏହା ପରିବର୍ତ୍ତେ ସ୍କ୍ରିନ ଲକ ବ୍ୟବହାର କରନ୍ତୁ।"</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"କୌଣସି ଆଙ୍ଗୁଠି ଚିହ୍ନ ପଞ୍ଜୀକୃତ ହୋଇନାହିଁ।"</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ଏହି ଡିଭାଇସ୍ରେ ଟିପଚିହ୍ନ ସେନ୍ସର୍ ନାହିଁ।"</string>
@@ -637,7 +637,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"ଏକ ମରାମତି କେନ୍ଦ୍ରକୁ ଭିଜିଟ୍ କରନ୍ତୁ।"</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"ଫେସର ମଡେଲ ତିଆରି କରାଯାଇପାରିବ ନାହିଁ। ପୁଣି ଚେଷ୍ଟା କର।"</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"ଅତ୍ୟଧିକ ଉଜ୍ଵଳ। କମ୍ ଉଜ୍ବଳକରଣରେ ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"ଉଜ୍ଜ୍ୱଳ ଲାଇଟ ବ୍ୟବହାର କରି ଦେଖନ୍ତୁ"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"ଫୋନକୁ ଟିକେ ଦୂରକୁ ନିଅନ୍ତୁ"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"ଫୋନକୁ ପାଖକୁ ଆଣନ୍ତୁ"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"ଫୋନକୁ ଉପରକୁ ମୁଭ କରନ୍ତୁ"</string>
@@ -1926,8 +1927,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"ପସନ୍ଦର ଅଞ୍ଚଳ"</string>
<string name="search_language_hint" msgid="7004225294308793583">"ଭାଷାର ନାମ ଟାଇପ୍ କରନ୍ତୁ"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"ପ୍ରସ୍ତାବିତ"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"ପ୍ରସ୍ତାବିତ"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"ସମସ୍ତ ଭାଷା"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"ସମସ୍ତ ଅଞ୍ଚଳ"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"ସନ୍ଧାନ କରନ୍ତୁ"</string>
@@ -2044,14 +2044,13 @@
<string name="shortcut_restore_signature_mismatch" msgid="579345304221605479">"ଶର୍ଟକଟ୍ ରିଷ୍ଟୋର୍ କରିହେଲା ନାହିଁ, କାରଣ ଏହି ଆପ୍ର ସ୍ୱାକ୍ଷର ମେଳ ହେଉନାହିଁ"</string>
<string name="shortcut_restore_unknown_issue" msgid="2478146134395982154">"ଶର୍ଟକଟ୍ ରିଷ୍ଟୋର୍ କରିହେଲା ନାହିଁ"</string>
<string name="shortcut_disabled_reason_unknown" msgid="753074793553599166">"ଶର୍ଟକଟ୍ ଅକ୍ଷମ କରାଯାଇଛି"</string>
- <string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"ଅନଇନଷ୍ଟଲ୍ କରନ୍ତୁ"</string>
+ <string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"ଅନଇନଷ୍ଟଲ କରନ୍ତୁ"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"କୌଣସିମତେ ଖୋଲନ୍ତୁ"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"ହାନିକାରକ ଆପ୍ ଚିହ୍ନଟ ହୋଇଛି"</string>
<string name="log_access_confirmation_title" msgid="2343578467290592708">"ସମସ୍ତ ଡିଭାଇସ ଲଗକୁ ଆକ୍ସେସ କରିବା ପାଇଁ <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g>କୁ ଅନୁମତି ଦେବେ?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"ଗୋଟିଏ-ଥର ଆକ୍ସେସ ପାଇଁ ଅନୁମତି ଦିଅନ୍ତୁ"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"ଅନୁମତି ଦିଅନ୍ତୁ ନାହିଁ"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"ଆପଣଙ୍କ ଡିଭାଇସରେ ଯାହା ହୁଏ ତାହା ଡିଭାଇସ ଲଗଗୁଡ଼ିକ ରେକର୍ଡ କରେ। ସମସ୍ୟାଗୁଡ଼ିକୁ ଖୋଜି ସମାଧାନ କରିବାକୁ ଆପ୍ସ ଏହି ଲଗଗୁଡ଼ିକୁ ବ୍ୟବହାର କରିପାରିବ।\n\nକିଛି ଲଗରେ ସମ୍ବେଦନଶୀଳ ସୂଚନା ଥାଇପାରେ, ତେଣୁ ସମସ୍ତ ଡିଭାଇସ ଲଗକୁ ଆକ୍ସେସ କରିବା ପାଇଁ ଆପଣ ବିଶ୍ୱାସ କରୁଥିବା ଆପ୍ସକୁ ହିଁ ଅନୁମତି ଦିଅନ୍ତୁ। \n\nଯଦି ଆପଣ ସମସ୍ତ ଡିଭାଇସ ଲଗକୁ ଆକ୍ସେସ କରିବା ପାଇଁ ଏହି ଆପକୁ ଅନୁମତି ଦିଅନ୍ତି ନାହିଁ, ତେବେ ବି ଏହା ନିଜର ଡିଭାଇସ ଲଗଗୁଡ଼ିକୁ ଆକ୍ସେସ କରିପାରିବ। ଆପଣଙ୍କ ଡିଭାଇସର ନିର୍ମାତା ଏବେ ବି ଆପଣଙ୍କର ଡିଭାଇସରେ କିଛି ଲଗ କିମ୍ବା ସୂଚନାକୁ ଆକ୍ସେସ କରିବା ପାଇଁ ସକ୍ଷମ ହୋଇପାରନ୍ତି।"</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"ପୁଣି ଦେଖାନ୍ତୁ ନାହିଁ"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g>, <xliff:g id="APP_2">%2$s</xliff:g> ସ୍ଲାଇସ୍କୁ ଦେଖାଇବା ପାଇଁ ଚାହେଁ"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"ଏଡିଟ କରନ୍ତୁ"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index c66f23da..c3d5569 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -608,7 +608,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਓਪਰੇਸ਼ਨ ਰੱਦ ਕੀਤਾ ਗਿਆ।"</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਓਪਰੇਸ਼ਨ ਵਰਤੋਂਕਾਰ ਵੱਲੋਂ ਰੱਦ ਕੀਤਾ ਗਿਆ।"</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"ਬਹੁਤ ਸਾਰੀਆਂ ਕੋਸ਼ਿਸ਼ਾਂ. ਬਾਅਦ ਵਿੱਚ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"ਹੱਦੋਂ ਵੱਧ ਕੋਸ਼ਿਸ਼ਾਂ। ਫਿੰਗਰਪ੍ਰਿੰਟ ਸੈਂਸਰ ਅਯੋਗ ਬਣਾਇਆ ਗਿਆ।"</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"ਬਹੁਤ ਸਾਰੀਆਂ ਕੋਸ਼ਿਸ਼ਾਂ। ਇਸਦੀ ਬਜਾਏ ਸਕ੍ਰੀਨ ਲਾਕ ਵਰਤੋ।"</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"ਕੋਈ ਫਿੰਗਰਪ੍ਰਿੰਟ ਦਰਜ ਨਹੀਂ ਕੀਤੇ ਗਏ।"</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ਇਸ ਡੀਵਾਈਸ ਵਿੱਚ ਫਿੰਗਰਪ੍ਰਿੰਟ ਸੈਂਸਰ ਨਹੀਂ ਹੈ।"</string>
@@ -637,7 +637,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"ਮੁਰੰਮਤ ਪ੍ਰਦਾਨਕ \'ਤੇ ਜਾਓ।"</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"ਤੁਹਾਡੇ ਚਿਹਰੇ ਦਾ ਮਾਡਲ ਨਹੀਂ ਬਣਿਆ। ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"ਬਹੁਤ ਜ਼ਿਆਦਾ ਚਮਕ। ਹਲਕੀ ਚਮਕ ਵਰਤ ਕੇ ਦੇਖੋ।"</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"ਤੇਜ਼ ਰੋਸ਼ਨੀ ਕਰ ਕੇ ਦੇਖੋ"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"ਫ਼ੋਨ ਨੂੰ ਦੂਰ ਲਿਜਾਓ"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"ਫ਼ੋਨ ਨੇੜੇ ਲਿਜਾਓ"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"ਫ਼ੋਨ ਨੂੰ ਥੋੜ੍ਹਾ ਉੱਤੇ ਲਿਜਾਓ"</string>
@@ -1926,8 +1927,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"ਖੇਤਰ ਤਰਜੀਹ"</string>
<string name="search_language_hint" msgid="7004225294308793583">"ਭਾਸ਼ਾ ਦਾ ਨਾਮ ਟਾਈਪ ਕਰੋ"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"ਸੁਝਾਈਆਂ ਗਈਆਂ"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"ਸੁਝਾਈਆਂ ਗਈਆਂ"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"ਸਾਰੀਆਂ ਭਾਸ਼ਾਵਾਂ"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"ਸਾਰੇ ਖੇਤਰ"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"ਖੋਜੋ"</string>
@@ -2050,8 +2050,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"ਕੀ <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> ਨੂੰ ਸਾਰੇ ਡੀਵਾਈਸ ਲੌਗਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਆਗਿਆ ਦੇਣੀ ਹੈ?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"ਇੱਕ-ਵਾਰ ਲਈ ਪਹੁੰਚ ਦੀ ਆਗਿਆ ਦਿਓ"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"ਆਗਿਆ ਨਾ ਦਿਓ"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"ਡੀਵਾਈਸ ਲੌਗਾਂ ਵਿੱਚ ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਦੀਆਂ ਕਾਰਵਾਈਆਂ ਰਿਕਾਰਡ ਹੁੰਦੀਆਂ ਹਨ। ਐਪਾਂ ਸਮੱਸਿਆਵਾਂ ਨੂੰ ਲੱਭਣ ਅਤੇ ਉਨ੍ਹਾਂ ਦਾ ਹੱਲ ਕਰਨ ਲਈ ਇਨ੍ਹਾਂ ਲੌਗਾਂ ਦੀ ਵਰਤੋਂ ਕਰ ਸਕਦੀਆਂ ਹਨ।\n\nਕੁਝ ਲੌਗਾਂ ਵਿੱਚ ਸੰਵੇਦਨਸ਼ੀਲ ਜਾਣਕਾਰੀ ਸ਼ਾਮਲ ਹੋ ਸਕਦੀ ਹੈ, ਇਸ ਲਈ ਸਿਰਫ਼ ਆਪਣੀਆਂ ਭਰੋਸੇਯੋਗ ਐਪਾਂ ਨੂੰ ਹੀ ਸਾਰੇ ਡੀਵਾਈਸ ਲੌਗਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿਓ। \n\nਜੇ ਤੁਸੀਂ ਇਸ ਐਪ ਨੂੰ ਸਾਰੇ ਡੀਵਾਈਸ ਲੌਗਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਆਗਿਆ ਨਹੀਂ ਦਿੰਦੇ ਹੋ, ਤਾਂ ਇਹ ਹਾਲੇ ਵੀ ਆਪਣੇ ਲੌਗਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰ ਸਕਦੀ ਹੈ। ਤੁਹਾਡਾ ਡੀਵਾਈਸ ਨਿਰਮਾਤਾ ਹਾਲੇ ਵੀ ਤੁਹਾਡੇ ਡੀਵਾਈਸ \'ਤੇ ਮੌਜੂਦ ਕੁਝ ਲੌਗਾਂ ਜਾਂ ਜਾਣਕਾਰੀ ਤੱਕ ਪਹੁੰਚ ਕਰ ਸਕਦਾ ਹੈ।"</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"ਦੁਬਾਰਾ ਨਾ ਦਿਖਾਓ"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> ਦੀ <xliff:g id="APP_2">%2$s</xliff:g> ਦੇ ਹਿੱਸੇ ਦਿਖਾਉਣ ਦੀ ਇੱਛਾ ਹੈ"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"ਸੰਪਾਦਨ ਕਰੋ"</string>
@@ -2292,7 +2291,6 @@
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"ਕਿਰਿਆਸ਼ੀਲ ਐਪਾਂ ਦੀ ਜਾਂਚ ਕਰੋ"</string>
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"ਤੁਹਾਡੇ <xliff:g id="DEVICE">%1$s</xliff:g> ਤੋਂ ਫ਼ੋਨ ਦੇ ਕੈਮਰੇ ਤੱਕ ਪਹੁੰਚ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"ਤੁਹਾਡੇ <xliff:g id="DEVICE">%1$s</xliff:g> ਤੋਂ ਟੈਬਲੈੱਟ ਦੇ ਕੈਮਰੇ ਤੱਕ ਪਹੁੰਚ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ"</string>
- <!-- no translation found for vdm_secure_window (161700398158812314) -->
- <skip />
+ <string name="vdm_secure_window" msgid="161700398158812314">"ਸਟ੍ਰੀਮਿੰਗ ਦੌਰਾਨ ਇਸ ਤੱਕ ਪਹੁੰਚ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ। ਇਸਦੀ ਬਜਾਏ ਆਪਣੇ ਫ਼ੋਨ \'ਤੇ ਵਰਤ ਕੇ ਦੇਖੋ।"</string>
<string name="system_locale_title" msgid="711882686834677268">"ਸਿਸਟਮ ਪੂਰਵ-ਨਿਰਧਾਰਿਤ"</string>
</resources>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index fd7d94a..04ee1a6 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -610,7 +610,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"Odczyt odcisku palca został anulowany."</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Odczyt odcisku palca został anulowany przez użytkownika."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"Zbyt wiele prób. Spróbuj ponownie później."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Zbyt wiele prób. Czytnik linii papilarnych został wyłączony."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Zbyt wiele prób. Użyj blokady ekranu."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Spróbuj ponownie."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nie zarejestrowano odcisków palców."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"To urządzenie nie jest wyposażone w czytnik linii papilarnych."</string>
@@ -639,7 +639,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Odwiedź serwis."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"Nie można utworzyć modelu twarzy. Spróbuj ponownie."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Zbyt jasno. Spróbuj przy słabszym świetle."</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"Spróbuj w jaśniejszym świetle"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"Odsuń telefon"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"Przybliż telefon"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"Przesuń telefon wyżej"</string>
@@ -1928,8 +1929,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"Ustawienie regionu"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Wpisz nazwę języka"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"Sugerowane"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Sugerowane"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"Wszystkie języki"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"Wszystkie kraje"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"Szukaj"</string>
@@ -2052,8 +2052,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Zezwolić aplikacji <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> na dostęp do wszystkich dzienników urządzenia?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"Zezwól na jednorazowy dostęp"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Nie zezwalaj"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"Dzienniki urządzenia zapisują, co dzieje się na urządzeniu. Aplikacje mogą ich używać do wykrywania i rozwiązywania problemów.\n\nNiektóre dzienniki mogą zawierać poufne dane, dlatego na dostęp do wszystkich dzienników zezwalaj tylko aplikacjom, którym ufasz. \n\nNawet jeśli nie zezwolisz tej aplikacji na dostęp do wszystkich dzienników na urządzeniu, będzie mogła korzystać z własnych. Producent urządzenia nadal będzie mógł używać niektórych dzienników na urządzeniu."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Nie pokazuj ponownie"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"Aplikacja <xliff:g id="APP_0">%1$s</xliff:g> chce pokazywać wycinki z aplikacji <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Edytuj"</string>
@@ -2294,7 +2293,6 @@
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Sprawdź aktywne aplikacje"</string>
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Nie można korzystać z aparatu telefonu na urządzeniu <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Nie można korzystać z aparatu tabletu na urządzeniu <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
- <!-- no translation found for vdm_secure_window (161700398158812314) -->
- <skip />
+ <string name="vdm_secure_window" msgid="161700398158812314">"Nie można z tego skorzystać podczas strumieniowania. Użyj telefonu."</string>
<string name="system_locale_title" msgid="711882686834677268">"Ustawienie domyślne systemu"</string>
</resources>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 9eb1e5d..283db53 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -52,6 +52,7 @@
<string name="enablePin" msgid="2543771964137091212">"Falha. Ative o bloqueio do chip/R-UIM."</string>
<plurals name="pinpuk_attempts" formatted="false" msgid="1619867269012213584">
<item quantity="one">Tentativas restantes: <xliff:g id="NUMBER_1">%d</xliff:g>. Caso o código correto não seja digitado, o chip será bloqueado.</item>
+ <item quantity="many">You have <xliff:g id="NUMBER_1">%d</xliff:g> remaining attempts before SIM is locked.</item>
<item quantity="other">Tentativas restantes: <xliff:g id="NUMBER_1">%d</xliff:g>. Caso o código correto não seja digitado, o chip será bloqueado.</item>
</plurals>
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
@@ -180,7 +181,7 @@
<string name="low_memory" product="watch" msgid="3479447988234030194">"Armazenamento do relógio cheio. Exclua alguns arquivos para liberar espaço."</string>
<string name="low_memory" product="tv" msgid="6663680413790323318">"O armazenamento do dispositivo Android TV está cheio. Exclua alguns arquivos para liberar espaço."</string>
<string name="low_memory" product="default" msgid="2539532364144025569">"O armazenamento do telefone está cheio. Exclua alguns arquivos para liberar espaço."</string>
- <string name="ssl_ca_cert_warning" msgid="7233573909730048571">"{count,plural, =1{Autoridade certificadora instalada}one{Autoridade certificadora instalada}other{Autoridades certificadoras instaladas}}"</string>
+ <string name="ssl_ca_cert_warning" msgid="7233573909730048571">"{count,plural, =1{Autoridade certificadora instalada}one{Autoridade certificadora instalada}many{Autoridades certificadoras instaladas}other{Autoridades certificadoras instaladas}}"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4961102218216815242">"Por terceiros desconhecidos"</string>
<string name="ssl_ca_cert_noti_by_administrator" msgid="4564941950768783879">"Pelo administrador do seu perfil de trabalho"</string>
<string name="ssl_ca_cert_noti_managed" msgid="217337232273211674">"Por <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
@@ -254,7 +255,7 @@
<string name="bugreport_option_interactive_summary" msgid="8493795476325339542">"Use este recurso na maioria das circunstâncias. Ele permite que você acompanhe o progresso do relatório, informe mais detalhes sobre o problema e faça capturas de tela. É possível que ele omita algumas seções menos utilizadas que levam muito tempo na emissão dos relatórios."</string>
<string name="bugreport_option_full_title" msgid="7681035745950045690">"Relatório completo"</string>
<string name="bugreport_option_full_summary" msgid="1975130009258435885">"Use esta opção para ter o mínimo de interferência do sistema quando seu dispositivo não estiver respondendo ou estiver muito lento, ou quando você precisar de todas as seções de relatórios. Ela não permite que você informe mais detalhes ou faça capturas de tela adicionais."</string>
- <string name="bugreport_countdown" msgid="6418620521782120755">"{count,plural, =1{Capturas de tela para o relatório do bug vão ser feitas em # segundo.}one{Capturas de tela para o relatório do bug vão ser feitas em # segundo.}other{Capturas de tela para o relatório do bug vão ser feitas em # segundos.}}"</string>
+ <string name="bugreport_countdown" msgid="6418620521782120755">"{count,plural, =1{Capturas de tela para o relatório do bug vão ser feitas em # segundo.}one{Capturas de tela para o relatório do bug vão ser feitas em # segundo.}many{Capturas de tela para o relatório do bug vão ser feitas em # segundos.}other{Capturas de tela para o relatório do bug vão ser feitas em # segundos.}}"</string>
<string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Captura de tela com o relatório do bug concluída"</string>
<string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Falha ao capturar a tela com o relatório do bug"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Modo silencioso"</string>
@@ -608,7 +609,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"Operação de impressão digital cancelada."</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Operação de impressão digital cancelada pelo usuário."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"Excesso de tentativas. Tente novamente mais tarde."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Excesso de tentativas. Sensor de impressão digital desativado."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Excesso de tentativas. Use o bloqueio de tela."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Tente novamente."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nenhuma impressão digital registrada."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Este dispositivo não tem um sensor de impressão digital."</string>
@@ -637,7 +638,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Entre em contato com uma assistência técnica."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"Falha ao criar o modelo de rosto. Tente de novo."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Muito iluminado. Diminua a iluminação."</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"Use uma iluminação mais intensa"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"Afaste o smartphone"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"Aproxime o smartphone do seu rosto"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"Mova o smartphone para cima"</string>
@@ -1087,7 +1089,7 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="4312979647356179250">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> quer ativar o Explorar por toque. Com ele, você pode ouvir ou ver descrições do que está sob seu dedo e interagir com o telefone por gestos."</string>
<string name="oneMonthDurationPast" msgid="4538030857114635777">"1 mês atrás"</string>
<string name="beforeOneMonthDurationPast" msgid="8315149541372065392">"Antes de 1 mês atrás"</string>
- <string name="last_num_days" msgid="2393660431490280537">"{count,plural, =1{No último # dia}one{No último # dia}other{Nos últimos # dias}}"</string>
+ <string name="last_num_days" msgid="2393660431490280537">"{count,plural, =1{No último # dia}one{No último # dia}many{Nos últimos # dias}other{Nos últimos # dias}}"</string>
<string name="last_month" msgid="1528906781083518683">"Mês passado"</string>
<string name="older" msgid="1645159827884647400">"Mais antigos"</string>
<string name="preposition_for_date" msgid="2780767868832729599">"em <xliff:g id="DATE">%s</xliff:g>"</string>
@@ -1114,14 +1116,14 @@
<string name="duration_hours_shortest_future" msgid="2979276794547981674">"em <xliff:g id="COUNT">%d</xliff:g>h"</string>
<string name="duration_days_shortest_future" msgid="3392722163935571543">"em <xliff:g id="COUNT">%d</xliff:g> dias"</string>
<string name="duration_years_shortest_future" msgid="5537464088352970388">"em <xliff:g id="COUNT">%d</xliff:g>a"</string>
- <string name="duration_minutes_relative" msgid="8620337701051015593">"{count,plural, =1{# minuto atrás}one{# minuto atrás}other{# minutos atrás}}"</string>
- <string name="duration_hours_relative" msgid="4836449961693180253">"{count,plural, =1{# hora atrás}one{# hora atrás}other{# horas atrás}}"</string>
- <string name="duration_days_relative" msgid="621965767567258302">"{count,plural, =1{# dia atrás}one{# dia atrás}other{# dias atrás}}"</string>
- <string name="duration_years_relative" msgid="8731202348869424370">"{count,plural, =1{# ano atrás}one{# ano atrás}other{# anos atrás}}"</string>
- <string name="duration_minutes_relative_future" msgid="5259574171747708115">"{count,plural, =1{# minuto}one{# minuto}other{# minutos}}"</string>
- <string name="duration_hours_relative_future" msgid="6670440478481140565">"{count,plural, =1{# hora}one{# hora}other{# horas}}"</string>
- <string name="duration_days_relative_future" msgid="8870658635774250746">"{count,plural, =1{# dia}one{# dia}other{# dias}}"</string>
- <string name="duration_years_relative_future" msgid="8855853883925918380">"{count,plural, =1{# ano}one{# ano}other{# anos}}"</string>
+ <string name="duration_minutes_relative" msgid="8620337701051015593">"{count,plural, =1{# minuto atrás}one{# minuto atrás}many{# minutos atrás}other{# minutos atrás}}"</string>
+ <string name="duration_hours_relative" msgid="4836449961693180253">"{count,plural, =1{# hora atrás}one{# hora atrás}many{# horas atrás}other{# horas atrás}}"</string>
+ <string name="duration_days_relative" msgid="621965767567258302">"{count,plural, =1{# dia atrás}one{# dia atrás}many{# dias atrás}other{# dias atrás}}"</string>
+ <string name="duration_years_relative" msgid="8731202348869424370">"{count,plural, =1{# ano atrás}one{# ano atrás}many{# anos atrás}other{# anos atrás}}"</string>
+ <string name="duration_minutes_relative_future" msgid="5259574171747708115">"{count,plural, =1{# minuto}one{# minuto}many{# minutos}other{# minutos}}"</string>
+ <string name="duration_hours_relative_future" msgid="6670440478481140565">"{count,plural, =1{# hora}one{# hora}many{# horas}other{# horas}}"</string>
+ <string name="duration_days_relative_future" msgid="8870658635774250746">"{count,plural, =1{# dia}one{# dia}many{# dias}other{# dias}}"</string>
+ <string name="duration_years_relative_future" msgid="8855853883925918380">"{count,plural, =1{# ano}one{# ano}many{# anos}other{# anos}}"</string>
<string name="VideoView_error_title" msgid="5750686717225068016">"Problema com o vídeo"</string>
<string name="VideoView_error_text_invalid_progressive_playback" msgid="3782449246085134720">"Este vídeo não é válido para transmissão neste dispositivo."</string>
<string name="VideoView_error_text_unknown" msgid="7658683339707607138">"Não é possível reproduzir este vídeo."</string>
@@ -1508,7 +1510,7 @@
<string name="skip_button_label" msgid="3566599811326688389">"Pular"</string>
<string name="no_matches" msgid="6472699895759164599">"Não encontrado"</string>
<string name="find_on_page" msgid="5400537367077438198">"Localizar na página"</string>
- <string name="matches_found" msgid="2296462299979507689">"{count,plural, =1{# correspondência}one{# de {total}}other{# de {total}}}"</string>
+ <string name="matches_found" msgid="2296462299979507689">"{count,plural, =1{# correspondência}one{# de {total}}many{# de {total}}other{# de {total}}}"</string>
<string name="action_mode_done" msgid="2536182504764803222">"Concluído"</string>
<string name="progress_erasing" msgid="6891435992721028004">"Limpando armazenamento compartilhado…"</string>
<string name="share" msgid="4157615043345227321">"Compartilhar"</string>
@@ -1861,14 +1863,14 @@
<string name="data_saver_description" msgid="4995164271550590517">"Para ajudar a reduzir o uso de dados, a Economia de dados impede que alguns apps enviem ou recebam dados em segundo plano. Um app que você está usando no momento pode acessar dados, mas com menos frequência. Isso pode fazer com que imagens não apareçam até você tocar nelas."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Ativar a Economia de dados?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Ativar"</string>
- <string name="zen_mode_duration_minutes_summary" msgid="4555514757230849789">"{count,plural, =1{Por um minuto (até {formattedTime})}one{Por # minuto (até {formattedTime})}other{Por # minutos (até {formattedTime})}}"</string>
- <string name="zen_mode_duration_minutes_summary_short" msgid="1187553788355486950">"{count,plural, =1{Por 1min (até {formattedTime})}one{Por #min (até {formattedTime})}other{Por #min (até {formattedTime})}}"</string>
- <string name="zen_mode_duration_hours_summary" msgid="3866333100793277211">"{count,plural, =1{Por 1 hora (até {formattedTime})}one{Por # hora (até {formattedTime})}other{Por # horas (até {formattedTime})}}"</string>
- <string name="zen_mode_duration_hours_summary_short" msgid="687919813833347945">"{count,plural, =1{Por 1h (até {formattedTime})}one{Por #h (até {formattedTime})}other{Por #h (até {formattedTime})}}"</string>
- <string name="zen_mode_duration_minutes" msgid="2340007982276569054">"{count,plural, =1{Por um minuto}one{Por # minuto}other{Por # minutos}}"</string>
- <string name="zen_mode_duration_minutes_short" msgid="2435756450204526554">"{count,plural, =1{Por 1min}one{Por #min}other{Por #min}}"</string>
- <string name="zen_mode_duration_hours" msgid="7841806065034711849">"{count,plural, =1{Por 1 hora}one{Por # hora}other{Por # horas}}"</string>
- <string name="zen_mode_duration_hours_short" msgid="3666949653933099065">"{count,plural, =1{Por 1h}one{Por #h}other{Por #h}}"</string>
+ <string name="zen_mode_duration_minutes_summary" msgid="4555514757230849789">"{count,plural, =1{Por um minuto (até {formattedTime})}one{Por # minuto (até {formattedTime})}many{Por # minutos (até {formattedTime})}other{Por # minutos (até {formattedTime})}}"</string>
+ <string name="zen_mode_duration_minutes_summary_short" msgid="1187553788355486950">"{count,plural, =1{Por 1min (até {formattedTime})}one{Por #min (até {formattedTime})}many{Por #min (até {formattedTime})}other{Por #min (até {formattedTime})}}"</string>
+ <string name="zen_mode_duration_hours_summary" msgid="3866333100793277211">"{count,plural, =1{Por 1 hora (até {formattedTime})}one{Por # hora (até {formattedTime})}many{Por # horas (até {formattedTime})}other{Por # horas (até {formattedTime})}}"</string>
+ <string name="zen_mode_duration_hours_summary_short" msgid="687919813833347945">"{count,plural, =1{Por 1h (até {formattedTime})}one{Por #h (até {formattedTime})}many{Por #h (até {formattedTime})}other{Por #h (até {formattedTime})}}"</string>
+ <string name="zen_mode_duration_minutes" msgid="2340007982276569054">"{count,plural, =1{Por um minuto}one{Por # minuto}many{Por # minutos}other{Por # minutos}}"</string>
+ <string name="zen_mode_duration_minutes_short" msgid="2435756450204526554">"{count,plural, =1{Por 1min}one{Por #min}many{Por #min}other{Por #min}}"</string>
+ <string name="zen_mode_duration_hours" msgid="7841806065034711849">"{count,plural, =1{Por 1 hora}one{Por # hora}many{Por # horas}other{Por # horas}}"</string>
+ <string name="zen_mode_duration_hours_short" msgid="3666949653933099065">"{count,plural, =1{Por 1h}one{Por #h}many{Por #h}other{Por #h}}"</string>
<string name="zen_mode_until_next_day" msgid="1403042784161725038">"Até <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
<string name="zen_mode_until" msgid="2250286190237669079">"Até às <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
<string name="zen_mode_alarm" msgid="7046911727540499275">"Até <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (próximo alarme)"</string>
@@ -1926,8 +1928,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"Preferência de região"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Digitar nome do idioma"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"Sugeridos"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Sugestões"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"Todos os idiomas"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"Todas as regiões"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"Pesquisa"</string>
@@ -2000,7 +2001,7 @@
<string name="autofill_save_accessibility_title" msgid="1523225776218450005">"Salvar no Preenchimento automático"</string>
<string name="autofill_error_cannot_autofill" msgid="6528827648643138596">"Não é possível preencher os conteúdos automaticamente"</string>
<string name="autofill_picker_no_suggestions" msgid="1076022650427481509">"Sem sugestões de preenchimento automático"</string>
- <string name="autofill_picker_some_suggestions" msgid="5560549696296202701">"{count,plural, =1{Uma sugestão de preenchimento automático}one{# sugestão de preenchimento automático}other{# sugestões de preenchimento automático}}"</string>
+ <string name="autofill_picker_some_suggestions" msgid="5560549696296202701">"{count,plural, =1{Uma sugestão de preenchimento automático}one{# sugestão de preenchimento automático}many{# sugestões de preenchimento automático}other{# sugestões de preenchimento automático}}"</string>
<string name="autofill_save_title" msgid="7719802414283739775">"Salvar em "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"?"</string>
<string name="autofill_save_title_with_type" msgid="3002460014579799605">"Salvar <xliff:g id="TYPE">%1$s</xliff:g> em "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"?"</string>
<string name="autofill_save_title_with_2types" msgid="3783270967447869241">"Salvar <xliff:g id="TYPE_0">%1$s</xliff:g> e <xliff:g id="TYPE_1">%2$s</xliff:g> em "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"?"</string>
@@ -2050,8 +2051,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Permitir que o app <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> acesse todos os registros do dispositivo?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"Permitir o acesso único"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Não permitir"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"Os registros do dispositivo gravam o que acontece nele. Os apps podem usar esses registros para encontrar e corrigir problemas.\n\nAlguns registros podem conter informações sensíveis, então autorize o acesso a eles apenas para os apps em que você confia. \n\nSe você não permitir que esse app acesse todos os registros do dispositivo, ele ainda vai poder acessar os próprios. O fabricante do dispositivo também pode ter acesso a alguns registros ou informações."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Não mostrar novamente"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> quer mostrar partes do app <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Editar"</string>
@@ -2111,7 +2111,7 @@
<string name="mime_type_presentation_ext" msgid="8761049335564371468">"Apresentação em <xliff:g id="EXTENSION">%1$s</xliff:g>"</string>
<string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"O Bluetooth permanecerá ativado no modo avião"</string>
<string name="car_loading_profile" msgid="8219978381196748070">"Carregando"</string>
- <string name="file_count" msgid="3220018595056126969">"{count,plural, =1{{file_name} + # arquivo}one{{file_name} + # arquivo}other{{file_name} + # arquivos}}"</string>
+ <string name="file_count" msgid="3220018595056126969">"{count,plural, =1{{file_name} + # arquivo}one{{file_name} + # arquivo}many{{file_name} + # arquivos}other{{file_name} + # arquivos}}"</string>
<string name="chooser_no_direct_share_targets" msgid="1511722103987329028">"Não há sugestões de pessoas para compartilhar"</string>
<string name="chooser_all_apps_button_label" msgid="3230427756238666328">"Lista de apps"</string>
<string name="usb_device_resolve_prompt_warn" msgid="325871329788064199">"Este app não tem permissão de gravação, mas pode capturar áudio pelo dispositivo USB."</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index fb27e5f..fe12782 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -51,6 +51,7 @@
<string name="needPuk2" msgid="7032612093451537186">"Introduza o PUK2 para desbloquear o cartão SIM."</string>
<string name="enablePin" msgid="2543771964137091212">"Ação sem êxito. Ative o bloqueio do SIM/RUIM."</string>
<plurals name="pinpuk_attempts" formatted="false" msgid="1619867269012213584">
+ <item quantity="many">You have <xliff:g id="NUMBER_1">%d</xliff:g> remaining attempts before SIM is locked.</item>
<item quantity="other">Tem mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas antes de o cartão SIM ficar bloqueado.</item>
<item quantity="one">Tem mais <xliff:g id="NUMBER_0">%d</xliff:g> tentativa antes de o cartão SIM ficar bloqueado.</item>
</plurals>
@@ -180,7 +181,7 @@
<string name="low_memory" product="watch" msgid="3479447988234030194">"O armazenamento de visualizações está cheio. Elimine alguns ficheiros para libertar espaço."</string>
<string name="low_memory" product="tv" msgid="6663680413790323318">"O armazenamento do dispositivo Android TV está cheio. Elimine alguns ficheiros para libertar espaço."</string>
<string name="low_memory" product="default" msgid="2539532364144025569">"O armazenamento do telemóvel está cheio. Elimine alguns ficheiros para libertar espaço."</string>
- <string name="ssl_ca_cert_warning" msgid="7233573909730048571">"{count,plural, =1{Autoridade de certificação instalada}other{Autoridades de certificação instaladas}}"</string>
+ <string name="ssl_ca_cert_warning" msgid="7233573909730048571">"{count,plural, =1{Autoridade de certificação instalada}many{Autoridades de certificação instaladas}other{Autoridades de certificação instaladas}}"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4961102218216815242">"Por um terceiro desconhecido"</string>
<string name="ssl_ca_cert_noti_by_administrator" msgid="4564941950768783879">"Pelo gestor do seu perfil de trabalho"</string>
<string name="ssl_ca_cert_noti_managed" msgid="217337232273211674">"Por <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
@@ -254,7 +255,7 @@
<string name="bugreport_option_interactive_summary" msgid="8493795476325339542">"Utilize esta opção na maioria das circunstâncias. Permite monitorizar o progresso do relatório, introduzir mais detalhes acerca do problema e tirar capturas de ecrã. Pode omitir algumas secções menos utilizadas que demoram muito tempo a comunicar."</string>
<string name="bugreport_option_full_title" msgid="7681035745950045690">"Relatório completo"</string>
<string name="bugreport_option_full_summary" msgid="1975130009258435885">"Utilize esta opção para uma interferência mínima do sistema quando o dispositivo não responder ou estiver demasiado lento, ou quando precisar de todas as secções de relatório. Não permite introduzir mais detalhes ou tirar capturas de ecrã adicionais."</string>
- <string name="bugreport_countdown" msgid="6418620521782120755">"{count,plural, =1{A fazer uma captura de ecrã do relatório de erro dentro de # segundo.}other{A fazer uma captura de ecrã do relatório de erro dentro de # segundos.}}"</string>
+ <string name="bugreport_countdown" msgid="6418620521782120755">"{count,plural, =1{A fazer uma captura de ecrã do relatório de erro dentro de # segundo.}many{A fazer uma captura de ecrã do relatório de erro dentro de # segundos.}other{A fazer uma captura de ecrã do relatório de erro dentro de # segundos.}}"</string>
<string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Captura de ecrã tirada com o relatório de erro."</string>
<string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Falha ao fazer captura de ecrã com o relatório de erro."</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Modo silencioso"</string>
@@ -608,7 +609,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"Operação de impressão digital cancelada."</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Operação de impressão digital cancelada pelo utilizador."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"Demasiadas tentativas. Tente novamente mais tarde."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Demasiadas tentativas. Sensor de impressões digitais desativado."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Demasiadas tentativas. Em alternativa, use o bloqueio de ecrã."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Tente novamente."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nenhuma impressão digital registada."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Este dispositivo não tem sensor de impressões digitais."</string>
@@ -637,7 +638,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Visite um fornecedor de serviços de reparação."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"Impossível criar modelo de rosto. Tente novamente."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Demasiado clara. Experimente uma luz mais suave."</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"Experimente um local com mais luz"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"Afaste ainda mais o telemóvel"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"Aproxime o telemóvel do rosto"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"Mova o telemóvel mais para cima"</string>
@@ -1087,7 +1089,7 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="4312979647356179250">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> pretende ativar a funcionalidade Explorar Através do Toque. Quando a funcionalidade Explorar Através do Toque estiver ativada, pode ouvir ou visualizar descrições sobre o que está por baixo do seu dedo ou executar gestos para interagir com o telemóvel."</string>
<string name="oneMonthDurationPast" msgid="4538030857114635777">"Há 1 mês"</string>
<string name="beforeOneMonthDurationPast" msgid="8315149541372065392">"Há mais de 1 mês"</string>
- <string name="last_num_days" msgid="2393660431490280537">"{count,plural, =1{# dia anterior}other{# dias anteriores}}"</string>
+ <string name="last_num_days" msgid="2393660431490280537">"{count,plural, =1{# dia anterior}many{# dias anteriores}other{# dias anteriores}}"</string>
<string name="last_month" msgid="1528906781083518683">"Último mês"</string>
<string name="older" msgid="1645159827884647400">"Mais antiga"</string>
<string name="preposition_for_date" msgid="2780767868832729599">"a <xliff:g id="DATE">%s</xliff:g>"</string>
@@ -1114,14 +1116,14 @@
<string name="duration_hours_shortest_future" msgid="2979276794547981674">"em <xliff:g id="COUNT">%d</xliff:g> h"</string>
<string name="duration_days_shortest_future" msgid="3392722163935571543">"em <xliff:g id="COUNT">%d</xliff:g> d"</string>
<string name="duration_years_shortest_future" msgid="5537464088352970388">"em <xliff:g id="COUNT">%d</xliff:g> a"</string>
- <string name="duration_minutes_relative" msgid="8620337701051015593">"{count,plural, =1{Há # minuto}other{Há # minutos}}"</string>
- <string name="duration_hours_relative" msgid="4836449961693180253">"{count,plural, =1{Há # hora}other{Há # horas}}"</string>
- <string name="duration_days_relative" msgid="621965767567258302">"{count,plural, =1{Há # dia}other{Há # dias}}"</string>
- <string name="duration_years_relative" msgid="8731202348869424370">"{count,plural, =1{Há # ano}other{Há # anos}}"</string>
- <string name="duration_minutes_relative_future" msgid="5259574171747708115">"{count,plural, =1{# minuto}other{# minutos}}"</string>
- <string name="duration_hours_relative_future" msgid="6670440478481140565">"{count,plural, =1{# hora}other{# horas}}"</string>
- <string name="duration_days_relative_future" msgid="8870658635774250746">"{count,plural, =1{# dia}other{# dias}}"</string>
- <string name="duration_years_relative_future" msgid="8855853883925918380">"{count,plural, =1{# ano}other{# anos}}"</string>
+ <string name="duration_minutes_relative" msgid="8620337701051015593">"{count,plural, =1{Há # minuto}many{Há # minutos}other{Há # minutos}}"</string>
+ <string name="duration_hours_relative" msgid="4836449961693180253">"{count,plural, =1{Há # hora}many{Há # horas}other{Há # horas}}"</string>
+ <string name="duration_days_relative" msgid="621965767567258302">"{count,plural, =1{Há # dia}many{Há # dias}other{Há # dias}}"</string>
+ <string name="duration_years_relative" msgid="8731202348869424370">"{count,plural, =1{Há # ano}many{Há # anos}other{Há # anos}}"</string>
+ <string name="duration_minutes_relative_future" msgid="5259574171747708115">"{count,plural, =1{# minuto}many{# minutos}other{# minutos}}"</string>
+ <string name="duration_hours_relative_future" msgid="6670440478481140565">"{count,plural, =1{# hora}many{# horas}other{# horas}}"</string>
+ <string name="duration_days_relative_future" msgid="8870658635774250746">"{count,plural, =1{# dia}many{# dias}other{# dias}}"</string>
+ <string name="duration_years_relative_future" msgid="8855853883925918380">"{count,plural, =1{# ano}many{# anos}other{# anos}}"</string>
<string name="VideoView_error_title" msgid="5750686717225068016">"Problema com o vídeo"</string>
<string name="VideoView_error_text_invalid_progressive_playback" msgid="3782449246085134720">"Este vídeo não é válido para transmissão neste aparelho."</string>
<string name="VideoView_error_text_unknown" msgid="7658683339707607138">"Não é possível reproduzir este vídeo."</string>
@@ -1427,7 +1429,7 @@
<string name="ext_media_browse_action" msgid="344865351947079139">"Explorar"</string>
<string name="ext_media_seamless_action" msgid="8837030226009268080">"Saída do interruptor"</string>
<string name="ext_media_missing_title" msgid="3209472091220515046">"<xliff:g id="NAME">%s</xliff:g> em falta"</string>
- <string name="ext_media_missing_message" msgid="4408988706227922909">"Volte a inserir o dispositivo."</string>
+ <string name="ext_media_missing_message" msgid="4408988706227922909">"Volte a inserir o dispositivo"</string>
<string name="ext_media_move_specific_title" msgid="8492118544775964250">"A mover <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="ext_media_move_title" msgid="2682741525619033637">"A mover dados"</string>
<string name="ext_media_move_success_title" msgid="4901763082647316767">"Transf. de conteúdo concluída"</string>
@@ -1508,7 +1510,7 @@
<string name="skip_button_label" msgid="3566599811326688389">"Ignorar"</string>
<string name="no_matches" msgid="6472699895759164599">"Sem correspondências"</string>
<string name="find_on_page" msgid="5400537367077438198">"Localizar na página"</string>
- <string name="matches_found" msgid="2296462299979507689">"{count,plural, =1{# correspondência}other{# de {total}}}"</string>
+ <string name="matches_found" msgid="2296462299979507689">"{count,plural, =1{# correspondência}many{# de {total}}other{# de {total}}}"</string>
<string name="action_mode_done" msgid="2536182504764803222">"Concluído"</string>
<string name="progress_erasing" msgid="6891435992721028004">"A apagar o armazenamento partilhado…"</string>
<string name="share" msgid="4157615043345227321">"Partilhar"</string>
@@ -1861,14 +1863,14 @@
<string name="data_saver_description" msgid="4995164271550590517">"Para ajudar a reduzir a utilização de dados, a Poupança de dados impede que algumas apps enviem ou recebam dados em segundo plano. Uma determinada app que esteja a utilizar atualmente pode aceder aos dados, mas é possível que o faça com menos frequência. Isto pode significar, por exemplo, que as imagens não são apresentadas até que toque nas mesmas."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Ativar a Poupança de dados?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Ativar"</string>
- <string name="zen_mode_duration_minutes_summary" msgid="4555514757230849789">"{count,plural, =1{Durante um minuto (até à[s] {formattedTime})}other{Durante # minutos (até à[s] {formattedTime})}}"</string>
- <string name="zen_mode_duration_minutes_summary_short" msgid="1187553788355486950">"{count,plural, =1{Durante 1 min (até à[s] {formattedTime})}other{Durante # min (até à[s] {formattedTime})}}"</string>
- <string name="zen_mode_duration_hours_summary" msgid="3866333100793277211">"{count,plural, =1{Durante 1 hora (até à[s] {formattedTime})}other{Durante # horas (até à[s] {formattedTime})}}"</string>
- <string name="zen_mode_duration_hours_summary_short" msgid="687919813833347945">"{count,plural, =1{Durante 1 h (até à[s] {formattedTime})}other{Durante # h (até à[s] {formattedTime})}}"</string>
- <string name="zen_mode_duration_minutes" msgid="2340007982276569054">"{count,plural, =1{Durante um minuto}other{Durante # minutos}}"</string>
- <string name="zen_mode_duration_minutes_short" msgid="2435756450204526554">"{count,plural, =1{Durante 1 min}other{Durante # min}}"</string>
- <string name="zen_mode_duration_hours" msgid="7841806065034711849">"{count,plural, =1{Durante 1 hora}other{Durante # horas}}"</string>
- <string name="zen_mode_duration_hours_short" msgid="3666949653933099065">"{count,plural, =1{Durante 1 h}other{Durante # h}}"</string>
+ <string name="zen_mode_duration_minutes_summary" msgid="4555514757230849789">"{count,plural, =1{Durante um minuto (até à[s] {formattedTime})}many{Durante # minutos (até à[s] {formattedTime})}other{Durante # minutos (até à[s] {formattedTime})}}"</string>
+ <string name="zen_mode_duration_minutes_summary_short" msgid="1187553788355486950">"{count,plural, =1{Durante 1 min (até à[s] {formattedTime})}many{Durante # min (até à[s] {formattedTime})}other{Durante # min (até à[s] {formattedTime})}}"</string>
+ <string name="zen_mode_duration_hours_summary" msgid="3866333100793277211">"{count,plural, =1{Durante 1 hora (até à[s] {formattedTime})}many{Durante # horas (até à[s] {formattedTime})}other{Durante # horas (até à[s] {formattedTime})}}"</string>
+ <string name="zen_mode_duration_hours_summary_short" msgid="687919813833347945">"{count,plural, =1{Durante 1 h (até à[s] {formattedTime})}many{Durante # h (até à[s] {formattedTime})}other{Durante # h (até à[s] {formattedTime})}}"</string>
+ <string name="zen_mode_duration_minutes" msgid="2340007982276569054">"{count,plural, =1{Durante um minuto}many{Durante # minutos}other{Durante # minutos}}"</string>
+ <string name="zen_mode_duration_minutes_short" msgid="2435756450204526554">"{count,plural, =1{Durante 1 min}many{Durante # min}other{Durante # min}}"</string>
+ <string name="zen_mode_duration_hours" msgid="7841806065034711849">"{count,plural, =1{Durante 1 hora}many{Durante # horas}other{Durante # horas}}"</string>
+ <string name="zen_mode_duration_hours_short" msgid="3666949653933099065">"{count,plural, =1{Durante 1 h}many{Durante # h}other{Durante # h}}"</string>
<string name="zen_mode_until_next_day" msgid="1403042784161725038">"Até <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
<string name="zen_mode_until" msgid="2250286190237669079">"Até às <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
<string name="zen_mode_alarm" msgid="7046911727540499275">"Até <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (próximo alarme)"</string>
@@ -1926,8 +1928,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"Preferência de região"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Intr. nome do idioma"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"Sugeridos"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Sugeridas"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"Todos os idiomas"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"Todas as regiões"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"Pesquisa"</string>
@@ -2000,7 +2001,7 @@
<string name="autofill_save_accessibility_title" msgid="1523225776218450005">"Guardar para o Preenchimento automático"</string>
<string name="autofill_error_cannot_autofill" msgid="6528827648643138596">"Não é possível preencher automaticamente o conteúdo"</string>
<string name="autofill_picker_no_suggestions" msgid="1076022650427481509">"Sem sugestões do preenchimento automático"</string>
- <string name="autofill_picker_some_suggestions" msgid="5560549696296202701">"{count,plural, =1{Uma sugestão do preenchimento automático}other{# sugestões de preenchimento automático}}"</string>
+ <string name="autofill_picker_some_suggestions" msgid="5560549696296202701">"{count,plural, =1{Uma sugestão do preenchimento automático}many{# sugestões de preenchimento automático}other{# sugestões de preenchimento automático}}"</string>
<string name="autofill_save_title" msgid="7719802414283739775">"Pretende guardar em "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"?"</string>
<string name="autofill_save_title_with_type" msgid="3002460014579799605">"Pretende guardar <xliff:g id="TYPE">%1$s</xliff:g> em "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"?"</string>
<string name="autofill_save_title_with_2types" msgid="3783270967447869241">"Pretende guardar <xliff:g id="TYPE_0">%1$s</xliff:g> e <xliff:g id="TYPE_1">%2$s</xliff:g> em "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"?"</string>
@@ -2050,8 +2051,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Permitir que a app <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> aceda a todos os registos do dispositivo?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"Permitir acesso único"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Não permitir"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"Os registos do dispositivo documentam o que ocorre no seu dispositivo. As apps podem usar esses registos para detetar e corrigir problemas.\n\nAlguns registos podem conter informações confidenciais e, por isso, o acesso a todos os registos do dispositivo deve apenas ser permitido às apps nas quais confia. \n\nSe não permitir o acesso desta app a todos os registos do dispositivo, esta pode ainda assim aceder aos próprios registos. O fabricante do dispositivo pode continuar a aceder a alguns registos ou informações no seu dispositivo."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Não mostrar de novo"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"A app <xliff:g id="APP_0">%1$s</xliff:g> pretende mostrar partes da app <xliff:g id="APP_2">%2$s</xliff:g>."</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Editar"</string>
@@ -2111,7 +2111,7 @@
<string name="mime_type_presentation_ext" msgid="8761049335564371468">"Apresentação <xliff:g id="EXTENSION">%1$s</xliff:g>"</string>
<string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"O Bluetooth continuará ativado durante o modo de avião."</string>
<string name="car_loading_profile" msgid="8219978381196748070">"A carregar…"</string>
- <string name="file_count" msgid="3220018595056126969">"{count,plural, =1{{file_name} + # ficheiro}other{{file_name} + # ficheiros}}"</string>
+ <string name="file_count" msgid="3220018595056126969">"{count,plural, =1{{file_name} + # ficheiro}many{{file_name} + # ficheiros}other{{file_name} + # ficheiros}}"</string>
<string name="chooser_no_direct_share_targets" msgid="1511722103987329028">"Não existem pessoas recomendadas com quem partilhar"</string>
<string name="chooser_all_apps_button_label" msgid="3230427756238666328">"Lista de aplicações"</string>
<string name="usb_device_resolve_prompt_warn" msgid="325871329788064199">"Esta app não recebeu autorização de gravação, mas pode capturar áudio através deste dispositivo USB."</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 9eb1e5d..283db53 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -52,6 +52,7 @@
<string name="enablePin" msgid="2543771964137091212">"Falha. Ative o bloqueio do chip/R-UIM."</string>
<plurals name="pinpuk_attempts" formatted="false" msgid="1619867269012213584">
<item quantity="one">Tentativas restantes: <xliff:g id="NUMBER_1">%d</xliff:g>. Caso o código correto não seja digitado, o chip será bloqueado.</item>
+ <item quantity="many">You have <xliff:g id="NUMBER_1">%d</xliff:g> remaining attempts before SIM is locked.</item>
<item quantity="other">Tentativas restantes: <xliff:g id="NUMBER_1">%d</xliff:g>. Caso o código correto não seja digitado, o chip será bloqueado.</item>
</plurals>
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
@@ -180,7 +181,7 @@
<string name="low_memory" product="watch" msgid="3479447988234030194">"Armazenamento do relógio cheio. Exclua alguns arquivos para liberar espaço."</string>
<string name="low_memory" product="tv" msgid="6663680413790323318">"O armazenamento do dispositivo Android TV está cheio. Exclua alguns arquivos para liberar espaço."</string>
<string name="low_memory" product="default" msgid="2539532364144025569">"O armazenamento do telefone está cheio. Exclua alguns arquivos para liberar espaço."</string>
- <string name="ssl_ca_cert_warning" msgid="7233573909730048571">"{count,plural, =1{Autoridade certificadora instalada}one{Autoridade certificadora instalada}other{Autoridades certificadoras instaladas}}"</string>
+ <string name="ssl_ca_cert_warning" msgid="7233573909730048571">"{count,plural, =1{Autoridade certificadora instalada}one{Autoridade certificadora instalada}many{Autoridades certificadoras instaladas}other{Autoridades certificadoras instaladas}}"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4961102218216815242">"Por terceiros desconhecidos"</string>
<string name="ssl_ca_cert_noti_by_administrator" msgid="4564941950768783879">"Pelo administrador do seu perfil de trabalho"</string>
<string name="ssl_ca_cert_noti_managed" msgid="217337232273211674">"Por <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
@@ -254,7 +255,7 @@
<string name="bugreport_option_interactive_summary" msgid="8493795476325339542">"Use este recurso na maioria das circunstâncias. Ele permite que você acompanhe o progresso do relatório, informe mais detalhes sobre o problema e faça capturas de tela. É possível que ele omita algumas seções menos utilizadas que levam muito tempo na emissão dos relatórios."</string>
<string name="bugreport_option_full_title" msgid="7681035745950045690">"Relatório completo"</string>
<string name="bugreport_option_full_summary" msgid="1975130009258435885">"Use esta opção para ter o mínimo de interferência do sistema quando seu dispositivo não estiver respondendo ou estiver muito lento, ou quando você precisar de todas as seções de relatórios. Ela não permite que você informe mais detalhes ou faça capturas de tela adicionais."</string>
- <string name="bugreport_countdown" msgid="6418620521782120755">"{count,plural, =1{Capturas de tela para o relatório do bug vão ser feitas em # segundo.}one{Capturas de tela para o relatório do bug vão ser feitas em # segundo.}other{Capturas de tela para o relatório do bug vão ser feitas em # segundos.}}"</string>
+ <string name="bugreport_countdown" msgid="6418620521782120755">"{count,plural, =1{Capturas de tela para o relatório do bug vão ser feitas em # segundo.}one{Capturas de tela para o relatório do bug vão ser feitas em # segundo.}many{Capturas de tela para o relatório do bug vão ser feitas em # segundos.}other{Capturas de tela para o relatório do bug vão ser feitas em # segundos.}}"</string>
<string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Captura de tela com o relatório do bug concluída"</string>
<string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Falha ao capturar a tela com o relatório do bug"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Modo silencioso"</string>
@@ -608,7 +609,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"Operação de impressão digital cancelada."</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Operação de impressão digital cancelada pelo usuário."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"Excesso de tentativas. Tente novamente mais tarde."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Excesso de tentativas. Sensor de impressão digital desativado."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Excesso de tentativas. Use o bloqueio de tela."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Tente novamente."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nenhuma impressão digital registrada."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Este dispositivo não tem um sensor de impressão digital."</string>
@@ -637,7 +638,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Entre em contato com uma assistência técnica."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"Falha ao criar o modelo de rosto. Tente de novo."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Muito iluminado. Diminua a iluminação."</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"Use uma iluminação mais intensa"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"Afaste o smartphone"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"Aproxime o smartphone do seu rosto"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"Mova o smartphone para cima"</string>
@@ -1087,7 +1089,7 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="4312979647356179250">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> quer ativar o Explorar por toque. Com ele, você pode ouvir ou ver descrições do que está sob seu dedo e interagir com o telefone por gestos."</string>
<string name="oneMonthDurationPast" msgid="4538030857114635777">"1 mês atrás"</string>
<string name="beforeOneMonthDurationPast" msgid="8315149541372065392">"Antes de 1 mês atrás"</string>
- <string name="last_num_days" msgid="2393660431490280537">"{count,plural, =1{No último # dia}one{No último # dia}other{Nos últimos # dias}}"</string>
+ <string name="last_num_days" msgid="2393660431490280537">"{count,plural, =1{No último # dia}one{No último # dia}many{Nos últimos # dias}other{Nos últimos # dias}}"</string>
<string name="last_month" msgid="1528906781083518683">"Mês passado"</string>
<string name="older" msgid="1645159827884647400">"Mais antigos"</string>
<string name="preposition_for_date" msgid="2780767868832729599">"em <xliff:g id="DATE">%s</xliff:g>"</string>
@@ -1114,14 +1116,14 @@
<string name="duration_hours_shortest_future" msgid="2979276794547981674">"em <xliff:g id="COUNT">%d</xliff:g>h"</string>
<string name="duration_days_shortest_future" msgid="3392722163935571543">"em <xliff:g id="COUNT">%d</xliff:g> dias"</string>
<string name="duration_years_shortest_future" msgid="5537464088352970388">"em <xliff:g id="COUNT">%d</xliff:g>a"</string>
- <string name="duration_minutes_relative" msgid="8620337701051015593">"{count,plural, =1{# minuto atrás}one{# minuto atrás}other{# minutos atrás}}"</string>
- <string name="duration_hours_relative" msgid="4836449961693180253">"{count,plural, =1{# hora atrás}one{# hora atrás}other{# horas atrás}}"</string>
- <string name="duration_days_relative" msgid="621965767567258302">"{count,plural, =1{# dia atrás}one{# dia atrás}other{# dias atrás}}"</string>
- <string name="duration_years_relative" msgid="8731202348869424370">"{count,plural, =1{# ano atrás}one{# ano atrás}other{# anos atrás}}"</string>
- <string name="duration_minutes_relative_future" msgid="5259574171747708115">"{count,plural, =1{# minuto}one{# minuto}other{# minutos}}"</string>
- <string name="duration_hours_relative_future" msgid="6670440478481140565">"{count,plural, =1{# hora}one{# hora}other{# horas}}"</string>
- <string name="duration_days_relative_future" msgid="8870658635774250746">"{count,plural, =1{# dia}one{# dia}other{# dias}}"</string>
- <string name="duration_years_relative_future" msgid="8855853883925918380">"{count,plural, =1{# ano}one{# ano}other{# anos}}"</string>
+ <string name="duration_minutes_relative" msgid="8620337701051015593">"{count,plural, =1{# minuto atrás}one{# minuto atrás}many{# minutos atrás}other{# minutos atrás}}"</string>
+ <string name="duration_hours_relative" msgid="4836449961693180253">"{count,plural, =1{# hora atrás}one{# hora atrás}many{# horas atrás}other{# horas atrás}}"</string>
+ <string name="duration_days_relative" msgid="621965767567258302">"{count,plural, =1{# dia atrás}one{# dia atrás}many{# dias atrás}other{# dias atrás}}"</string>
+ <string name="duration_years_relative" msgid="8731202348869424370">"{count,plural, =1{# ano atrás}one{# ano atrás}many{# anos atrás}other{# anos atrás}}"</string>
+ <string name="duration_minutes_relative_future" msgid="5259574171747708115">"{count,plural, =1{# minuto}one{# minuto}many{# minutos}other{# minutos}}"</string>
+ <string name="duration_hours_relative_future" msgid="6670440478481140565">"{count,plural, =1{# hora}one{# hora}many{# horas}other{# horas}}"</string>
+ <string name="duration_days_relative_future" msgid="8870658635774250746">"{count,plural, =1{# dia}one{# dia}many{# dias}other{# dias}}"</string>
+ <string name="duration_years_relative_future" msgid="8855853883925918380">"{count,plural, =1{# ano}one{# ano}many{# anos}other{# anos}}"</string>
<string name="VideoView_error_title" msgid="5750686717225068016">"Problema com o vídeo"</string>
<string name="VideoView_error_text_invalid_progressive_playback" msgid="3782449246085134720">"Este vídeo não é válido para transmissão neste dispositivo."</string>
<string name="VideoView_error_text_unknown" msgid="7658683339707607138">"Não é possível reproduzir este vídeo."</string>
@@ -1508,7 +1510,7 @@
<string name="skip_button_label" msgid="3566599811326688389">"Pular"</string>
<string name="no_matches" msgid="6472699895759164599">"Não encontrado"</string>
<string name="find_on_page" msgid="5400537367077438198">"Localizar na página"</string>
- <string name="matches_found" msgid="2296462299979507689">"{count,plural, =1{# correspondência}one{# de {total}}other{# de {total}}}"</string>
+ <string name="matches_found" msgid="2296462299979507689">"{count,plural, =1{# correspondência}one{# de {total}}many{# de {total}}other{# de {total}}}"</string>
<string name="action_mode_done" msgid="2536182504764803222">"Concluído"</string>
<string name="progress_erasing" msgid="6891435992721028004">"Limpando armazenamento compartilhado…"</string>
<string name="share" msgid="4157615043345227321">"Compartilhar"</string>
@@ -1861,14 +1863,14 @@
<string name="data_saver_description" msgid="4995164271550590517">"Para ajudar a reduzir o uso de dados, a Economia de dados impede que alguns apps enviem ou recebam dados em segundo plano. Um app que você está usando no momento pode acessar dados, mas com menos frequência. Isso pode fazer com que imagens não apareçam até você tocar nelas."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Ativar a Economia de dados?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Ativar"</string>
- <string name="zen_mode_duration_minutes_summary" msgid="4555514757230849789">"{count,plural, =1{Por um minuto (até {formattedTime})}one{Por # minuto (até {formattedTime})}other{Por # minutos (até {formattedTime})}}"</string>
- <string name="zen_mode_duration_minutes_summary_short" msgid="1187553788355486950">"{count,plural, =1{Por 1min (até {formattedTime})}one{Por #min (até {formattedTime})}other{Por #min (até {formattedTime})}}"</string>
- <string name="zen_mode_duration_hours_summary" msgid="3866333100793277211">"{count,plural, =1{Por 1 hora (até {formattedTime})}one{Por # hora (até {formattedTime})}other{Por # horas (até {formattedTime})}}"</string>
- <string name="zen_mode_duration_hours_summary_short" msgid="687919813833347945">"{count,plural, =1{Por 1h (até {formattedTime})}one{Por #h (até {formattedTime})}other{Por #h (até {formattedTime})}}"</string>
- <string name="zen_mode_duration_minutes" msgid="2340007982276569054">"{count,plural, =1{Por um minuto}one{Por # minuto}other{Por # minutos}}"</string>
- <string name="zen_mode_duration_minutes_short" msgid="2435756450204526554">"{count,plural, =1{Por 1min}one{Por #min}other{Por #min}}"</string>
- <string name="zen_mode_duration_hours" msgid="7841806065034711849">"{count,plural, =1{Por 1 hora}one{Por # hora}other{Por # horas}}"</string>
- <string name="zen_mode_duration_hours_short" msgid="3666949653933099065">"{count,plural, =1{Por 1h}one{Por #h}other{Por #h}}"</string>
+ <string name="zen_mode_duration_minutes_summary" msgid="4555514757230849789">"{count,plural, =1{Por um minuto (até {formattedTime})}one{Por # minuto (até {formattedTime})}many{Por # minutos (até {formattedTime})}other{Por # minutos (até {formattedTime})}}"</string>
+ <string name="zen_mode_duration_minutes_summary_short" msgid="1187553788355486950">"{count,plural, =1{Por 1min (até {formattedTime})}one{Por #min (até {formattedTime})}many{Por #min (até {formattedTime})}other{Por #min (até {formattedTime})}}"</string>
+ <string name="zen_mode_duration_hours_summary" msgid="3866333100793277211">"{count,plural, =1{Por 1 hora (até {formattedTime})}one{Por # hora (até {formattedTime})}many{Por # horas (até {formattedTime})}other{Por # horas (até {formattedTime})}}"</string>
+ <string name="zen_mode_duration_hours_summary_short" msgid="687919813833347945">"{count,plural, =1{Por 1h (até {formattedTime})}one{Por #h (até {formattedTime})}many{Por #h (até {formattedTime})}other{Por #h (até {formattedTime})}}"</string>
+ <string name="zen_mode_duration_minutes" msgid="2340007982276569054">"{count,plural, =1{Por um minuto}one{Por # minuto}many{Por # minutos}other{Por # minutos}}"</string>
+ <string name="zen_mode_duration_minutes_short" msgid="2435756450204526554">"{count,plural, =1{Por 1min}one{Por #min}many{Por #min}other{Por #min}}"</string>
+ <string name="zen_mode_duration_hours" msgid="7841806065034711849">"{count,plural, =1{Por 1 hora}one{Por # hora}many{Por # horas}other{Por # horas}}"</string>
+ <string name="zen_mode_duration_hours_short" msgid="3666949653933099065">"{count,plural, =1{Por 1h}one{Por #h}many{Por #h}other{Por #h}}"</string>
<string name="zen_mode_until_next_day" msgid="1403042784161725038">"Até <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
<string name="zen_mode_until" msgid="2250286190237669079">"Até às <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
<string name="zen_mode_alarm" msgid="7046911727540499275">"Até <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (próximo alarme)"</string>
@@ -1926,8 +1928,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"Preferência de região"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Digitar nome do idioma"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"Sugeridos"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Sugestões"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"Todos os idiomas"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"Todas as regiões"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"Pesquisa"</string>
@@ -2000,7 +2001,7 @@
<string name="autofill_save_accessibility_title" msgid="1523225776218450005">"Salvar no Preenchimento automático"</string>
<string name="autofill_error_cannot_autofill" msgid="6528827648643138596">"Não é possível preencher os conteúdos automaticamente"</string>
<string name="autofill_picker_no_suggestions" msgid="1076022650427481509">"Sem sugestões de preenchimento automático"</string>
- <string name="autofill_picker_some_suggestions" msgid="5560549696296202701">"{count,plural, =1{Uma sugestão de preenchimento automático}one{# sugestão de preenchimento automático}other{# sugestões de preenchimento automático}}"</string>
+ <string name="autofill_picker_some_suggestions" msgid="5560549696296202701">"{count,plural, =1{Uma sugestão de preenchimento automático}one{# sugestão de preenchimento automático}many{# sugestões de preenchimento automático}other{# sugestões de preenchimento automático}}"</string>
<string name="autofill_save_title" msgid="7719802414283739775">"Salvar em "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"?"</string>
<string name="autofill_save_title_with_type" msgid="3002460014579799605">"Salvar <xliff:g id="TYPE">%1$s</xliff:g> em "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"?"</string>
<string name="autofill_save_title_with_2types" msgid="3783270967447869241">"Salvar <xliff:g id="TYPE_0">%1$s</xliff:g> e <xliff:g id="TYPE_1">%2$s</xliff:g> em "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"?"</string>
@@ -2050,8 +2051,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Permitir que o app <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> acesse todos os registros do dispositivo?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"Permitir o acesso único"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Não permitir"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"Os registros do dispositivo gravam o que acontece nele. Os apps podem usar esses registros para encontrar e corrigir problemas.\n\nAlguns registros podem conter informações sensíveis, então autorize o acesso a eles apenas para os apps em que você confia. \n\nSe você não permitir que esse app acesse todos os registros do dispositivo, ele ainda vai poder acessar os próprios. O fabricante do dispositivo também pode ter acesso a alguns registros ou informações."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Não mostrar novamente"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> quer mostrar partes do app <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Editar"</string>
@@ -2111,7 +2111,7 @@
<string name="mime_type_presentation_ext" msgid="8761049335564371468">"Apresentação em <xliff:g id="EXTENSION">%1$s</xliff:g>"</string>
<string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"O Bluetooth permanecerá ativado no modo avião"</string>
<string name="car_loading_profile" msgid="8219978381196748070">"Carregando"</string>
- <string name="file_count" msgid="3220018595056126969">"{count,plural, =1{{file_name} + # arquivo}one{{file_name} + # arquivo}other{{file_name} + # arquivos}}"</string>
+ <string name="file_count" msgid="3220018595056126969">"{count,plural, =1{{file_name} + # arquivo}one{{file_name} + # arquivo}many{{file_name} + # arquivos}other{{file_name} + # arquivos}}"</string>
<string name="chooser_no_direct_share_targets" msgid="1511722103987329028">"Não há sugestões de pessoas para compartilhar"</string>
<string name="chooser_all_apps_button_label" msgid="3230427756238666328">"Lista de apps"</string>
<string name="usb_device_resolve_prompt_warn" msgid="325871329788064199">"Este app não tem permissão de gravação, mas pode capturar áudio pelo dispositivo USB."</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 695e1ea..b2cb99b 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -609,7 +609,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"Operațiunea privind amprenta a fost anulată."</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Operațiunea privind amprenta a fost anulată de utilizator."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"Prea multe încercări. Încercați din nou mai târziu."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Prea multe încercări. Senzorul de amprentă este dezactivat."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Prea multe încercări. Folosește blocarea ecranului."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Încercați din nou."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nu au fost înregistrate amprente."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Dispozitivul nu are senzor de amprentă."</string>
@@ -638,7 +638,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Vizitați un furnizor de servicii de reparații."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"Nu se poate crea modelul facial. Reîncercați."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Prea luminos. Încercați o lumină mai slabă."</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"Încercați o lumină mai puternică"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"Mutați telefonul mai departe"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"Mutați telefonul mai aproape"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"Mutați telefonul mai sus"</string>
@@ -968,7 +969,7 @@
<string name="lockscreen_glogin_instructions" msgid="4695162942525531700">"Pentru a debloca, conectați-vă folosind Contul Google."</string>
<string name="lockscreen_glogin_username_hint" msgid="6916101478673157045">"Nume de utilizator (e-mail)"</string>
<string name="lockscreen_glogin_password_hint" msgid="3031027901286812848">"Parolă"</string>
- <string name="lockscreen_glogin_submit_button" msgid="3590556636347843733">"Conectați-vă"</string>
+ <string name="lockscreen_glogin_submit_button" msgid="3590556636347843733">"Conectează-te"</string>
<string name="lockscreen_glogin_invalid_input" msgid="4369219936865697679">"Nume de utilizator sau parolă nevalide."</string>
<string name="lockscreen_glogin_account_recovery_hint" msgid="1683405808525090649">"Ați uitat numele de utilizator sau parola?\nAccesați "<b>"google.com/accounts/recovery"</b>"."</string>
<string name="lockscreen_glogin_checking_password" msgid="2607271802803381645">"Se verifică..."</string>
@@ -1656,7 +1657,7 @@
<string name="kg_login_instructions" msgid="3619844310339066827">"Pentru a debloca, conectați-vă cu Contul dvs. Google."</string>
<string name="kg_login_username_hint" msgid="1765453775467133251">"Nume de utilizator (e-mail)"</string>
<string name="kg_login_password_hint" msgid="3330530727273164402">"Parolă"</string>
- <string name="kg_login_submit_button" msgid="893611277617096870">"Conectați-vă"</string>
+ <string name="kg_login_submit_button" msgid="893611277617096870">"Conectează-te"</string>
<string name="kg_login_invalid_input" msgid="8292367491901220210">"Nume de utilizator sau parolă nevalide."</string>
<string name="kg_login_account_recovery_hint" msgid="4892466171043541248">"Ați uitat numele de utilizator sau parola?\nAccesați "<b>"google.com/accounts/recovery"</b>"."</string>
<string name="kg_login_checking_password" msgid="4676010303243317253">"Se verifică contul…"</string>
@@ -1927,8 +1928,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"Regiunea preferată"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Numele limbii"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"Sugerate"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Sugerate"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"Toate limbile"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"Toate regiunile"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"Căutați"</string>
@@ -2051,8 +2051,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Permiteți ca <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> să acceseze toate jurnalele dispozitivului?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"Permiteți accesul o dată"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Nu permiteți"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"Jurnalele dispozitivului înregistrează activitatea de pe dispozitivul tău. Aplicațiile pot folosi aceste jurnale pentru a identifica și a remedia probleme.\n\nUnele jurnale pot să conțină informații sensibile, prin urmare permite accesul la toate jurnalele dispozitivului doar aplicațiilor în care ai încredere. \n\nDacă nu permiți accesul aplicației la toate jurnalele dispozitivului, aceasta poate în continuare să acceseze propriile jurnale. Este posibil ca producătorul dispozitivului să acceseze în continuare unele jurnale sau informații de pe dispozitiv."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Nu mai afișa"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> vrea să afișeze porțiuni din <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Editați"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 38fa8f4..e8f4107 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -610,7 +610,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"Операция с отпечатком отменена."</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Операция с отпечатком пальца отменена пользователем."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"Слишком много попыток. Повторите позже."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Слишком много попыток. Сканер отпечатков пальцев отключен."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Слишком много попыток. Используйте другой способ разблокировки экрана."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Повторите попытку."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Нет отсканированных отпечатков пальцев"</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"На этом устройстве нет сканера отпечатков пальцев."</string>
@@ -639,7 +639,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Обратитесь в сервисный центр."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"Невозможно создать модель лица. Повторите попытку."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Слишком светло. Сделайте освещение менее ярким."</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"Сделайте освещение ярче"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"Переместите телефон дальше от лица"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"Переместите телефон ближе к лицу"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"Переместите телефон выше"</string>
@@ -1428,7 +1429,7 @@
<string name="ext_media_unmount_action" msgid="966992232088442745">"Извлечь"</string>
<string name="ext_media_browse_action" msgid="344865351947079139">"Обзор"</string>
<string name="ext_media_seamless_action" msgid="8837030226009268080">"Сменить устройство вывода"</string>
- <string name="ext_media_missing_title" msgid="3209472091220515046">"<xliff:g id="NAME">%s</xliff:g> не найден"</string>
+ <string name="ext_media_missing_title" msgid="3209472091220515046">"Устройство \"<xliff:g id="NAME">%s</xliff:g>\" не найдено"</string>
<string name="ext_media_missing_message" msgid="4408988706227922909">"Подключите накопитель снова."</string>
<string name="ext_media_move_specific_title" msgid="8492118544775964250">"Перенос приложения <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="ext_media_move_title" msgid="2682741525619033637">"Перенос данных"</string>
@@ -1928,8 +1929,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"Региональные настройки"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Введите название языка"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"Рекомендуемые"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Доступные регионы"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"Все языки"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"Все регионы"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"Поиск"</string>
@@ -2052,8 +2052,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Разрешить приложению \"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g>\" доступ ко всем журналам устройства?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"Разрешить разовый доступ"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Запретить"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"В журналы записывается информация о том, что происходит на устройстве. Приложения могут использовать их, чтобы находить и устранять неполадки.\n\nТак как некоторые журналы могут содержать конфиденциальную информацию, доступ ко всем журналам следует предоставлять только тем приложениям, которым вы доверяете. \n\nЕсли вы не предоставите такой доступ этому приложению, оно по-прежнему сможет просматривать свои журналы. Не исключено, что некоторые журналы или сведения на вашем устройстве будут по-прежнему доступны его производителю."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Больше не показывать"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"Приложение \"<xliff:g id="APP_0">%1$s</xliff:g>\" запрашивает разрешение на показ фрагментов приложения \"<xliff:g id="APP_2">%2$s</xliff:g>\"."</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Изменить"</string>
@@ -2294,7 +2293,6 @@
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Проверить активные приложения"</string>
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"У устройства \"<xliff:g id="DEVICE">%1$s</xliff:g>\" нет доступа к камере телефона."</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"У устройства \"<xliff:g id="DEVICE">%1$s</xliff:g>\" нет доступа к камере планшета."</string>
- <!-- no translation found for vdm_secure_window (161700398158812314) -->
- <skip />
+ <string name="vdm_secure_window" msgid="161700398158812314">"Этот контент недоступен во время трансляции. Используйте телефон."</string>
<string name="system_locale_title" msgid="711882686834677268">"Системные настройки по умолчанию"</string>
</resources>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index b3d9368..5048213 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -608,7 +608,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"ඇඟිලි සලකුණු මෙහෙයුම අවලංගු කරන ලදී."</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"පරිශීලක විසින් ඇඟිලි සලකුණු මෙහෙයුම අවසන් කරන ලදී."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"උත්සාහයන් ඉතා වැඩි ගණනකි. කරුණාකර පසුව නැවත උත්සාහ කරන්න."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"උත්සාහයන් ඉතා වැඩි ගණනකි. ඇඟිලි සලකුණු සංවේදකය අබල කරන ලදී."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"උත්සාහ ගණන ඉතා වැඩියි. ඒ වෙනුවට තිර අගුල භාවිත කරන්න."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"නැවත උත්සාහ කරන්න."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"ඇඟිලි සලකුණු ඇතුළත් කර නොමැත."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"මෙම උපාංගයේ ඇඟිලි සලකුණු සංවේදකයක් නොමැත."</string>
@@ -637,7 +637,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"අළුත්වැඩියා සැපයුම්කරුවෙකු බලන්න."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"ඔබගේ මුහුණු ආකෘතිය තැනිය නොහැකිය. නැවත උත්සාහ කරන්න."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"දීප්තිය වැඩියි. තවත් මඳ ආලෝකය උත්සාහ කරන්න."</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"තවත් දීප්තිමත් ආලෝකය උත්සාහ කරන්න"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"දුරකථනය තවත් ඈතට ගෙන යන්න"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"දුරකථනය තවත් සමීපයට ගෙන එන්න"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"දුරකථනය තවත් ඉහළට ගෙන යන්න"</string>
@@ -1926,8 +1927,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"ප්රදේශ මනාපය"</string>
<string name="search_language_hint" msgid="7004225294308793583">"භාෂා නම ටයිප් කරන්න"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"යෝජිත"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"යෝජිත"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"සියලු භාෂා"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"සියලු ප්රදේශ"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"සෙවීම"</string>
@@ -2050,8 +2050,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> හට සියලු උපාංග ලොග ප්රවේශ වීමට ඉඩ දෙන්නද?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"එක් වරක් ප්රවේශය ඉඩ දෙන්න"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"ඉඩ නොදෙන්න"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"උපාංග ලොග ඔබේ උපාංගයෙහි සිදු වන දේ වාර්තා කරයි. ගැටලු සොයා ගැනීමට සහ නිරාකරණයට යෙදුම්වලට මෙම ලොග භාවිතා කළ හැක.\n\nසමහර ලොගවල සංවේදී තතු අඩංගු විය හැකි බැවින්, ඔබ විශ්වාස කරන යෙදුම්වලට පමණක් සියලු උපාංග ලොග වෙත ප්රවේශ වීමට ඉඩ දෙන්න. \n\nඔබ මෙම යෙදුමට සියලු උපාංග ලොග වෙත ප්රවේශ වීමට ඉඩ නොදෙන්නේ නම්, එයට තවමත් එහිම ලොග වෙත ප්රවේශ විය හැක. ඔබේ උපාංග නිෂ්පාදකයාට තවමත් ඔබේ උපාංගයෙහි සමහර ලොග හෝ තතු වෙත ප්රවේශ විය හැක."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"නැවත නොපෙන්වන්න"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> හට කොටස් <xliff:g id="APP_2">%2$s</xliff:g>ක් පෙන්වීමට අවශ්යයි"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"සංස්කරණය"</string>
@@ -2292,7 +2291,6 @@
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"සක්රිය යෙදුම් පරීක්ෂා කරන්න"</string>
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"ඔබගේ <xliff:g id="DEVICE">%1$s</xliff:g> වෙතින් දුරකථනයේ කැමරාවට ප්රවේශ විය නොහැකිය"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"ඔබගේ <xliff:g id="DEVICE">%1$s</xliff:g> වෙතින් ටැබ්ලටයේ කැමරාවට ප්රවේශ විය නොහැකිය"</string>
- <!-- no translation found for vdm_secure_window (161700398158812314) -->
- <skip />
+ <string name="vdm_secure_window" msgid="161700398158812314">"ප්රවාහය කරන අතරේ මෙයට ප්රවේශ විය නොහැක. ඒ වෙනුවට ඔබේ දුරකථනයෙහි උත්සාහ කරන්න."</string>
<string name="system_locale_title" msgid="711882686834677268">"පද්ධති පෙරනිමිය"</string>
</resources>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index c607a48..0238018 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -610,7 +610,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"Operácia týkajúca sa odtlačku prsta bola zrušená"</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Overenie odtlačku prsta zrušil používateľ."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"Príliš veľa pokusov. Skúste to neskôr."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Príliš veľa pokusov. Senzor odtlačkov prstov bol deaktivovaný."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Príliš veľa pokusov. Použite radšej zámku obrazovky."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Skúste to znova"</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Neregistrovali ste žiadne odtlačky prstov."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Toto zariadenie nemá senzor odtlačkov prstov."</string>
@@ -639,7 +639,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Navštívte poskytovateľa opráv."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"Model tváre sa nedá vytvoriť. Skúste to znova."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Príliš veľa svetla. Skúste jemnejšie osvetlenie."</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"Skúste lepšie osvetlenie"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"Oddiaľte telefón"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"Priblížte telefón"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"Posuňte telefón vyššie"</string>
@@ -1928,8 +1929,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"Preferovaný región"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Zadajte názov jazyka"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"Navrhované"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Navrhované"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"Všetky jazyky"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"Všetky oblasti"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"Vyhľadávanie"</string>
@@ -2052,8 +2052,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Chcete povoliť aplikácii <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> prístup k všetkým denníkom zariadenia?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"Povoliť jednorazový prístup"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Nepovoliť"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"Denníky zariadenia zaznamenávajú, čo sa deje vo vašom zariadení. Aplikácie môžu pomocou týchto denníkov vyhľadávať a riešiť problémy.\n\nNiektoré denníky môžu obsahovať citlivé údaje, preto povoľte prístup k všetkým denníkom zariadenia iba dôveryhodným aplikáciám. \n\nAk tejto aplikácii nepovolíte prístup k všetkým denníkom zariadenia, stále bude mať prístup k vlastným denníkom. Výrobca vášho zariadenia bude mať naďalej prístup k niektorým denníkom alebo informáciám vo vašom zariadení."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Už nezobrazovať"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> chce zobrazovať rezy z aplikácie <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Upraviť"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index d32e398..e1e06da 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -610,7 +610,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"Dejanje s prstnim odtisom je bilo preklicano."</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Dejanje s prstnim odtisom je preklical uporabnik."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"Preveč poskusov. Poskusite znova pozneje."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Preveč poskusov. Tipalo prstnih odtisov je onemogočeno."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Preveč poskusov. Odklenite z zaklepanjem zaslona."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Poskusite znova."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Ni registriranih prstnih odtisov."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Ta naprava nima tipala prstnih odtisov."</string>
@@ -639,7 +639,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Obiščite ponudnika popravil."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"Modela obraza ni mogoče ustvariti. Poskusite znova."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Presvetlo. Poskusite z blažjo osvetlitvijo."</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"Poskusite z močnejšo osvetlitvijo."</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"Telefon nekoliko odmaknite."</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"Bolj približajte telefon."</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"Telefon premaknite višje."</string>
@@ -1928,8 +1929,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"Nastavitev območja"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Vnesite ime jezika"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"Predlagano"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Predlagano"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"Vsi jeziki"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"Vse regije"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"Išči"</string>
@@ -2052,8 +2052,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Ali aplikaciji <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> dovolite dostop do vseh dnevnikov naprave?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"Dovoli enkratni dostop"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Ne dovoli"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"V dnevnikih naprave se beleži dogajanje v napravi. Aplikacije lahko te dnevnike uporabijo za iskanje in odpravljanje težav.\n\nNekateri dnevniki morda vsebujejo občutljive podatke, zato dostop do vseh dnevnikov naprave omogočite le aplikacijam, ki jim zaupate. \n\nČe tej aplikaciji ne dovolite dostopa do vseh dnevnikov naprave, bo aplikacija kljub temu lahko dostopala do svojih dnevnikov. Proizvajalec naprave bo morda lahko kljub temu dostopal do nekaterih dnevnikov ali podatkov v napravi."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Ne prikaži več"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"Aplikacija <xliff:g id="APP_0">%1$s</xliff:g> želi prikazati izreze aplikacije <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Uredi"</string>
@@ -2294,7 +2293,6 @@
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Preverite aktivne aplikacije"</string>
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Ni mogoče dostopati do fotoaparata telefona prek naprave <xliff:g id="DEVICE">%1$s</xliff:g>."</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Ni mogoče dostopati do fotoaparata tabličnega računalnika prek naprave <xliff:g id="DEVICE">%1$s</xliff:g>."</string>
- <!-- no translation found for vdm_secure_window (161700398158812314) -->
- <skip />
+ <string name="vdm_secure_window" msgid="161700398158812314">"Do te vsebine ni mogoče dostopati med pretočnim predvajanjem. Poskusite s telefonom."</string>
<string name="system_locale_title" msgid="711882686834677268">"Sistemsko privzeto"</string>
</resources>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 8c162ca..1e2d909 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -608,7 +608,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"Operacioni i gjurmës së gishtit u anulua."</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Veprimi i gjurmës së gishtit u anulua nga përdoruesi."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"Keni bërë shumë tentativa. Provo përsëri më vonë."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Shumë përpjekje. Sensori i gjurmës së gishtit u çaktivizua."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Shumë përpjekje. Përdor më mirë kyçjen e ekranit."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Provo përsëri."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nuk ka asnjë gjurmë gishti të regjistruar."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Kjo pajisje nuk ka sensor të gjurmës së gishtit."</string>
@@ -637,7 +637,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Vizito një ofrues të shërbimit të riparimit."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"Modeli i fytyrës nuk krijohet. Provo sërish."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Me shumë ndriçim. Provo një ndriçim më të butë."</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"Provo një ndriçim më të fortë"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"Lëvize telefonin më larg"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"Lëvize telefonin më afër"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"Lëvize telefonin më lart"</string>
@@ -1926,8 +1927,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"Preferenca e rajonit"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Shkruaj emrin e gjuhës"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"Sugjeruar"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Të sugjeruara"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"Të gjitha gjuhët"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"Të gjitha rajonet"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"Kërko"</string>
@@ -2050,8 +2050,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Të lejohet që <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> të ketë qasje te të gjitha evidencat e pajisjes?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"Lejo qasjen vetëm për një herë"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Mos lejo"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"Evidencat e pajisjes regjistrojnë çfarë ndodh në pajisjen tënde. Aplikacionet mund t\'i përdorin këto evidenca për të gjetur dhe rregulluar problemet.\n\nDisa evidenca mund të përmbajnë informacione delikate, ndaj lejo vetëm aplikacionet që u beson të kenë qasje te të gjitha evidencat e pajisjes. \n\nNëse nuk e lejon këtë aplikacion që të ketë qasje te të gjitha evidencat e pajisjes, ai mund të vazhdojë të ketë qasje tek evidencat e tij. Prodhuesi i pajisjes sate mund të jetë ende në gjendje që të ketë qasje te disa evidenca ose informacione në pajisjen tënde."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Mos e shfaq më"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> dëshiron të shfaqë pjesë të <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Modifiko"</string>
@@ -2292,7 +2291,6 @@
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Kontrollo aplikacionet aktive"</string>
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Nuk mund të qasesh në kamerën e telefonit tënd nga <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Nuk mund të qasesh në kamerën e tabletit tënd nga <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
- <!-- no translation found for vdm_secure_window (161700398158812314) -->
- <skip />
+ <string name="vdm_secure_window" msgid="161700398158812314">"Nuk mund të kesh qasje në të gjatë transmetimit. Provoje në telefon më mirë."</string>
<string name="system_locale_title" msgid="711882686834677268">"Parazgjedhja e sistemit"</string>
</resources>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 266884b..ef17368 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -609,7 +609,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"Радња са отиском прста је отказана."</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Корисник је отказао радњу са отиском прста."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"Превише покушаја. Пробајте поново касније."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Превише покушаја. Сензор за отисак прста је онемогућен."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Превише покушаја. Користите закључавање екрана уместо тога."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Пробајте поново."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Није регистрован ниједан отисак прста."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Овај уређај нема сензор за отисак прста."</string>
@@ -638,7 +638,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Посетите добављача за поправке."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"Прављење модела лица није успело. Пробајте поново."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Превише је светло. Пробајте са слабијим осветљењем."</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"Пробајте са јачим осветљењем"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"Удаљите телефон"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"Приближите телефон"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"Померите телефон нагоре"</string>
@@ -1927,8 +1928,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"Подешавање региона"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Унесите назив језика"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"Предложени"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Предложено"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"Сви језици"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"Сви региони"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"Претражи"</string>
@@ -2051,8 +2051,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Желите да дозволите апликацији <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> да приступа свим евиденцијама уређаја?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"Дозволи једнократан приступ"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Не дозволи"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"Евиденције уређаја региструју шта се дешава на уређају. Апликације могу да користе те евиденције да би пронашле и решиле проблеме.\n\nНеке евиденције могу да садрже осетљиве информације, па приступ свим евиденцијама уређаја треба да дозвољавате само апликацијама у које имате поверења. \n\nАко не дозволите овој апликацији да приступа свим евиденцијама уређаја, она и даље може да приступа сопственим евиденцијама. Произвођач уређаја ће можда и даље моћи да приступа неким евиденцијама или информацијама на уређају."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Не приказуј поново"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"Апликација <xliff:g id="APP_0">%1$s</xliff:g> жели да приказује исечке из апликације <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Измени"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 8e821c2..4e6000c 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -242,7 +242,7 @@
<string name="global_actions" product="default" msgid="6410072189971495460">"Telefonalternativ"</string>
<string name="global_action_lock" msgid="6949357274257655383">"Skärmlås"</string>
<string name="global_action_power_off" msgid="4404936470711393203">"Stäng av"</string>
- <string name="global_action_power_options" msgid="1185286119330160073">"Strömbrytare"</string>
+ <string name="global_action_power_options" msgid="1185286119330160073">"Av/på"</string>
<string name="global_action_restart" msgid="4678451019561687074">"Starta om"</string>
<string name="global_action_emergency" msgid="1387617624177105088">"Nödsituation"</string>
<string name="global_action_bug_report" msgid="5127867163044170003">"Felrapport"</string>
@@ -608,13 +608,13 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"Fingeravtrycksåtgärden avbröts."</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Fingeravtrycksåtgärden avbröts av användaren."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"Du har gjort för många försök. Försök igen senare."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Du har försökt för många gånger. Fingeravtryckssensorn har inaktiverats."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"För många försök. Använd låsskärmen i stället."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Försök igen."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Inga fingeravtryck har registrerats."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Enheten har ingen fingeravtryckssensor."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensorn har tillfälligt inaktiverats."</string>
<string name="fingerprint_error_bad_calibration" msgid="4385512597740168120">"Det går inte att använda fingeravtryckssensorn. Besök ett reparationsställe"</string>
- <string name="fingerprint_error_power_pressed" msgid="5479524500542129414">"Strömbrytaren nedtryckt"</string>
+ <string name="fingerprint_error_power_pressed" msgid="5479524500542129414">"Av/på-knappen nedtryckt"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Finger <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Använd ditt fingeravtryck"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Använd ditt fingeravtryck eller skärmlåset"</string>
@@ -637,7 +637,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Besök ett reparationsställe."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"Ansiktsmodellen kunde inte skapas. Försök igen."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Det är för ljust. Testa lägre belysning."</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"Testa med bättre belysning"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"Flytta telefonen längre bort"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"För telefonen närmare"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"Höj telefonen"</string>
@@ -1249,11 +1250,11 @@
<string name="android_preparing_apk" msgid="589736917792300956">"<xliff:g id="APPNAME">%1$s</xliff:g> förbereds."</string>
<string name="android_upgrading_starting_apps" msgid="6206161195076057075">"Appar startas."</string>
<string name="android_upgrading_complete" msgid="409800058018374746">"Uppgraderingen är klar."</string>
- <string name="fp_power_button_enrollment_message" msgid="5648173517663246140">"Du tryckte på strömbrytaren, vilket vanligtvis stänger av skärmen.\n\nTesta att trycka lätt när du konfigurerar fingeravtrycket."</string>
+ <string name="fp_power_button_enrollment_message" msgid="5648173517663246140">"Du tryckte på av/på-knappen, vilket vanligtvis stänger av skärmen.\n\nTesta att trycka lätt när du konfigurerar fingeravtrycket."</string>
<string name="fp_power_button_enrollment_title" msgid="8997641910928785172">"Tryck för att stänga av skärmen"</string>
<string name="fp_power_button_enrollment_button_text" msgid="8351290204990805109">"Stäng av skärmen"</string>
<string name="fp_power_button_bp_title" msgid="5585506104526820067">"Vill du verifiera ditt fingeravtryck?"</string>
- <string name="fp_power_button_bp_message" msgid="2983163038168903393">"Du tryckte på strömbrytaren, vilket vanligtvis stänger av skärmen.\n\nTesta att trycka lätt för att verifiera ditt fingeravtryck."</string>
+ <string name="fp_power_button_bp_message" msgid="2983163038168903393">"Du tryckte på av/på-knappen, vilket vanligtvis stänger av skärmen.\n\nTesta att trycka lätt för att verifiera ditt fingeravtryck."</string>
<string name="fp_power_button_bp_positive_button" msgid="728945472408552251">"Stäng av skärmen"</string>
<string name="fp_power_button_bp_negative_button" msgid="3971364246496775178">"Fortsätt"</string>
<string name="heavy_weight_notification" msgid="8382784283600329576">"<xliff:g id="APP">%1$s</xliff:g> körs"</string>
@@ -1926,8 +1927,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"Regionsinställningar"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Ange språk"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"Förslag"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Förslag"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"Alla språk"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"Alla regioner"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"Sök"</string>
@@ -2050,8 +2050,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Vill du tillåta att <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> får åtkomst till alla enhetsloggar?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"Tillåt engångsåtkomst"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Tillåt inte"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"I enhetsloggar registreras vad som händer på enheten. Appar kan använda dessa loggar för att hitta och åtgärda problem.\n\nVissa loggar kan innehålla känsliga uppgifter, så du ska bara bevilja appar du litar på åtkomst till alla enhetsloggar. \n\nEn app har åtkomst till sina egna loggar även om du inte ger den åtkomst till alla enhetsloggar. Enhetens tillverkare kan fortfarande ha åtkomst till vissa loggar eller viss information på enheten."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Visa inte igen"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> vill kunna visa bitar av <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Redigera"</string>
@@ -2292,7 +2291,6 @@
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Kontrollera aktiva appar"</string>
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Telefonens kamera kan inte användas från <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Surfplattans kamera kan inte användas från <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
- <!-- no translation found for vdm_secure_window (161700398158812314) -->
- <skip />
+ <string name="vdm_secure_window" msgid="161700398158812314">"Det går inte att komma åt innehållet när du streamar. Testa med telefonen i stället."</string>
<string name="system_locale_title" msgid="711882686834677268">"Systemets standardinställning"</string>
</resources>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 0557f12..0c5ae64 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -608,7 +608,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"Mchakato wa alama ya kidole umeghairiwa."</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Mtumiaji ameghairi uthibitishaji wa alama ya kidole."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"Majaribio mengi mno. Jaribu tena baadaye."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Majaribio mengi mno. Kitambua alama ya kidole kimezimwa."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Umejaribu mara nyingi mno. Badala yake, tumia mbinu ya kufunga skrini."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Jaribu tena."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Hakuna alama za vidole zilizojumuishwa."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Kifaa hiki hakina kitambua alama ya kidole."</string>
@@ -637,7 +637,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Tembelea mtoa huduma za urekebishaji."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"Imeshindwa kuunda muundo wa uso wako. Jaribu tena."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Inang\'aa mno. Jaribu mwangaza hafifu"</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"Jaribu kuongeza mwangaza"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"Sogeza simu mbali kiasi"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"Sogeza simu karibu"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"Sogeza simu juu zaidi"</string>
@@ -1567,7 +1568,7 @@
<string name="action_bar_home_subtitle_description_format" msgid="4346835454749569826">"%1$s, %2$s, %3$s"</string>
<string name="storage_internal" msgid="8490227947584914460">"Hifadhi ya ndani ya pamoja"</string>
<string name="storage_sd_card" msgid="3404740277075331881">"Kadi ya SD"</string>
- <string name="storage_sd_card_label" msgid="7526153141147470509">"Kadi ya SD iliyotengenezwa na <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
+ <string name="storage_sd_card_label" msgid="7526153141147470509">"Kadi ya SD ya <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
<string name="storage_usb_drive" msgid="448030813201444573">"Hifadhi ya USB"</string>
<string name="storage_usb_drive_label" msgid="6631740655876540521">"Hifadhi ya USB iliyotengenezwa na <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
<string name="storage_usb" msgid="2391213347883616886">"Hifadhi ya USB"</string>
@@ -1926,8 +1927,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"Mapendeleo ya eneo"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Weka jina la lugha"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"Zinazopendekezwa"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Yanayopendekezwa"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"Lugha zote"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"Maeneo yote"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"Tafuta"</string>
@@ -2050,8 +2050,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Ungependa kuruhusu <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> ifikie kumbukumbu zote za kifaa?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"Ruhusu ufikiaji wa mara moja"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Usiruhusu"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"Kumbukumbu za kifaa zinarekodi kinachofanyika kwenye kifaa chako. Programu zinaweza kutumia kumbukumbu hizi ili kutambua na kurekebisha hitilafu.\n\nBaadhi ya kumbukumbu huenda zikawa na taarifa nyeti, hivyo ruhusu tu programu unazoziamini kufikia kumbukumbu zote za kifaa. \n\nIwapo hutaruhusu programu hii ifikie kumbukumbu zote za kifaa, bado inaweza kufikia kumbukumbu zake yenyewe. Huenda mtengenezaji wa kifaa chako bado akaweza kufikia baadhi ya kumbukumbu au taarifa zilizopo kwenye kifaa chako."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Usionyeshe tena"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> inataka kuonyesha vipengee <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Badilisha"</string>
@@ -2292,7 +2291,6 @@
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Angalia programu zinazotumika"</string>
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Haiwezi kufikia kamera ya simu kutoka kwenye <xliff:g id="DEVICE">%1$s</xliff:g> yako"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Haiwezi kufikia kamera ya kompyuta kibao kutoka kwenye <xliff:g id="DEVICE">%1$s</xliff:g> yako"</string>
- <!-- no translation found for vdm_secure_window (161700398158812314) -->
- <skip />
+ <string name="vdm_secure_window" msgid="161700398158812314">"Huwezi kufikia maudhui haya unapotiririsha. Badala yake jaribu kwenye simu yako."</string>
<string name="system_locale_title" msgid="711882686834677268">"Chaguomsingi la mfumo"</string>
</resources>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index a4b89e5..9b3671e 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -608,7 +608,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"கைரேகை செயல்பாடு ரத்துசெய்யப்பட்டது."</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"பயனர், கைரேகை உறுதிப்படுத்துதலை ரத்துசெய்தார்."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"அதிகமான முயற்சிகள். பிறகு முயற்சிக்கவும்."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"பலமுறை முயன்றுவிட்டீர்கள். கைரேகை சென்சார் முடக்கப்பட்டது."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"பலமுறை முயன்றுவிட்டீர்கள். இதற்குப் பதிலாகத் திரைப்பூட்டைப் பயன்படுத்தவும்."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"மீண்டும் முயற்சிக்கவும்."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"கைரேகைப் பதிவுகள் எதுவும் இல்லை."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"இந்தச் சாதனத்தில் கைரேகை சென்சார் இல்லை."</string>
@@ -637,7 +637,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"பழுதுபார்ப்புச் சேவை வழங்குநரைத் தொடர்புகொள்ளவும்."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"முகத் தோற்றம் பதிவாகவில்லை. மீண்டும் முயலவும்."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"அதிக ஒளிர்வு. மிதமான ஒளியில் முயலவும்."</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"பிரகாசமான ஒளியில் முயலவும்"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"மொபைலை முகத்தில் இருந்து தள்ளிப் பிடிக்கவும்"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"மொபைலை அருகில் நகர்த்தவும்"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"மொபைலை மேலே நகர்த்தவும்"</string>
@@ -1926,8 +1927,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"மண்டல விருப்பம்"</string>
<string name="search_language_hint" msgid="7004225294308793583">"மொழி பெயரை உள்ளிடுக"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"பரிந்துரைகள்"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"பரிந்துரைக்கப்படுபவை"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"எல்லா மொழிகளும்"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"எல்லா மண்டலங்களும்"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"தேடு"</string>
@@ -2050,8 +2050,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"சாதனப் பதிவுகள் அனைத்தையும் <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> அணுக அனுமதிக்கவா?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"ஒருமுறை அணுகலை அனுமதி"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"அனுமதிக்க வேண்டாம்"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"உங்கள் சாதனத்தில் நடப்பவற்றைச் சாதனப் பதிவுகள் ரெக்கார்டு செய்யும். சிக்கல்களைக் கண்டறிந்து சரிசெய்ய ஆப்ஸ் இந்தப் பதிவுகளைப் பயன்படுத்தலாம்.\n\nபாதுகாக்கப்பட வேண்டிய தகவல்கள் சில பதிவுகளில் இருக்கக்கூடும் என்பதால் சாதனப் பதிவுகள் அனைத்தையும் அணுக நீங்கள் நம்பும் ஆப்ஸை மட்டும் அனுமதிக்கவும். \n\nசாதனப் பதிவுகள் அனைத்தையும் அணுக இந்த ஆப்ஸை அனுமதிக்கவில்லை என்றாலும் அதற்குச் சொந்தமான பதிவுகளை அதனால் அணுக முடியும். உங்கள் சாதனத்திலுள்ள சில பதிவுகளையோ தகவல்களையோ சாதன உற்பத்தியாளரால் தொடர்ந்து அணுக முடியும்."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"மீண்டும் காட்டாதே"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_2">%2$s</xliff:g> ஆப்ஸின் விழிப்பூட்டல்களைக் காண்பிக்க, <xliff:g id="APP_0">%1$s</xliff:g> அனுமதி கேட்கிறது"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"திருத்து"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 6937b5d..16f1b04 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -608,7 +608,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"వేలిముద్ర యాక్టివిటీ రద్దయింది."</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"వేలిముద్ర చర్యని వినియోగదారు రద్దు చేశారు."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"చాలా ఎక్కువ ప్రయత్నాలు చేశారు. తర్వాత మళ్లీ ప్రయత్నించండి."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"అనేకసార్లు ప్రయత్నించారు. వేలిముద్ర సెన్సార్ నిలిపివేయబడింది."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"చాలా ఎక్కువ సార్లు ప్రయత్నించారు. బదులుగా స్క్రీన్ లాక్ను ఉపయోగించండి."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"మళ్లీ ప్రయత్నించండి."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"వేలిముద్రలు నమోదు చేయబడలేదు."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ఈ పరికరంలో వేలిముద్ర సెన్సార్ ఎంపిక లేదు."</string>
@@ -637,7 +637,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"రిపెయిర్ ప్రొవైడర్ను సందర్శించండి."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"మీ ఫేస్మోడల్ క్రియేషన్ కుదరదు. మళ్లీ ట్రై చేయండి."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"వెలుతురు అధికంగా ఉంది. తక్కువ ఉండేలా చూడండి."</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"ప్రకాశవంతమైన లైటింగ్లో ట్రై చేయండి"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"ఫోన్ను కాస్త దూరంగా జరపండి"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"ఫోన్ను దగ్గరగా పట్టుకోండి"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"ఫోన్ను పైకి పట్టుకోండి"</string>
@@ -1926,8 +1927,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"ప్రాంతం ప్రాధాన్యత"</string>
<string name="search_language_hint" msgid="7004225294308793583">"భాష పేరును టైప్ చేయండి"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"సూచించినవి"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"సూచించబడినవి"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"అన్ని భాషలు"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"అన్ని ప్రాంతాలు"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"సెర్చ్"</string>
@@ -2050,8 +2050,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"అన్ని పరికర లాగ్లను యాక్సెస్ చేయడానికి <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g>ను అనుమతించాలా?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"వన్-టైమ్ యాక్సెస్ను అనుమతించండి"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"అనుమతించవద్దు"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"మీ పరికరంలో జరిగే దాన్ని పరికర లాగ్లు రికార్డ్ చేస్తాయి. సమస్యలను కనుగొని, పరిష్కరించడానికి యాప్లు ఈ లాగ్లను ఉపయోగిస్తాయి.\n\nకొన్ని లాగ్లలో గోప్యమైన సమాచారం ఉండవచ్చు, కాబట్టి మీరు విశ్వసించే యాప్లను మాత్రమే అన్ని పరికర లాగ్లను యాక్సెస్ చేయడానికి అనుమతించండి. \n\nఅన్ని పరికర లాగ్లను యాక్సెస్ చేయడానికి మీరు ఈ యాప్ను అనుమతించకపోతే, అది తన స్వంత లాగ్లను ఇప్పటికి యాక్సెస్ చేయగలదు. మీ పరికర తయారీదారు ఇప్పటికీ మీ పరికరంలో కొన్ని లాగ్లు లేదా సమాచారాన్ని యాక్సెస్ చేయగలరు."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"మళ్లీ చూపవద్దు"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> <xliff:g id="APP_2">%2$s</xliff:g> స్లైస్లను చూపించాలనుకుంటోంది"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"ఎడిట్ చేయండి"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index cde8a83..33f85eb 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -608,7 +608,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"ยกเลิกการทำงานของลายนิ้วมือ"</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"ผู้ใช้ยกเลิกการทำงานของลายนิ้วมือ"</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"ดำเนินการหลายครั้งเกินไป ลองอีกครั้งในภายหลัง"</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"ลองหลายครั้งเกินไป ปิดใช้เซ็นเซอร์ลายนิ้วมือแล้ว"</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"ลองหลายครั้งเกินไป ใช้การล็อกหน้าจอแทน"</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"ลองอีกครั้ง"</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"ไม่มีลายนิ้วมือที่ลงทะเบียน"</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"อุปกรณ์นี้ไม่มีเซ็นเซอร์ลายนิ้วมือ"</string>
@@ -637,7 +637,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"โปรดติดต่อผู้ให้บริการซ่อม"</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"สร้างรูปแบบใบหน้าไม่ได้ โปรดลองอีกครั้ง"</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"สว่างเกินไป ลองหาตำแหน่งที่แสงน้อยกว่านี้"</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"ลองหาตำแหน่งที่สว่างขึ้น"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"ถือโทรศัพท์ให้ห่างกว่านี้"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"ถือโทรศัพท์ให้ใกล้กว่านี้"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"ยกโทรศัพท์ให้สูงขึ้น"</string>
@@ -1426,7 +1427,7 @@
<string name="ext_media_unmount_action" msgid="966992232088442745">"นำอุปกรณ์ออก"</string>
<string name="ext_media_browse_action" msgid="344865351947079139">"สำรวจ"</string>
<string name="ext_media_seamless_action" msgid="8837030226009268080">"เปลี่ยนเอาต์พุต"</string>
- <string name="ext_media_missing_title" msgid="3209472091220515046">"ไม่มี <xliff:g id="NAME">%s</xliff:g>"</string>
+ <string name="ext_media_missing_title" msgid="3209472091220515046">"ไม่มี<xliff:g id="NAME">%s</xliff:g>"</string>
<string name="ext_media_missing_message" msgid="4408988706227922909">"ใส่อุปกรณ์อีกครั้ง"</string>
<string name="ext_media_move_specific_title" msgid="8492118544775964250">"กำลังย้าย <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="ext_media_move_title" msgid="2682741525619033637">"กำลังย้ายข้อมูล"</string>
@@ -1926,8 +1927,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"ค่ากำหนดภูมิภาค"</string>
<string name="search_language_hint" msgid="7004225294308793583">"พิมพ์ชื่อภาษา"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"แนะนำ"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"แนะนำ"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"ทุกภาษา"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"ภูมิภาคทั้งหมด"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"ค้นหา"</string>
@@ -2050,8 +2050,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"อนุญาตให้ <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> เข้าถึงบันทึกทั้งหมดของอุปกรณ์ใช่ไหม"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"อนุญาตสิทธิ์เข้าถึงแบบครั้งเดียว"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"ไม่อนุญาต"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"บันทึกของอุปกรณ์เก็บข้อมูลสิ่งที่เกิดขึ้นในอุปกรณ์ แอปสามารถใช้บันทึกเหล่านี้เพื่อค้นหาและแก้ไขปัญหา\n\nบันทึกบางรายการอาจมีข้อมูลที่ละเอียดอ่อน คุณจึงควรอนุญาตเฉพาะแอปที่เชื่อถือได้ให้เข้าถึงบันทึกทั้งหมดของอุปกรณ์ \n\nหากคุณไม่อนุญาตให้แอปนี้เข้าถึงบันทึกทั้งหมดของอุปกรณ์ แอปจะยังเข้าถึงบันทึกของตัวเองได้อยู่ ผู้ผลิตอุปกรณ์อาจยังเข้าถึงบันทึกหรือข้อมูลบางรายการในอุปกรณ์ของคุณได้"</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"ไม่ต้องแสดงอีก"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> ต้องการแสดงส่วนต่างๆ ของ <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"แก้ไข"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 9fabc83..dca19c6 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -608,7 +608,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"Nakansela ang operasyong ginagamitan ng fingerprint."</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Kinansela ng user ang operasyon sa fingerprint."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"Napakaraming pagtatangka. Subukan ulit sa ibang pagkakataon."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Masyadong maraming beses sumubok. Na-disable ang sensor para sa fingerprint."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Masyadong maraming pagsubok. Gamitin na lang ang lock ng screen."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Subukang muli."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Walang naka-enroll na fingerprint."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Walang sensor ng fingerprint ang device na ito."</string>
@@ -637,7 +637,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Bumisita sa provider ng pag-aayos."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"Hindi magawa ang iyong face model. Subukan ulit."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Masyadong maliwanag. Subukang bawasan ang liwanag."</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"Subukan sa mas maliwanag"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"Ilayo pa ang telepono"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"Ilapit pa ang telepono"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"Itaas pa ang telepono"</string>
@@ -1427,7 +1428,7 @@
<string name="ext_media_browse_action" msgid="344865351947079139">"I-explore"</string>
<string name="ext_media_seamless_action" msgid="8837030226009268080">"Ilipat ang output"</string>
<string name="ext_media_missing_title" msgid="3209472091220515046">"Nawawala ang <xliff:g id="NAME">%s</xliff:g>"</string>
- <string name="ext_media_missing_message" msgid="4408988706227922909">"Ikabit muli ang device"</string>
+ <string name="ext_media_missing_message" msgid="4408988706227922909">"Ikabit ulit ang device"</string>
<string name="ext_media_move_specific_title" msgid="8492118544775964250">"Inililipat ang <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="ext_media_move_title" msgid="2682741525619033637">"Naglilipat ng data"</string>
<string name="ext_media_move_success_title" msgid="4901763082647316767">"Tapos na ang paglipat ng content"</string>
@@ -1926,8 +1927,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"Kagustuhan sa rehiyon"</string>
<string name="search_language_hint" msgid="7004225294308793583">"I-type ang wika"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"Iminumungkahi"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Iminumungkahi"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"Lahat ng wika"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"Lahat ng rehiyon"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"Maghanap"</string>
@@ -2050,8 +2050,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Payagan ang <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> na i-access ang lahat ng log ng device?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"Payagan ang isang beses na pag-access"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Huwag payagan"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"Nire-record ng mga log ng device kung ano ang nangyayari sa iyong device. Magagamit ng mga app ang mga log na ito para maghanap at mag-ayos ng mga isyu.\n\nPosibleng maglaman ang ilang log ng sensitibong impormasyon, kaya ang mga app lang na pinagkakatiwalaan mo ang payagang maka-access sa lahat ng log ng device. \n\nKung hindi mo papayagan ang app na ito na i-access ang lahat ng log ng device, maa-access pa rin nito ang mga sarili nitong log. Posible pa ring ma-access ng manufacturer ng iyong device ang ilang log o impormasyon sa device mo."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Huwag ipakita ulit"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"Gustong ipakita ng <xliff:g id="APP_0">%1$s</xliff:g> ang mga slice ng <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"I-edit"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 638e51c..02d6180 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -608,7 +608,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"Parmak izi işlemi iptal edildi."</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Parmak izi işlemi kullanıcı tarafından iptal edildi."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"Çok fazla deneme yapıldı. Daha sonra tekrar deneyin."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Çok fazla deneme yapıldı. Parmak izi sensörü devre dışı bırakıldı."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Çok fazla deneme yapıldı. Bunun yerine ekran kilidini kullanın."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Tekrar deneyin."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Parmak izi kaydedilmedi."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Bu cihazda parmak izi sensörü yok."</string>
@@ -637,7 +637,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Bir onarım hizmeti sağlayıcıyı ziyaret edin."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"Yüzünüzün modeli oluşturulamıyor. Tekrar deneyin."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Çok parlak. Parlaklığı daha az bir ışıklandırma deneyin."</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"Daha parlak ışıkta deneyin"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"Telefonu uzaklaştırın"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"Telefonu yaklaştırın"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"Telefonu daha yukarı kaldırın"</string>
@@ -1595,7 +1596,7 @@
<string name="validity_period" msgid="1717724283033175968">"Geçerlilik:"</string>
<string name="issued_on" msgid="5855489688152497307">"Yayınlanma tarihi:"</string>
<string name="expires_on" msgid="1623640879705103121">"Sona erme tarihi:"</string>
- <string name="serial_number" msgid="3479576915806623429">"Seri numara:"</string>
+ <string name="serial_number" msgid="3479576915806623429">"Seri numarası:"</string>
<string name="fingerprints" msgid="148690767172613723">"Parmak izleri:"</string>
<string name="sha256_fingerprint" msgid="7103976380961964600">"SHA-256 parmak izi:"</string>
<string name="sha1_fingerprint" msgid="2339915142825390774">"SHA-1 parmak izi:"</string>
@@ -1926,8 +1927,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"Bölge tercihi"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Dil adını yazın"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"Önerilen"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Önerilen"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"Tüm diller"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"Tüm bölgeler"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"Ara"</string>
@@ -2050,8 +2050,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> uygulamasının tüm cihaz günlüklerine erişmesine izin verilsin mi?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"Tek seferlik erişim izni ver"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"İzin verme"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"Cihaz günlükleri, cihazınızda olanları kaydeder. Uygulamalar, sorunları bulup düzeltmek için bu günlükleri kullanabilir.\n\nBazı günlükler hassas bilgiler içerebileceği için yalnızca güvendiğiniz uygulamaların tüm cihaz günlüklerine erişmesine izin verin. \n\nBu uygulamanın tüm cihaz günlüklerine erişmesine izin vermeseniz de kendi günlüklerine erişmeye devam edebilir. Ayrıca, cihaz üreticiniz de cihazınızdaki bazı günlüklere veya bilgilere erişmeye devam edebilir."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Bir daha gösterme"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> uygulaması, <xliff:g id="APP_2">%2$s</xliff:g> dilimlerini göstermek istiyor"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Düzenle"</string>
@@ -2292,7 +2291,6 @@
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Etkin uygulamaları kontrol edin"</string>
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"<xliff:g id="DEVICE">%1$s</xliff:g> cihazınızdan telefonun kamerasına erişilemiyor"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"<xliff:g id="DEVICE">%1$s</xliff:g> cihazınızdan tabletin kamerasına erişilemiyor"</string>
- <!-- no translation found for vdm_secure_window (161700398158812314) -->
- <skip />
+ <string name="vdm_secure_window" msgid="161700398158812314">"Canlı oynatılırken bu içeriğe erişilemez. Bunun yerine telefonunuzu kullanmayı deneyin."</string>
<string name="system_locale_title" msgid="711882686834677268">"Sistem varsayılanı"</string>
</resources>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index b038ccf..d2c63a5 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -610,7 +610,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"Дію з відбитком пальця скасовано."</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Користувач скасував дію з відбитком пальця."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"Забагато спроб. Спробуйте пізніше."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Забагато спроб. Сканер відбитків пальців вимкнено."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Забагато спроб. Використайте натомість розблокування екрана."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Повторіть спробу."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Відбитки пальців не зареєстровано."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"На цьому пристрої немає сканера відбитків пальців."</string>
@@ -639,7 +639,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Зверніться до постачальника послуг із ремонту."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"Модель обличчя не створено. Повторіть спробу."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Занадто яскраво. Потрібно менше світла."</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"Потрібно більше світла"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"Тримайте телефон далі від обличчя"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"Тримайте телефон ближче до обличчя"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"Підніміть телефон вище"</string>
@@ -1928,8 +1929,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"Вибір регіону"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Введіть назву мови"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"Рекомендовані"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Пропоновані"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"Усі мови"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"Усі регіони"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"Пошук"</string>
@@ -2052,8 +2052,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Надати додатку <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> доступ до всіх журналів пристрою?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"Надати доступ лише цього разу"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Не дозволяти"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"У журналах пристрою реєструється все, що відбувається на ньому. За допомогою цих журналів додатки можуть виявляти й усувати проблеми.\n\nДеякі журнали можуть містити конфіденційні дані, тому надавати доступ до всіх журналів пристрою слід лише надійним додаткам. \n\nЯкщо додаток не має доступу до всіх журналів пристрою, він усе одно може використовувати власні журнали. Виробник вашого пристрою все одно може використовувати деякі журнали чи інформацію на ньому."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Більше не показувати"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> хоче показати фрагменти додатка <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Редагувати"</string>
@@ -2294,7 +2293,6 @@
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Перевірте активні додатки"</string>
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Не вдається отримати доступ до камери телефона з пристрою <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Не вдається отримати доступ до камери планшета з пристрою <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
- <!-- no translation found for vdm_secure_window (161700398158812314) -->
- <skip />
+ <string name="vdm_secure_window" msgid="161700398158812314">"Цей контент недоступний під час потокового передавання. Спробуйте натомість скористатися телефоном."</string>
<string name="system_locale_title" msgid="711882686834677268">"Налаштування системи за умовчанням"</string>
</resources>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index d6ff559..85f63d4 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -608,7 +608,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"فنگر پرنٹ کی کارروائی منسوخ ہوگئی۔"</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"صارف نے فنگر پرنٹ کی کارروائی منسوخ کر دی۔"</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"کافی زیادہ کوششیں کی گئیں۔ بعد میں دوبارہ کوشش کریں۔"</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"کافی زیادہ کوششیں۔ فنگر پرنٹ سینسر غیر فعال ہو گیا۔"</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"کافی زیادہ کوششیں۔ اس کے بجائے اسکرین لاک کا استعمال کریں۔"</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"دوبارہ کوشش کریں۔"</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"کوئی فنگر پرنٹ مندرج شدہ نہیں ہے۔"</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"اس آلہ میں فنگر پرنٹ سینسر نہیں ہے۔"</string>
@@ -637,7 +637,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"ایک مرمت فراہم کنندہ کو ملاحظہ کریں۔"</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"آپکے چہرے کا ماڈل تخلیق نہیں ہو سکا۔ پھر کوشش کریں۔"</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"کافی روشنی ہے۔ ہلکی روشنی میں آزمائیں۔"</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"تیز روشنی میں آزمائیں"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"فون کو تھوڑا دور کریں"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"فون کو تھوڑا قریب کریں"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"فون کو تھوڑا اوپر لے جائیں"</string>
@@ -1926,8 +1927,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"علاقہ کی ترجیح"</string>
<string name="search_language_hint" msgid="7004225294308793583">"زبان کا نام ٹائپ کریں"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"تجویز کردہ"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"تجویز کردہ"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"سبھی زبانیں"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"تمام علاقے"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"تلاش"</string>
@@ -2050,8 +2050,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> کو آلے کے تمام لاگز تک رسائی کی اجازت دیں؟"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"یک وقتی رسائی کی اجازت دیں"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"اجازت نہ دیں"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"آپ کے آلے پر جو ہوتا ہے آلے کے لاگز اسے ریکارڈ کر لیتے ہیں۔ ایپس ان لاگز کا استعمال مسائل کو تلاش کرنے اور ان کو حل کرنے کے لیے کر سکتی ہیں۔\n\nکچھ لاگز میں حساس معلومات شامل ہو سکتی ہیں، اس لیے صرف اپنے بھروسے مند ایپس کو ہی آلے کے تمام لاگز تک رسائی کی اجازت دیں۔ \n\nاگر آپ اس ایپ کو آلے کے تمام لاگز تک رسائی کی اجازت نہیں دیتے ہیں تب بھی یہ اپنے لاگز تک رسائی حاصل کر سکتی ہے۔ آپ کے آلے کا مینوفیکچرر اب بھی آپ کے آلے پر کچھ لاگز یا معلومات تک رسائی حاصل کر سکتا ہے۔"</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"دوبارہ نہ دکھائیں"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> <xliff:g id="APP_2">%2$s</xliff:g> کے سلائسز دکھانا چاہتی ہے"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"ترمیم کریں"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index d27bcd9..473c0c8 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -608,7 +608,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"Barmoq izi tekshiruvi bekor qilindi."</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Barmoq izi amali foydalanuvchi tomonidan bekor qilindi"</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"Urinishlar soni ko‘payib ketdi. Keyinroq qayta urinib ko‘ring."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Urinishlar soni ko‘payib ketdi. Barmoq izi skaneri bloklandi."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Juda koʻp urinildi. Ekran qulfi orqali urining."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Qayta urinib ko‘ring."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Hech qanday barmoq izi qayd qilinmagan."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Bu qurilmada barmoq izi skaneri mavjud emas."</string>
@@ -637,7 +637,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Xizmat koʻrsatish markaziga murojaat qiling."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"Yuzingiz modeli yaratilmadi. Qayta urining."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Juda yorqin. Biroz soyaroq joy tanlang."</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"Atrofingizni yanada yoriting"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"Telefonni biroz uzoqroq tuting"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"Telefonni yaqinroq tuting"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"Telefonni teparoq tuting"</string>
@@ -1424,10 +1425,10 @@
<string name="ext_media_unmounting_notification_message" msgid="5717036261538754203">"Chiqarib olinmasin"</string>
<string name="ext_media_init_action" msgid="2312974060585056709">"Sozlash"</string>
<string name="ext_media_unmount_action" msgid="966992232088442745">"Chiqarish"</string>
- <string name="ext_media_browse_action" msgid="344865351947079139">"O‘rganish"</string>
+ <string name="ext_media_browse_action" msgid="344865351947079139">"Ochish"</string>
<string name="ext_media_seamless_action" msgid="8837030226009268080">"Audio chiqishni almashtirish"</string>
<string name="ext_media_missing_title" msgid="3209472091220515046">"<xliff:g id="NAME">%s</xliff:g> topilmadi"</string>
- <string name="ext_media_missing_message" msgid="4408988706227922909">"Qurilmani yana ulang"</string>
+ <string name="ext_media_missing_message" msgid="4408988706227922909">"Qurilmani qayta ulang"</string>
<string name="ext_media_move_specific_title" msgid="8492118544775964250">"<xliff:g id="NAME">%s</xliff:g> ko‘chirib o‘tkazilmoqda"</string>
<string name="ext_media_move_title" msgid="2682741525619033637">"Ma’lumotlar ko‘chirilmoqda"</string>
<string name="ext_media_move_success_title" msgid="4901763082647316767">"Kontent ko‘chirildi"</string>
@@ -1926,8 +1927,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"Hudud sozlamalari"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Til nomini kiriting"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"Taklif etiladi"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Tavsiya etiladi"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"Barcha tillar"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"Barcha hududlar"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"Qidiruv"</string>
@@ -2050,8 +2050,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> ilovasining qurilmadagi barcha jurnallarga kirishiga ruxsat berilsinmi?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"Bir matalik foydalanishga ruxsat berish"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Rad etish"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"Qurilma jurnaliga qurilma bilan yuz bergan hodisalar qaydlari yoziladi. Ilovalar bu jurnal qaydlari yordamida muammolarni topishi va bartaraf qilishi mumkin.\n\nAyrim jurnal qaydlarida maxfiy axborotlar yozilishi mumkin, shu sababli qurilmadagi barcha jurnal qaydlariga ruxsatni faqat ishonchli ilovalarga bering. \n\nBu ilovaga qurilmadagi barcha jurnal qaydlariga ruxsat berilmasa ham, u oʻzining jurnalini ocha oladi. Qurilma ishlab chiqaruvchisi ham ayrim jurnallar yoki qurilma haqidagi axborotlarni ocha oladi."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Boshqa chiqmasin"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> ilovasi <xliff:g id="APP_2">%2$s</xliff:g> ilovasidan fragmentlar ko‘rsatish uchun ruxsat so‘ramoqda"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Tahrirlash"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 3c260c9..48efde40 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -608,7 +608,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"Thao tác dùng dấu vân tay bị hủy."</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Người dùng đã hủy thao tác dùng dấu vân tay."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"Quá nhiều lần thử. Hãy thử lại sau."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Quá nhiều lần thử. Cảm biến vân tay đã bị tắt."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Bạn đã thử quá nhiều lần. Hãy dùng phương thức khoá màn hình."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Thử lại."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Chưa đăng ký vân tay."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Thiết bị này không có cảm biến vân tay."</string>
@@ -637,7 +637,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Hãy liên hệ với một nhà cung cấp dịch vụ sửa chữa."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"Không thể tạo mẫu khuôn mặt của bạn. Hãy thử lại."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Quá sáng. Hãy thử giảm độ sáng."</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"Hãy thử tăng độ sáng"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"Đưa điện thoại ra xa hơn"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"Đưa điện thoại lại gần hơn"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"Nâng điện thoại lên cao hơn"</string>
@@ -1423,7 +1424,7 @@
<string name="ext_media_unmounting_notification_title" msgid="4147986383917892162">"Đang ngắt kết nối <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="ext_media_unmounting_notification_message" msgid="5717036261538754203">"Không tháo"</string>
<string name="ext_media_init_action" msgid="2312974060585056709">"Thiết lập"</string>
- <string name="ext_media_unmount_action" msgid="966992232088442745">"Tháo"</string>
+ <string name="ext_media_unmount_action" msgid="966992232088442745">"Ngắt kết nối"</string>
<string name="ext_media_browse_action" msgid="344865351947079139">"Khám phá"</string>
<string name="ext_media_seamless_action" msgid="8837030226009268080">"Chuyển đổi đầu ra"</string>
<string name="ext_media_missing_title" msgid="3209472091220515046">"<xliff:g id="NAME">%s</xliff:g> bị thiếu"</string>
@@ -1926,8 +1927,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"Tùy chọn khu vực"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Nhập tên ngôn ngữ"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"Đề xuất"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Ðề xuất"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"Tất cả ngôn ngữ"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"Tất cả khu vực"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"Tìm kiếm"</string>
@@ -2050,8 +2050,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Cho phép <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> truy cập vào tất cả các nhật ký thiết bị?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"Cho phép truy cập một lần"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Không cho phép"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"Nhật ký thiết bị ghi lại những hoạt động diễn ra trên thiết bị. Các ứng dụng có thể dùng nhật ký này để tìm và khắc phục sự cố.\n\nMột số nhật ký có thể chứa thông tin nhạy cảm, vì vậy, bạn chỉ nên cấp quyền truy cập vào toàn bộ nhật ký thiết bị cho những ứng dụng mà mình tin cậy. \n\nNếu bạn không cho phép ứng dụng này truy cập vào toàn bộ nhật ký thiết bị, thì ứng dụng vẫn có thể truy cập vào nhật ký của chính nó. Nhà sản xuất thiết bị vẫn có thể truy cập vào một số nhật ký hoặc thông tin trên thiết bị của bạn."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Không hiện lại"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> muốn hiển thị các lát của <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Chỉnh sửa"</string>
@@ -2292,7 +2291,6 @@
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Xem các ứng dụng đang hoạt động"</string>
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Không truy cập được vào máy ảnh trên điện thoại từ <xliff:g id="DEVICE">%1$s</xliff:g> của bạn"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Không truy cập được vào máy ảnh trên máy tính bảng từ <xliff:g id="DEVICE">%1$s</xliff:g> của bạn"</string>
- <!-- no translation found for vdm_secure_window (161700398158812314) -->
- <skip />
+ <string name="vdm_secure_window" msgid="161700398158812314">"Bạn không thể truy cập vào nội dung này trong khi phát trực tuyến. Hãy thử trên điện thoại."</string>
<string name="system_locale_title" msgid="711882686834677268">"Theo chế độ mặc định của hệ thống"</string>
</resources>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index e4ca303..b958269 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -608,7 +608,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"指纹操作已取消。"</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"用户取消了指纹操作。"</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"尝试次数过多,请稍后重试。"</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"尝试次数过多。指纹传感器已停用。"</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"尝试次数过多,请通过屏幕锁定功能解锁。"</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"请重试。"</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"未注册任何指纹。"</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"此设备没有指纹传感器。"</string>
@@ -637,7 +637,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"请联系维修服务提供商。"</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"无法创建您的脸部模型,请重试。"</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"亮度过高,请尝试使用较柔和的亮度。"</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"请尝试调亮光线"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"请将手机拿远一点"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"请将手机拿近一点"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"请将手机举高一点"</string>
@@ -1926,8 +1927,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"区域偏好设置"</string>
<string name="search_language_hint" msgid="7004225294308793583">"输入语言名称"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"建议语言"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"推荐地区"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"所有语言"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"所有国家/地区"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"搜索"</string>
@@ -2050,8 +2050,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"允许“<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g>”访问所有设备日志吗?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"允许访问一次"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"不允许"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"设备日志会记录设备上发生的活动。应用可以使用这些日志查找和修复问题。\n\n部分日志可能包含敏感信息,因此请仅允许您信任的应用访问所有设备日志。\n\n如果您不授予此应用访问所有设备日志的权限,它仍然可以访问自己的日志。您的设备制造商可能仍然能够访问设备上的部分日志或信息。"</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"不再显示"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"“<xliff:g id="APP_0">%1$s</xliff:g>”想要显示“<xliff:g id="APP_2">%2$s</xliff:g>”图块"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"编辑"</string>
@@ -2292,7 +2291,6 @@
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"查看使用中的应用"</string>
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"无法从<xliff:g id="DEVICE">%1$s</xliff:g>上访问手机的摄像头"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"无法从<xliff:g id="DEVICE">%1$s</xliff:g>上访问平板电脑的摄像头"</string>
- <!-- no translation found for vdm_secure_window (161700398158812314) -->
- <skip />
+ <string name="vdm_secure_window" msgid="161700398158812314">"流式传输时无法访问此内容。您可以尝试在手机上访问。"</string>
<string name="system_locale_title" msgid="711882686834677268">"系统默认设置"</string>
</resources>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 34aac7d..7ed1fe8 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -608,7 +608,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"指紋操作已取消。"</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"使用者已取消指紋操作。"</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"嘗試次數過多,請稍後再試。"</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"嘗試次數過多,指紋感應器已停用。"</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"嘗試次數過多,請改用螢幕鎖定功能。"</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"再試一次。"</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"未註冊任何指紋"</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"此裝置沒有指紋感應器。"</string>
@@ -637,7 +637,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"請諮詢維修服務供應商。"</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"無法建立面部模型,請再試一次。"</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"影像太亮。請嘗試在更暗的環境下使用。"</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"請試用更充足的光線"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"請將手機移開一點"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"請將手機移近一點"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"請將手機向上移"</string>
@@ -1926,8 +1927,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"地區偏好設定"</string>
<string name="search_language_hint" msgid="7004225294308793583">"輸入語言名稱"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"建議"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"建議的語言"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"所有語言"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"所有國家/地區"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"搜尋"</string>
@@ -2050,8 +2050,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"要允許「<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g>」存取所有裝置記錄嗎?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"允許存取一次"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"不允許"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"裝置記錄會記下裝置上的活動。應用程式可透過這些記錄找出並修正問題。\n\n部分記錄可能包含敏感資料,因此請只允許信任的應用程式存取所有裝置記錄。\n\n如果不允許此應用程式存取所有裝置記錄,此應用程式仍能存取自己的記錄,且裝置製造商可能仍可存取裝置上的部分記錄或資料。"</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"不要再顯示"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"「<xliff:g id="APP_0">%1$s</xliff:g>」想顯示「<xliff:g id="APP_2">%2$s</xliff:g>」的快訊"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"編輯"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 9a11889..1c9f92c 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -608,7 +608,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"指紋作業已取消。"</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"使用者已取消指紋驗證作業。"</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"嘗試次數過多,請稍後再試。"</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"嘗試次數過多,指紋感應器已停用。"</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"嘗試次數過多,請改用螢幕鎖定功能。"</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"請再試一次。"</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"未登錄任何指紋。"</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"這個裝置沒有指紋感應器。"</string>
@@ -637,7 +637,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"請洽詢維修供應商。"</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"無法建立臉部模型,請再試一次。"</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"亮度過高,請嘗試使用較柔和的照明方式。"</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"請採用更明亮的光源"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"請將手機拿遠一點"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"請將手機拿近一點"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"請將手機舉高一點"</string>
@@ -1926,8 +1927,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"地區偏好設定"</string>
<string name="search_language_hint" msgid="7004225294308793583">"請輸入語言名稱"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"建議語言"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"建議的語言"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"所有語言"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"所有地區"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"搜尋"</string>
@@ -2050,8 +2050,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"要允許「<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g>」存取所有裝置記錄嗎?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"允許一次性存取"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"不允許"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"系統會透過裝置記錄記下裝置上的活動。應用程式可以根據這些記錄找出問題並進行修正。\n\n某些記錄可能含有機密資訊,因此請勿讓不信任的應用程式存取所有裝置記錄。\n\n即使你不允許這個應用程式存取所有裝置記錄,這個應用程式仍能存取自己的記錄,而且裝置製造商或許仍可存取裝置的某些記錄或資訊。"</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"不要再顯示"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"「<xliff:g id="APP_0">%1$s</xliff:g>」想要顯示「<xliff:g id="APP_2">%2$s</xliff:g>」的區塊"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"編輯"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 0872ec3..4703af8 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -608,7 +608,7 @@
<string name="fingerprint_error_canceled" msgid="540026881380070750">"Ukusebenza kwezigxivizo zeminwe kukhanseliwe."</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Umsebenzi wezigxivizo zomunwe ukhanselwe umsebenzisi."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"Imizamo eminingi kakhulu. Zama futhi emuva kwesikhathi."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Imizamo eminingi kakhulu. Inzwa yezigxivizo zeminwe ikhutshaziwe."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Imizamo eminingi kakhulu. Sebenzisa ukukhiya isikrini kunalokho."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Zama futhi."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Azikho izigxivizo zeminwe ezibhalisiwe."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Le divayisi ayinayo inzwa yezigxivizo zeminwe."</string>
@@ -637,7 +637,8 @@
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Vakashela umhlinzeki wokulungisa."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"Ayikwazi ukusungula imodeli yobuso bakho. Zama futhi."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Kukhanya kakhulu. Zama ukukhanya okuthambile."</string>
- <string name="face_acquired_too_dark" msgid="7919016380747701228">"Zama ukukhanyisa okukhudlwana"</string>
+ <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+ <skip />
<string name="face_acquired_too_close" msgid="4453646176196302462">"Yisa ifoni kude"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"Sondeza ifoni eduze"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"Yisa ifoni phezulu"</string>
@@ -1926,8 +1927,7 @@
<string name="country_selection_title" msgid="5221495687299014379">"Okuncamelayo kwesifunda"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Thayipha igama lolimi"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"Okuphakanyisiwe"</string>
- <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
- <skip />
+ <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Okuphakanyisiwe"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"Zonke izilimi"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"Zonke izifunda"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"Sesha"</string>
@@ -2050,8 +2050,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Vumela i-<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> ukuba ifinyelele wonke amalogu edivayisi?"</string>
<string name="log_access_confirmation_allow" msgid="5302517782599389507">"Vumela ukufinyelela kwesikhathi esisodwa"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Ungavumeli"</string>
- <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
- <skip />
+ <string name="log_access_confirmation_body" msgid="1806692062668620735">"Amalogu edivayisi arekhoda okwenzekayo kudivayisi yakho. Ama-app angasebenzisa lawa malogu ukuze athole futhi alungise izinkinga.\n\nAmanye amalogu angase aqukathe ulwazi olubucayi, ngakho vumela ama-app owathembayo kuphela ukuthi afinyelele wonke amalogu edivayisi. \n\nUma ungayivumeli le app ukuthi ifinyelele wonke amalogu wedivayisi, isengakwazi ukufinyelela amalogu wayo. Umkhiqizi wedivayisi yakho usengakwazi ukufinyelela amanye amalogu noma ulwazi kudivayisi yakho."</string>
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Ungabonisi futhi"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"I-<xliff:g id="APP_0">%1$s</xliff:g> ifuna ukubonisa izingcezu ze-<xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Hlela"</string>
diff --git a/core/res/res/values/bools.xml b/core/res/res/values/bools.xml
index 5fd9dc0..988303e 100644
--- a/core/res/res/values/bools.xml
+++ b/core/res/res/values/bools.xml
@@ -18,6 +18,7 @@
<bool name="kg_enable_camera_default_widget">true</bool>
<bool name="kg_center_small_widgets_vertically">false</bool>
<bool name="kg_top_align_page_shrink_on_bouncer_visible">true</bool>
+ <bool name="kg_wake_on_acquire_start">false</bool>
<bool name="action_bar_embed_tabs">true</bool>
<bool name="split_action_bar_is_narrow">true</bool>
<bool name="preferences_prefer_dual_pane">false</bool>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index ae55e36..c3b6df1 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1567,8 +1567,7 @@
<bool name="config_enableIdleScreenBrightnessMode">false</bool>
<!-- Array of desired screen brightness in nits corresponding to the lux values
- in the config_autoBrightnessLevels array. As with config_screenBrightnessMinimumNits and
- config_screenBrightnessMaximumNits, the display brightness is defined as the measured
+ in the config_autoBrightnessLevels array. The display brightness is defined as the measured
brightness of an all-white image.
If this is defined then:
@@ -1589,7 +1588,7 @@
<array name="config_autoBrightnessDisplayValuesNitsIdle">
</array>
- <!-- Array of output values for button backlight corresponding to the luX values
+ <!-- Array of output values for button backlight corresponding to the lux values
in the config_autoBrightnessLevels array. This array should have size one greater
than the size of the config_autoBrightnessLevels array.
The brightness values must be between 0 and 255 and be non-decreasing.
@@ -1734,7 +1733,7 @@
<item name="default_lock_wallpaper" type="drawable">@null</item>
<!-- Component name of the built in wallpaper used to display bitmap wallpapers. This must not be null. -->
- <string name="image_wallpaper_component" translatable="false">com.android.systemui/com.android.systemui.ImageWallpaper</string>
+ <string name="image_wallpaper_component" translatable="false">com.android.systemui/com.android.systemui.wallpapers.ImageWallpaper</string>
<!-- True if WallpaperService is enabled -->
<bool name="config_enableWallpaperService">true</bool>
@@ -2060,6 +2059,10 @@
<!-- The default volume for the ring stream -->
<integer name="config_audio_ring_vol_default">5</integer>
+ <!-- The default value for whether head tracking for
+ spatial audio is enabled for a newly connected audio device -->
+ <bool name="config_spatial_audio_head_tracking_enabled_default">false</bool>
+
<!-- Flag indicating whether platform level volume adjustments are enabled for remote sessions
on grouped devices. -->
<bool name="config_volumeAdjustmentForRemoteGroupSessions">true</bool>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index aad32b1..6ec98e8 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1696,7 +1696,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">Couldn\'t process fingerprint. Please try again.</string>
+ <string name="fingerprint_acquired_insufficient">Can\u2019t recognize fingerprint. 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>
@@ -1708,6 +1708,8 @@
<string name="fingerprint_acquired_already_enrolled">Try another fingerprint</string>
<!-- Message shown during fingerprint acquisition when fingerprint sensor detected too much light.[CHAR LIMIT=50] -->
<string name="fingerprint_acquired_too_bright">Too bright</string>
+ <!-- Message shown during fingerprint acquisition when a Power press has been detected.[CHAR LIMIT=50] -->
+ <string name="fingerprint_acquired_power_press">Power press detected</string>
<!-- Message shown during fingerprint acquisition when a fingerprint must be adjusted.[CHAR LIMIT=50] -->
<string name="fingerprint_acquired_try_adjusting">Try adjusting</string>
<!-- Message shown during fingerprint acquisition when a fingeprint area has already been captured during enrollment [CHAR LIMIT=100] -->
@@ -1732,17 +1734,17 @@
<!-- Error message shown when the fingerprint hardware has run out of room for storing fingerprints -->
<string name="fingerprint_error_no_space">Can\u2019t set up fingerprint</string>
<!-- Error message shown when the fingerprint hardware timer has expired and the user needs to restart the operation. -->
- <string name="fingerprint_error_timeout">Fingerprint time out reached. Try again.</string>
+ <string name="fingerprint_error_timeout">Fingerprint setup timed out. Try again.</string>
<!-- Generic error message shown when the fingerprint operation (e.g. enrollment or authentication) is canceled. Generally not shown to the user-->
<string name="fingerprint_error_canceled">Fingerprint operation canceled.</string>
<!-- Generic error message shown when the fingerprint authentication operation is canceled due to user input. Generally not shown to the user -->
<string name="fingerprint_error_user_canceled">Fingerprint operation canceled by user.</string>
<!-- Generic error message shown when the fingerprint operation fails because too many attempts have been made. -->
- <string name="fingerprint_error_lockout">Too many attempts. Try again later.</string>
+ <string name="fingerprint_error_lockout">Too many attempts. Use screen lock instead.</string>
<!-- Generic error message shown when the fingerprint operation fails because strong authentication is required -->
<string name="fingerprint_error_lockout_permanent">Too many attempts. Use screen lock instead.</string>
<!-- Generic error message shown when the fingerprint hardware can't recognize the fingerprint -->
- <string name="fingerprint_error_unable_to_process">Try again.</string>
+ <string name="fingerprint_error_unable_to_process">Can\u2019t process fingerprint. Try again.</string>
<!-- Generic error message shown when the user has no enrolled fingerprints -->
<string name="fingerprint_error_no_fingerprints">No fingerprints enrolled.</string>
<!-- Generic error message shown when the app requests fingerprint authentication on a device without a sensor -->
@@ -1804,7 +1806,7 @@
<!-- Message shown during face acquisition when the image is too bright [CHAR LIMIT=50] -->
<string name="face_acquired_too_bright">Too bright. Try gentler lighting.</string>
<!-- Message shown during face acquisition when the image is too dark [CHAR LIMIT=50] -->
- <string name="face_acquired_too_dark">Try brighter lighting</string>
+ <string name="face_acquired_too_dark">Not enough light</string>
<!-- Message shown during face acquisition when the user is too close to sensor [CHAR LIMIT=50] -->
<string name="face_acquired_too_close">Move phone farther away</string>
<!-- Message shown during face acquisition when the user is too far from sensor [CHAR LIMIT=50] -->
@@ -3574,11 +3576,11 @@
<!-- [CHAR LIMIT=40] Title of dialog shown to confirm device going to sleep if the power button
is pressed during fingerprint enrollment. -->
- <string name="fp_power_button_enrollment_title">Tap to turn off screen</string>
+ <string name="fp_power_button_enrollment_title">To end setup, turn off screen</string>
<!-- [CHAR LIMIT=20] Positive button of dialog shown to confirm device going to sleep if the
power button is pressed during fingerprint enrollment. -->
- <string name="fp_power_button_enrollment_button_text">Turn off screen</string>
+ <string name="fp_power_button_enrollment_button_text">Turn off</string>
<!-- [CHAR LIMIT=40] Title of dialog shown to confirm device going to sleep if the power button
is pressed during biometric prompt when a side fingerprint sensor is present. -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 123770e..6c6a0a3 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -79,6 +79,11 @@
<java-symbol type="id" name="deny_button" />
<java-symbol type="id" name="description" />
<java-symbol type="id" name="divider" />
+ <java-symbol type="id" name="drag" />
+ <java-symbol type="id" name="profile_pager" />
+ <java-symbol type="id" name="chooser_header" />
+ <java-symbol type="id" name="content_preview_container" />
+ <java-symbol type="id" name="profile_tabhost" />
<java-symbol type="id" name="edit_query" />
<java-symbol type="id" name="edittext_container" />
<java-symbol type="id" name="expand_activities_button" />
@@ -278,6 +283,7 @@
<java-symbol type="integer" name="config_audio_notif_vol_steps" />
<java-symbol type="integer" name="config_audio_ring_vol_default" />
<java-symbol type="integer" name="config_audio_ring_vol_steps" />
+ <java-symbol type="bool" name="config_spatial_audio_head_tracking_enabled_default" />
<java-symbol type="bool" name="config_avoidGfxAccel" />
<java-symbol type="bool" name="config_bluetooth_address_validation" />
<java-symbol type="integer" name="config_chooser_max_targets_per_row" />
@@ -2606,6 +2612,7 @@
<java-symbol type="string" name="fingerprint_acquired_imager_dirty" />
<java-symbol type="string" name="fingerprint_acquired_too_slow" />
<java-symbol type="string" name="fingerprint_acquired_too_fast" />
+ <java-symbol type="string" name="fingerprint_acquired_power_press" />
<java-symbol type="string" name="fingerprint_acquired_too_bright" />
<java-symbol type="array" name="fingerprint_acquired_vendor" />
<java-symbol type="string" name="fingerprint_error_canceled" />
@@ -2825,6 +2832,7 @@
<java-symbol type="dimen" name="fast_scroller_minimum_touch_target" />
<java-symbol type="array" name="config_cdma_international_roaming_indicators" />
<java-symbol type="string" name="kg_text_message_separator" />
+ <java-symbol type="bool" name="kg_wake_on_acquire_start" />
<java-symbol type="bool" name="config_use_sim_language_file" />
<java-symbol type="bool" name="config_LTE_eri_for_network_name" />
@@ -4273,6 +4281,7 @@
<java-symbol type="id" name="conversation_icon_badge_ring" />
<java-symbol type="id" name="conversation_icon_badge_bg" />
<java-symbol type="id" name="expand_button_container" />
+ <java-symbol type="id" name="expand_button_a11y_container" />
<java-symbol type="id" name="expand_button_touch_container" />
<java-symbol type="id" name="messaging_group_content_container" />
<java-symbol type="id" name="expand_button_and_content_container" />
diff --git a/core/tests/coretests/src/android/app/NotificationChannelGroupTest.java b/core/tests/coretests/src/android/app/NotificationChannelGroupTest.java
index 2a3da05..625c66a 100644
--- a/core/tests/coretests/src/android/app/NotificationChannelGroupTest.java
+++ b/core/tests/coretests/src/android/app/NotificationChannelGroupTest.java
@@ -17,9 +17,11 @@
package android.app;
import static junit.framework.TestCase.assertEquals;
+import static junit.framework.TestCase.assertTrue;
import android.os.Parcel;
import android.test.AndroidTestCase;
+import android.text.TextUtils;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -70,4 +72,18 @@
assertEquals(NotificationChannelGroup.MAX_TEXT_LENGTH,
fromParcel.getDescription().length());
}
+
+ @Test
+ public void testNullableFields() {
+ NotificationChannelGroup group = new NotificationChannelGroup("my_group_01", null);
+
+ Parcel parcel = Parcel.obtain();
+ group.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+
+ NotificationChannelGroup fromParcel =
+ NotificationChannelGroup.CREATOR.createFromParcel(parcel);
+ assertEquals(group.getId(), fromParcel.getId());
+ assertTrue(TextUtils.isEmpty(fromParcel.getName()));
+ }
}
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index f6499f8..ce6df20 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -3193,12 +3193,6 @@
"group": "WM_DEBUG_LOCKTASK",
"at": "com\/android\/server\/wm\/LockTaskController.java"
},
- "956467125": {
- "message": "Reparenting Activity to embedded TaskFragment, but the Activity is not collected",
- "level": "WARN",
- "group": "WM_DEBUG_WINDOW_TRANSITIONS",
- "at": "com\/android\/server\/wm\/WindowOrganizerController.java"
- },
"958338552": {
"message": "grantEmbeddedWindowFocus win=%s dropped focus so setting focus to null since no candidate was found",
"level": "VERBOSE",
diff --git a/graphics/java/android/graphics/RuntimeShader.java b/graphics/java/android/graphics/RuntimeShader.java
index 6abe34b..9c36fc3 100644
--- a/graphics/java/android/graphics/RuntimeShader.java
+++ b/graphics/java/android/graphics/RuntimeShader.java
@@ -214,7 +214,7 @@
* uniform shader myShader;
* vec4 main(vec2 canvas_coordinates) {
* // swap the red and blue color channels when sampling from myShader
- * return myShader.sample(canvas_coordinates).bgra;
+ * return myShader.eval(canvas_coordinates).bgra;
* }</pre>
*
* <p>After creating a {@link RuntimeShader} with that program the shader uniform can
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
index 5727b91..6af3d2b 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
@@ -583,7 +583,7 @@
}
if (!isOnReparent && getContainerWithActivity(activity) == null
- && getInitialTaskFragmentToken(activity) != null) {
+ && getTaskFragmentTokenFromActivityClientRecord(activity) != null) {
// We can't find the new launched activity in any recorded container, but it is
// currently placed in an embedded TaskFragment. This can happen in two cases:
// 1. the activity is embedded in another app.
@@ -866,11 +866,12 @@
}
@VisibleForTesting
+ @GuardedBy("mLock")
void onActivityDestroyed(@NonNull Activity activity) {
// Remove any pending appeared activity, as the server won't send finished activity to the
// organizer.
for (int i = mTaskContainers.size() - 1; i >= 0; i--) {
- mTaskContainers.valueAt(i).cleanupPendingAppearedActivity(activity);
+ mTaskContainers.valueAt(i).onActivityDestroyed(activity);
}
// We didn't trigger the callback if there were any pending appeared activities, so check
// again after the pending is removed.
@@ -900,6 +901,36 @@
mPresenter.cleanupContainer(wct, container, false /* shouldFinishDependent */);
}
+ @Nullable
+ @GuardedBy("mLock")
+ private TaskFragmentContainer resolveStartActivityIntentFromNonActivityContext(
+ @NonNull WindowContainerTransaction wct, @NonNull Intent intent) {
+ final int taskCount = mTaskContainers.size();
+ if (taskCount == 0) {
+ // We don't have other Activity to check split with.
+ return null;
+ }
+ if (taskCount > 1) {
+ Log.w(TAG, "App is calling startActivity from a non-Activity context when it has"
+ + " more than one Task. If the new launch Activity is in a different process,"
+ + " and it is expected to be embedded, please start it from an Activity"
+ + " instead.");
+ return null;
+ }
+
+ // Check whether the Intent should be embedded in the known Task.
+ final TaskContainer taskContainer = mTaskContainers.valueAt(0);
+ if (taskContainer.isInPictureInPicture()
+ || taskContainer.getTopNonFinishingActivity() == null) {
+ // We don't embed activity when it is in PIP, or if we can't find any other owner
+ // activity in the Task.
+ return null;
+ }
+
+ return resolveStartActivityIntent(wct, taskContainer.getTaskId(), intent,
+ null /* launchingActivity */);
+ }
+
/**
* When we are trying to handle a new activity Intent, returns the {@link TaskFragmentContainer}
* that we should reparent the new activity to if there is any embedding rule matched.
@@ -1605,15 +1636,16 @@
}
/**
- * Gets the token of the initial TaskFragment that embedded this activity. Do not rely on it
- * after creation because the activity could be reparented.
+ * Gets the token of the TaskFragment that embedded this activity. It is available as soon as
+ * the activity is created and attached, so it can be used during {@link #onActivityCreated}
+ * before the server notifies the organizer to avoid racing condition.
*/
@VisibleForTesting
@Nullable
- IBinder getInitialTaskFragmentToken(@NonNull Activity activity) {
+ IBinder getTaskFragmentTokenFromActivityClientRecord(@NonNull Activity activity) {
final ActivityThread.ActivityClientRecord record = ActivityThread.currentActivityThread()
.getActivityClient(activity.getActivityToken());
- return record != null ? record.mInitialTaskFragmentToken : null;
+ return record != null ? record.mTaskFragmentToken : null;
}
/**
@@ -1691,7 +1723,8 @@
@Nullable Bundle savedInstanceState) {
synchronized (mLock) {
final IBinder activityToken = activity.getActivityToken();
- final IBinder initialTaskFragmentToken = getInitialTaskFragmentToken(activity);
+ final IBinder initialTaskFragmentToken =
+ getTaskFragmentTokenFromActivityClientRecord(activity);
// If the activity is not embedded, then it will not have an initial task fragment
// token so no further action is needed.
if (initialTaskFragmentToken == null) {
@@ -1774,23 +1807,38 @@
@Override
public Instrumentation.ActivityResult onStartActivity(@NonNull Context who,
@NonNull Intent intent, @NonNull Bundle options) {
- // TODO(b/190433398): Check if the activity is configured to always be expanded.
+ // TODO(b/232042367): Consolidate the activity create handling so that we can handle
+ // cross-process the same as normal.
- // Check if activity should be put in a split with the activity that launched it.
- if (!(who instanceof Activity)) {
- return super.onStartActivity(who, intent, options);
- }
- final Activity launchingActivity = (Activity) who;
- if (isInPictureInPicture(launchingActivity)) {
- // We don't embed activity when it is in PIP.
- return super.onStartActivity(who, intent, options);
+ final Activity launchingActivity;
+ if (who instanceof Activity) {
+ // We will check if the new activity should be split with the activity that launched
+ // it.
+ launchingActivity = (Activity) who;
+ if (isInPictureInPicture(launchingActivity)) {
+ // We don't embed activity when it is in PIP.
+ return super.onStartActivity(who, intent, options);
+ }
+ } else {
+ // When the context to start activity is not an Activity context, we will check if
+ // the new activity should be embedded in the known Task belonging to the organizer
+ // process. @see #resolveStartActivityIntentFromNonActivityContext
+ // It is a current security limitation that we can't access the activity info of
+ // other process even if it is in the same Task.
+ launchingActivity = null;
}
synchronized (mLock) {
- final int taskId = getTaskId(launchingActivity);
final WindowContainerTransaction wct = new WindowContainerTransaction();
- final TaskFragmentContainer launchedInTaskFragment = resolveStartActivityIntent(wct,
- taskId, intent, launchingActivity);
+ final TaskFragmentContainer launchedInTaskFragment;
+ if (launchingActivity != null) {
+ final int taskId = getTaskId(launchingActivity);
+ launchedInTaskFragment = resolveStartActivityIntent(wct, taskId, intent,
+ launchingActivity);
+ } else {
+ launchedInTaskFragment = resolveStartActivityIntentFromNonActivityContext(wct,
+ intent);
+ }
if (launchedInTaskFragment != null) {
// Make sure the WCT is applied immediately instead of being queued so that the
// TaskFragment will be ready before activity attachment.
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
index 45645b2..b563677 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
@@ -137,6 +137,13 @@
return mContainers.isEmpty() && mFinishedContainer.isEmpty();
}
+ /** Called when the activity is destroyed. */
+ void onActivityDestroyed(@NonNull Activity activity) {
+ for (TaskFragmentContainer container : mContainers) {
+ container.onActivityDestroyed(activity);
+ }
+ }
+
/** Removes the pending appeared activity from all TaskFragments in this Task. */
void cleanupPendingAppearedActivity(@NonNull Activity pendingAppearedActivity) {
for (TaskFragmentContainer container : mContainers) {
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
index 2843b14..626e0d9 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
@@ -19,6 +19,7 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import android.app.Activity;
+import android.app.ActivityThread;
import android.app.WindowConfiguration.WindowingMode;
import android.content.Intent;
import android.graphics.Rect;
@@ -190,6 +191,19 @@
// Remove the pending activity from other TaskFragments.
mTaskContainer.cleanupPendingAppearedActivity(pendingAppearedActivity);
mPendingAppearedActivities.add(pendingAppearedActivity);
+ updateActivityClientRecordTaskFragmentToken(pendingAppearedActivity);
+ }
+
+ /**
+ * Updates the {@link ActivityThread.ActivityClientRecord#mTaskFragmentToken} for the
+ * activity. This makes sure the token is up-to-date if the activity is relaunched later.
+ */
+ private void updateActivityClientRecordTaskFragmentToken(@NonNull Activity activity) {
+ final ActivityThread.ActivityClientRecord record = ActivityThread
+ .currentActivityThread().getActivityClient(activity.getActivityToken());
+ if (record != null) {
+ record.mTaskFragmentToken = mToken;
+ }
}
void removePendingAppearedActivity(@NonNull Activity pendingAppearedActivity) {
@@ -197,8 +211,29 @@
}
void clearPendingAppearedActivities() {
+ final List<Activity> cleanupActivities = new ArrayList<>(mPendingAppearedActivities);
+ // Clear mPendingAppearedActivities so that #getContainerWithActivity won't return the
+ // current TaskFragment.
mPendingAppearedActivities.clear();
mPendingAppearedIntent = null;
+
+ // For removed pending activities, we need to update the them to their previous containers.
+ for (Activity activity : cleanupActivities) {
+ final TaskFragmentContainer curContainer = mController.getContainerWithActivity(
+ activity);
+ if (curContainer != null) {
+ curContainer.updateActivityClientRecordTaskFragmentToken(activity);
+ }
+ }
+ }
+
+ /** Called when the activity is destroyed. */
+ void onActivityDestroyed(@NonNull Activity activity) {
+ removePendingAppearedActivity(activity);
+ if (mInfo != null) {
+ // Remove the activity now because there can be a delay before the server callback.
+ mInfo.getActivities().remove(activity.getActivityToken());
+ }
}
@Nullable
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
index 4dbbc04..58870a6 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
@@ -930,7 +930,8 @@
@Test
public void testResolveActivityToContainer_inUnknownTaskFragment() {
- doReturn(new Binder()).when(mSplitController).getInitialTaskFragmentToken(mActivity);
+ doReturn(new Binder()).when(mSplitController)
+ .getTaskFragmentTokenFromActivityClientRecord(mActivity);
// No need to handle when the new launched activity is in an unknown TaskFragment.
assertTrue(mSplitController.resolveActivityToContainer(mTransaction, mActivity,
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java
index 1bc81ee..082774e 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java
@@ -316,6 +316,25 @@
assertEquals(activity, container.getBottomMostActivity());
}
+ @Test
+ public void testOnActivityDestroyed() {
+ final TaskContainer taskContainer = new TaskContainer(TASK_ID);
+ final TaskFragmentContainer container = new TaskFragmentContainer(null /* activity */,
+ mIntent, taskContainer, mController);
+ container.addPendingAppearedActivity(mActivity);
+ final List<IBinder> activities = new ArrayList<>();
+ activities.add(mActivity.getActivityToken());
+ doReturn(activities).when(mInfo).getActivities();
+ container.setInfo(mTransaction, mInfo);
+
+ assertTrue(container.hasActivity(mActivity.getActivityToken()));
+
+ taskContainer.onActivityDestroyed(mActivity);
+
+ // It should not contain the destroyed Activity.
+ assertFalse(container.hasActivity(mActivity.getActivityToken()));
+ }
+
/** Creates a mock activity in the organizer process. */
private Activity createMockActivity() {
final Activity activity = mock(Activity.class);
diff --git a/libs/WindowManager/Shell/res/values-af/strings.xml b/libs/WindowManager/Shell/res/values-af/strings.xml
index e87a008..cc60074 100644
--- a/libs/WindowManager/Shell/res/values-af/strings.xml
+++ b/libs/WindowManager/Shell/res/values-af/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Kamerakwessies?\nTik om aan te pas"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nie opgelos nie?\nTik om terug te stel"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Geen kamerakwessies nie? Tik om toe te maak."</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Sommige programme werk beter in portret"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Probeer een van hierdie opsies om jou spasie ten beste te benut"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Draai jou toestel om dit volskerm te maak"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Dubbeltik langs ’n program om dit te herposisioneer"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Sien en doen meer"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Sleep ’n ander program in vir verdeelde skerm"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Dubbeltik buite ’n program om dit te herposisioneer"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Het dit"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Vou uit vir meer inligting."</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maksimeer"</string>
diff --git a/libs/WindowManager/Shell/res/values-am/strings.xml b/libs/WindowManager/Shell/res/values-am/strings.xml
index f752310..7aa8770 100644
--- a/libs/WindowManager/Shell/res/values-am/strings.xml
+++ b/libs/WindowManager/Shell/res/values-am/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"የካሜራ ችግሮች አሉ?\nዳግም ለማበጀት መታ ያድርጉ"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"አልተስተካከለም?\nለማህደር መታ ያድርጉ"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"ምንም የካሜራ ችግሮች የሉም? ለማሰናበት መታ ያድርጉ።"</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"አንዳንድ መተግበሪያዎች በቁም ፎቶ ውስጥ በተሻለ ሁኔታ ይሰራሉ"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"ቦታዎን በአግባቡ ለመጠቀም ከእነዚህ አማራጮች ውስጥ አንዱን ይሞክሩ"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"ወደ የሙሉ ገጽ ዕይታ ለመሄድ መሣሪያዎን ያሽከርክሩት"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"ቦታውን ለመቀየር ከመተግበሪያው ቀጥሎ ላይ ሁለቴ መታ ያድርጉ"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"ተጨማሪ ይመልከቱ እና ያድርጉ"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"ለተከፈለ ማያ ገጽ ሌላ መተግበሪያ ይጎትቱ"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"ቦታውን ለመቀየር ከመተግበሪያው ውጪ ሁለቴ መታ ያድርጉ"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"ገባኝ"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"ለተጨማሪ መረጃ ይዘርጉ።"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"አስፋ"</string>
diff --git a/libs/WindowManager/Shell/res/values-ar/strings.xml b/libs/WindowManager/Shell/res/values-ar/strings.xml
index 262e826..2d0d970 100644
--- a/libs/WindowManager/Shell/res/values-ar/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ar/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"هل هناك مشاكل في الكاميرا؟\nانقر لإعادة الضبط."</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"ألم يتم حل المشكلة؟\nانقر للعودة"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"أليس هناك مشاكل في الكاميرا؟ انقر للإغلاق."</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"تعمل بعض التطبيقات على أكمل وجه في الشاشات العمودية"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"جرِّب تنفيذ أحد هذه الخيارات للاستفادة من مساحتك إلى أقصى حد."</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"قم بتدوير الشاشة للانتقال إلى وضع ملء الشاشة."</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"انقر مرتين بجانب التطبيق لتغيير موضعه."</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"استخدام تطبيقات متعدّدة في وقت واحد"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"اسحب تطبيقًا آخر لاستخدام وضع تقسيم الشاشة."</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"انقر مرّتين خارج تطبيق لتغيير موضعه."</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"حسنًا"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"التوسيع للحصول على مزيد من المعلومات"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"تكبير"</string>
diff --git a/libs/WindowManager/Shell/res/values-as/strings.xml b/libs/WindowManager/Shell/res/values-as/strings.xml
index 5cfd4e5..42153ff 100644
--- a/libs/WindowManager/Shell/res/values-as/strings.xml
+++ b/libs/WindowManager/Shell/res/values-as/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"কেমেৰাৰ কোনো সমস্যা হৈছে নেকি?\nপুনৰ খাপ খোৱাবলৈ টিপক"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"এইটো সমাধান কৰা নাই নেকি?\nপূৰ্বাৱস্থালৈ নিবলৈ টিপক"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"কেমেৰাৰ কোনো সমস্যা নাই নেকি? অগ্ৰাহ্য কৰিবলৈ টিপক।"</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"কিছুমান এপে প’ৰ্ট্ৰেইট ম’ডত বেছি ভালকৈ কাম কৰে"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"আপোনাৰ spaceৰ পৰা পাৰ্যমানে উপকৃত হ’বলৈ ইয়াৰে এটা বিকল্প চেষ্টা কৰি চাওক"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"পূৰ্ণ স্ক্ৰীনলৈ যাবলৈ আপোনাৰ ডিভাইচটো ঘূৰাওক"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"এপ্টোৰ স্থান সলনি কৰিবলৈ ইয়াৰ কাষত দুবাৰ টিপক"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"চাওক আৰু অধিক কৰক"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"বিভাজিত স্ক্ৰীনৰ বাবে অন্য এটা এপ্ টানি আনি এৰক"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"এপ্টোৰ স্থান সলনি কৰিবলৈ ইয়াৰ বাহিৰত দুবাৰ টিপক"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"বুজি পালোঁ"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"অধিক তথ্যৰ বাবে বিস্তাৰ কৰক।"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"সৰ্বাধিক মাত্ৰালৈ বঢ়াওক"</string>
diff --git a/libs/WindowManager/Shell/res/values-az/strings.xml b/libs/WindowManager/Shell/res/values-az/strings.xml
index 37e92b2..5da5a97 100644
--- a/libs/WindowManager/Shell/res/values-az/strings.xml
+++ b/libs/WindowManager/Shell/res/values-az/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Kamera problemi var?\nBərpa etmək üçün toxunun"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Düzəltməmisiniz?\nGeri qaytarmaq üçün toxunun"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Kamera problemi yoxdur? Qapatmaq üçün toxunun."</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Bəzi tətbiqlər portret rejimində daha yaxşı işləyir"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Məkanınızdan maksimum yararlanmaq üçün bu seçimlərdən birini sınayın"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Tam ekrana keçmək üçün cihazınızı fırladın"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Tətbiqin yerini dəyişmək üçün yanına iki dəfə toxunun"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Ardını görün və edin"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Bölünmüş ekrandan istifadə etmək üçün başqa tətbiqi sürüşdürüb gətirin"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Tətbiqin yerini dəyişmək üçün kənarına iki dəfə toxunun"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Anladım"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Ətraflı məlumat üçün genişləndirin."</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Böyüdün"</string>
diff --git a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
index 9bb260d..aff2b9f 100644
--- a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Imate problema sa kamerom?\nDodirnite da biste ponovo uklopili"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Problem nije rešen?\nDodirnite da biste vratili"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nemate problema sa kamerom? Dodirnite da biste odbacili."</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Neke aplikacije najbolje funkcionišu u uspravnom režimu"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Isprobajte jednu od ovih opcija da biste na najbolji način iskoristili prostor"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Rotirajte uređaj za prikaz preko celog ekrana"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Dvaput dodirnite pored aplikacije da biste promenili njenu poziciju"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Vidite i uradite više"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Prevucite drugu aplikaciju da biste koristili podeljeni ekran"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Dvaput dodirnite izvan aplikacije da biste promenili njenu poziciju"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Važi"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Proširite za još informacija."</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Uvećajte"</string>
diff --git a/libs/WindowManager/Shell/res/values-be/strings.xml b/libs/WindowManager/Shell/res/values-be/strings.xml
index a7b57d5..e325e51 100644
--- a/libs/WindowManager/Shell/res/values-be/strings.xml
+++ b/libs/WindowManager/Shell/res/values-be/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Праблемы з камерай?\nНацісніце, каб пераабсталяваць"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Не ўдалося выправіць?\nНацісніце, каб аднавіць"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Ніякіх праблем з камерай? Націсніце, каб адхіліць."</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Некаторыя праграмы лепш за ўсё працуюць у кніжнай арыентацыі"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Каб эфектыўна выкарыстоўваць прастору, паспрабуйце адзін з гэтых варыянтаў"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Каб перайсці ў поўнаэкранны рэжым, павярніце прыладу"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Двойчы націсніце побач з праграмай, каб перамясціць яе"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Адначасова выконвайце розныя задачы"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Перацягніце іншую праграму, каб выкарыстоўваць падзелены экран"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Двойчы націсніце экран па-за праграмай, каб перамясціць яе"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Зразумела"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Разгарнуць для дадатковай інфармацыі"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Разгарнуць"</string>
diff --git a/libs/WindowManager/Shell/res/values-bg/strings.xml b/libs/WindowManager/Shell/res/values-bg/strings.xml
index c5c0761..3bedc86 100644
--- a/libs/WindowManager/Shell/res/values-bg/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bg/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Имате проблеми с камерата?\nДокоснете за ремонтиране"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Проблемът не се отстрани?\nДокоснете за връщане в предишното състояние"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Нямате проблеми с камерата? Докоснете, за да отхвърлите."</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Някои приложения работят най-добре във вертикален режим"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Изпробвайте една от следните опции, за да се възползвате максимално от мястото на екрана"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Завъртете екрана си, за да преминете в режим на цял екран"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Докоснете два пъти дадено приложение, за да промените позицията му"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Преглеждайте и правете повече неща"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Преместете друго приложение с плъзгане, за да преминете в режим за разделен екран"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Докоснете два пъти извън дадено приложение, за да промените позицията му"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Разбрах"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Разгъване за още информация."</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Увеличаване"</string>
diff --git a/libs/WindowManager/Shell/res/values-bn/strings.xml b/libs/WindowManager/Shell/res/values-bn/strings.xml
index 131e610..35e5b38 100644
--- a/libs/WindowManager/Shell/res/values-bn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bn/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"ক্যামেরা সংক্রান্ত সমস্যা?\nরিফিট করতে ট্যাপ করুন"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"এখনও সমাধান হয়নি?\nরিভার্ট করার জন্য ট্যাপ করুন"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"ক্যামেরা সংক্রান্ত সমস্যা নেই? বাতিল করতে ট্যাপ করুন।"</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"কিছু অ্যাপ \'পোর্ট্রেট\' মোডে সবচেয়ে ভাল কাজ করে"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"আপনার স্পেস সবচেয়ে ভালভাবে কাজে লাগাতে এইসব বিকল্পের মধ্যে কোনও একটি ব্যবহার করে দেখুন"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"\'ফুল স্ক্রিন\' মোডে যেতে ডিভাইস ঘোরান"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"কোনও অ্যাপের পাশে ডবল ট্যাপ করে সেটির জায়গা পরিবর্তন করুন"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"দেখুন ও আরও অনেক কিছু করুন"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"স্প্লিট স্ক্রিনের জন্য অন্য অ্যাপে টেনে আনুন"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"কোনও অ্যাপের স্থান পরিবর্তন করতে তার বাইরে ডবল ট্যাপ করুন"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"বুঝেছি"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"আরও তথ্যের জন্য বড় করুন।"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"বড় করুন"</string>
diff --git a/libs/WindowManager/Shell/res/values-bs/strings.xml b/libs/WindowManager/Shell/res/values-bs/strings.xml
index 2fa48c3..34b282b 100644
--- a/libs/WindowManager/Shell/res/values-bs/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bs/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problemi s kamerom?\nDodirnite da ponovo namjestite"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nije popravljeno?\nDodirnite da vratite"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nema problema s kamerom? Dodirnite da odbacite."</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Određene aplikacije najbolje funkcioniraju u uspravnom načinu rada"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Isprobajte jednu od ovih opcija da maksimalno iskoristite prostor"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Zarotirajte uređaj da aktivirate prikaz preko cijelog ekrana"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Dvaput dodirnite pored aplikacije da promijenite njen položaj"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Pogledajte i učinite više"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Prevucite još jednu aplikaciju za podijeljeni ekran"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Dvaput dodirnite izvan aplikacije da promijenite njen položaj"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Razumijem"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Proširite za više informacija."</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maksimiziranje"</string>
diff --git a/libs/WindowManager/Shell/res/values-ca/strings.xml b/libs/WindowManager/Shell/res/values-ca/strings.xml
index c96ae8f..0279917 100644
--- a/libs/WindowManager/Shell/res/values-ca/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ca/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Tens problemes amb la càmera?\nToca per resoldre\'ls"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"El problema no s\'ha resolt?\nToca per desfer els canvis"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"No tens cap problema amb la càmera? Toca per ignorar."</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Algunes aplicacions funcionen millor en posició vertical"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Prova una d\'aquestes opcions per treure el màxim profit de l\'espai"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Gira el dispositiu per passar a pantalla completa"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Fes doble toc al costat d\'una aplicació per canviar-ne la posició"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Consulta i fes més coses"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Arrossega una altra aplicació per utilitzar la pantalla dividida"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Fes doble toc fora d\'una aplicació per canviar-ne la posició"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Entesos"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Desplega per obtenir més informació."</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maximitza"</string>
diff --git a/libs/WindowManager/Shell/res/values-cs/strings.xml b/libs/WindowManager/Shell/res/values-cs/strings.xml
index 54ed36b..d58100b 100644
--- a/libs/WindowManager/Shell/res/values-cs/strings.xml
+++ b/libs/WindowManager/Shell/res/values-cs/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problémy s fotoaparátem?\nKlepnutím vyřešíte"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nepomohlo to?\nKlepnutím se vrátíte"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Žádné problémy s fotoaparátem? Klepnutím zavřete."</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Některé aplikace fungují nejlépe na výšku"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Pokud chcete maximálně využít prostor, vyzkoušejte jednu z těchto možností"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Otočením zařízení přejděte do režimu celé obrazovky"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Dvojitým klepnutím vedle aplikace změňte její umístění"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Lepší zobrazení a více možností"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Přetáhnutím druhé aplikace použijete rozdělenou obrazovku"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Dvojitým klepnutím mimo aplikaci změníte její umístění"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Rozbalením zobrazíte další informace."</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maximalizovat"</string>
diff --git a/libs/WindowManager/Shell/res/values-da/strings.xml b/libs/WindowManager/Shell/res/values-da/strings.xml
index db5fb27..abb9cea 100644
--- a/libs/WindowManager/Shell/res/values-da/strings.xml
+++ b/libs/WindowManager/Shell/res/values-da/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Har du problemer med dit kamera?\nTryk for at gendanne det oprindelige format"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Løste det ikke problemet?\nTryk for at fortryde"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Har du ingen problemer med dit kamera? Tryk for at afvise."</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Nogle apps fungerer bedst i stående format"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Prøv én af disse muligheder for at få mest muligt ud af dit rum"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Drej din enhed for at gå til fuld skærm"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Tryk to gange ud for en app for at ændre dens placering"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Se og gør mere"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Træk en anden app hertil for at bruge opdelt skærm"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Tryk to gange uden for en app for at justere dens placering"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Udvid for at få flere oplysninger."</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maksimér"</string>
diff --git a/libs/WindowManager/Shell/res/values-de/strings.xml b/libs/WindowManager/Shell/res/values-de/strings.xml
index ac82dc1..a579394 100644
--- a/libs/WindowManager/Shell/res/values-de/strings.xml
+++ b/libs/WindowManager/Shell/res/values-de/strings.xml
@@ -76,14 +76,12 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Probleme mit der Kamera?\nZum Anpassen tippen."</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Das Problem ist nicht behoben?\nZum Rückgängigmachen tippen."</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Keine Probleme mit der Kamera? Zum Schließen tippen."</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Einige Apps funktionieren am besten im Hochformat"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Mithilfe dieser Möglichkeiten kannst du dein Display optimal nutzen"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Gerät drehen, um zum Vollbildmodus zu wechseln"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Neben einer App doppeltippen, um die Position zu ändern"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Mehr sehen und erledigen"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Weitere App hineinziehen, um den Bildschirm zu teilen"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Außerhalb einer App doppeltippen, um die Position zu ändern"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Ok"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Für weitere Informationen maximieren."</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maximieren"</string>
- <!-- no translation found for minimize_button_text (271592547935841753) -->
- <skip />
+ <string name="minimize_button_text" msgid="271592547935841753">"Minimieren"</string>
<string name="close_button_text" msgid="2913281996024033299">"Schließen"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-el/strings.xml b/libs/WindowManager/Shell/res/values-el/strings.xml
index cf671cc..248cff8 100644
--- a/libs/WindowManager/Shell/res/values-el/strings.xml
+++ b/libs/WindowManager/Shell/res/values-el/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Προβλήματα με την κάμερα;\nΠατήστε για επιδιόρθωση."</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Δεν διορθώθηκε;\nΠατήστε για επαναφορά."</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Δεν αντιμετωπίζετε προβλήματα με την κάμερα; Πατήστε για παράβλεψη."</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Ορισμένες εφαρμογές λειτουργούν καλύτερα σε κατακόρυφο προσανατολισμό"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Δοκιμάστε μία από αυτές τις επιλογές για να αξιοποιήσετε στο έπακρο τον χώρο σας."</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Περιστρέψτε τη συσκευή σας για μετάβαση σε πλήρη οθόνη."</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Πατήστε δύο φορές δίπλα σε μια εφαρμογή για να αλλάξετε τη θέση της."</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Δείτε και κάντε περισσότερα"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Σύρετε σε μια άλλη εφαρμογή για διαχωρισμό οθόνης"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Πατήστε δύο φορές έξω από μια εφαρμογή για να αλλάξετε τη θέση της"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Το κατάλαβα"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Ανάπτυξη για περισσότερες πληροφορίες."</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Μεγιστοποίηση"</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
index 1bb0ea1..9c798b8 100644
--- a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Camera issues?\nTap to refit"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Didn’t fix it?\nTap to revert"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"No camera issues? Tap to dismiss."</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Some apps work best in portrait"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Try one of these options to make the most of your space"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Rotate your device to go full screen"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Double-tap next to an app to reposition it"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"See and do more"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Drag in another app for split-screen"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Double-tap outside an app to reposition it"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Got it"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Expand for more information."</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maximise"</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rCA/strings.xml b/libs/WindowManager/Shell/res/values-en-rCA/strings.xml
index 1bb0ea1..9c798b8 100644
--- a/libs/WindowManager/Shell/res/values-en-rCA/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rCA/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Camera issues?\nTap to refit"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Didn’t fix it?\nTap to revert"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"No camera issues? Tap to dismiss."</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Some apps work best in portrait"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Try one of these options to make the most of your space"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Rotate your device to go full screen"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Double-tap next to an app to reposition it"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"See and do more"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Drag in another app for split-screen"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Double-tap outside an app to reposition it"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Got it"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Expand for more information."</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maximise"</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
index 1bb0ea1..9c798b8 100644
--- a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Camera issues?\nTap to refit"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Didn’t fix it?\nTap to revert"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"No camera issues? Tap to dismiss."</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Some apps work best in portrait"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Try one of these options to make the most of your space"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Rotate your device to go full screen"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Double-tap next to an app to reposition it"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"See and do more"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Drag in another app for split-screen"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Double-tap outside an app to reposition it"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Got it"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Expand for more information."</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maximise"</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
index 1bb0ea1..9c798b8 100644
--- a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Camera issues?\nTap to refit"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Didn’t fix it?\nTap to revert"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"No camera issues? Tap to dismiss."</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Some apps work best in portrait"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Try one of these options to make the most of your space"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Rotate your device to go full screen"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Double-tap next to an app to reposition it"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"See and do more"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Drag in another app for split-screen"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Double-tap outside an app to reposition it"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Got it"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Expand for more information."</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maximise"</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rXC/strings.xml b/libs/WindowManager/Shell/res/values-en-rXC/strings.xml
index a94a63d..5ff5c58 100644
--- a/libs/WindowManager/Shell/res/values-en-rXC/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rXC/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Camera issues?\nTap to refit"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Didn’t fix it?\nTap to revert"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"No camera issues? Tap to dismiss."</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Some apps work best in portrait"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Try one of these options to make the most of your space"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Rotate your device to go full screen"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Double-tap next to an app to reposition it"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"See and do more"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Drag in another app for split-screen"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Double-tap outside an app to reposition it"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Got it"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Expand for more information."</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maximize"</string>
diff --git a/libs/WindowManager/Shell/res/values-es-rUS/strings.xml b/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
index e77b190..08a7f49 100644
--- a/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
+++ b/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"¿Tienes problemas con la cámara?\nPresiona para reajustarla"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"¿No se resolvió?\nPresiona para revertir los cambios"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"¿No tienes problemas con la cámara? Presionar para descartar."</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Algunas apps funcionan mejor en modo vertical"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Prueba estas opciones para aprovechar al máximo tu espacio"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Rota el dispositivo para ver la pantalla completa"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Presiona dos veces junto a una app para cambiar su posición"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Aprovecha más"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Arrastra otra app para el modo de pantalla dividida"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Presiona dos veces fuera de una app para cambiar su ubicación"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Entendido"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Expande para obtener más información."</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maximizar"</string>
diff --git a/libs/WindowManager/Shell/res/values-es/strings.xml b/libs/WindowManager/Shell/res/values-es/strings.xml
index d52c015..139232c 100644
--- a/libs/WindowManager/Shell/res/values-es/strings.xml
+++ b/libs/WindowManager/Shell/res/values-es/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"¿Problemas con la cámara?\nToca para reajustar"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"¿No se ha solucionado?\nToca para revertir"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"¿No hay problemas con la cámara? Toca para cerrar."</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Algunas aplicaciones funcionan mejor en vertical"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Prueba una de estas opciones para sacar el máximo partido al espacio de tu pantalla"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Gira el dispositivo para ir al modo de pantalla completa"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Toca dos veces junto a una aplicación para cambiar su posición"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Consulta más información y haz más"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Arrastra otra aplicación para activar la pantalla dividida"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Toca dos veces fuera de una aplicación para cambiarla de posición"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Entendido"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Mostrar más información"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maximizar"</string>
diff --git a/libs/WindowManager/Shell/res/values-et/strings.xml b/libs/WindowManager/Shell/res/values-et/strings.xml
index 735b373..d6f3580 100644
--- a/libs/WindowManager/Shell/res/values-et/strings.xml
+++ b/libs/WindowManager/Shell/res/values-et/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Kas teil on kaameraprobleeme?\nPuudutage ümberpaigutamiseks."</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Kas probleemi ei lahendatud?\nPuudutage ennistamiseks."</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Kas kaameraprobleeme pole? Puudutage loobumiseks."</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Mõni rakendus töötab kõige paremini vertikaalpaigutuses"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Proovige ühte neist valikutest, et oma ruumi parimal moel kasutada"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Pöörake seadet, et aktiveerida täisekraanirežiim"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Topeltpuudutage rakenduse kõrval, et selle asendit muuta"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Vaadake ja tehke rohkem"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Lohistage muusse rakendusse, et jagatud ekraanikuva kasutada"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Topeltpuudutage rakendusest väljaspool, et selle asendit muuta"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Selge"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Laiendage lisateabe saamiseks."</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maksimeeri"</string>
diff --git a/libs/WindowManager/Shell/res/values-eu/strings.xml b/libs/WindowManager/Shell/res/values-eu/strings.xml
index 4bb6b0b..e0efadd6 100644
--- a/libs/WindowManager/Shell/res/values-eu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-eu/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Arazoak dauzkazu kamerarekin?\nBerriro doitzeko, sakatu hau."</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Ez al da konpondu?\nLeheneratzeko, sakatu hau."</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Ez daukazu arazorik kamerarekin? Baztertzeko, sakatu hau."</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Aplikazio batzuk orientazio bertikalean funtzionatzen dute hobekien"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Pantailako eremuari ahalik eta etekinik handiena ateratzeko, probatu aukera hauetakoren bat"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Pantaila osoko modua erabiltzeko, biratu gailua"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Aplikazioaren posizioa aldatzeko, sakatu birritan haren ondoko edozein toki"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Ikusi eta egin gauza gehiago"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Pantaila zatituta ikusteko, arrastatu beste aplikazio bat"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Aplikazioaren posizioa aldatzeko, sakatu birritan haren kanpoaldea"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Ados"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Informazio gehiago lortzeko, zabaldu hau."</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maximizatu"</string>
diff --git a/libs/WindowManager/Shell/res/values-fa/strings.xml b/libs/WindowManager/Shell/res/values-fa/strings.xml
index 2b73743..267dd20 100644
--- a/libs/WindowManager/Shell/res/values-fa/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fa/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"دوربین مشکل دارد؟\nبرای تنظیم مجدد اندازه ضربه بزنید"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"مشکل برطرف نشد؟\nبرای برگرداندن ضربه بزنید"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"دوربین مشکلی ندارد؟ برای بستن ضربه بزنید."</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"برخیاز برنامهها در حالت عمودی عملکرد بهتری دارند"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"با امتحان کردن یکی از این گزینهها، بیشترین بهره را از فضایتان ببرید"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"برای رفتن به حالت تمام صفحه، دستگاهتان را بچرخانید"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"در کنار برنامه دوضربه بزنید تا جابهجا شود"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"از چندین برنامه بهطور همزمان استفاده کنید"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"برای حالت صفحهٔ دونیمه، در برنامهای دیگر بکشید"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"برای جابهجا کردن برنامه، بیرون از آن دوضربه بزنید"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"متوجهام"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"برای اطلاعات بیشتر، گسترده کنید."</string>
<string name="maximize_button_text" msgid="1650859196290301963">"بزرگ کردن"</string>
diff --git a/libs/WindowManager/Shell/res/values-fi/strings.xml b/libs/WindowManager/Shell/res/values-fi/strings.xml
index d78e32d..30321a2 100644
--- a/libs/WindowManager/Shell/res/values-fi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fi/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Onko kameran kanssa ongelmia?\nKorjaa napauttamalla"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Eikö ongelma ratkennut?\nKumoa napauttamalla"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Ei ongelmia kameran kanssa? Hylkää napauttamalla."</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Osa sovelluksista toimii parhaiten pystytilassa"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Kokeile jotakin näistä vaihtoehdoista, jotta saat parhaan hyödyn näytön tilasta"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Käännä laitetta, niin se siirtyy koko näytön tilaan"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Kaksoisnapauta sovellusta, jos haluat siirtää sitä"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Näe ja tee enemmän"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Käytä jaettua näyttöä vetämällä tähän toinen sovellus"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Kaksoisnapauta sovelluksen ulkopuolella, jos haluat siirtää sitä"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Katso lisätietoja laajentamalla."</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Suurenna"</string>
diff --git a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
index 0ee4191..1278997 100644
--- a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problèmes d\'appareil photo?\nTouchez pour réajuster"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Problème non résolu?\nTouchez pour rétablir"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Aucun problème d\'appareil photo? Touchez pour ignorer."</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Certaines applications fonctionnent mieux en mode portrait"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Essayez l\'une de ces options pour tirer le meilleur parti de votre espace"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Faites pivoter votre appareil pour passer en plein écran"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Touchez deux fois à côté d\'une application pour la repositionner"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Voir et en faire plus"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Faites glisser une autre application pour utiliser l\'écran partagé"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Touchez deux fois à côté d\'une application pour la repositionner"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Développer pour en savoir plus."</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Agrandir"</string>
diff --git a/libs/WindowManager/Shell/res/values-fr/strings.xml b/libs/WindowManager/Shell/res/values-fr/strings.xml
index 0377ffa..84c8618 100644
--- a/libs/WindowManager/Shell/res/values-fr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fr/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problèmes d\'appareil photo ?\nAppuyez pour réajuster"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Problème non résolu ?\nAppuyez pour rétablir"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Aucun problème d\'appareil photo ? Appuyez pour ignorer."</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Certaines applis fonctionnent mieux en mode Portrait"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Essayez l\'une de ces options pour exploiter pleinement l\'espace"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Faites pivoter l\'appareil pour passer en plein écran"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Appuyez deux fois à côté d\'une appli pour la repositionner"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Voir et interagir plus"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Faites glisser une autre appli pour utiliser l\'écran partagé"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Appuyez deux fois en dehors d\'une appli pour la repositionner"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Développez pour obtenir plus d\'informations"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Agrandir"</string>
diff --git a/libs/WindowManager/Shell/res/values-gl/strings.xml b/libs/WindowManager/Shell/res/values-gl/strings.xml
index 908edb46..59ec2de 100644
--- a/libs/WindowManager/Shell/res/values-gl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-gl/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Tes problemas coa cámara?\nToca para reaxustala"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Non se solucionaron os problemas?\nToca para reverter o seu tratamento"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Non hai problemas coa cámara? Tocar para ignorar."</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Algunhas aplicacións funcionan mellor en modo vertical"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Proba unha destas opcións para sacar o máximo proveito do espazo da pantalla"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Xira o dispositivo para ver o contido en pantalla completa"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Toca dúas veces a carón dunha aplicación para cambiala de posición"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Ver e facer máis"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Arrastra outra aplicación para usar a pantalla dividida"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Toca dúas veces fóra da aplicación para cambiala de posición"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Entendido"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Despregar para obter máis información."</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maximizar"</string>
diff --git a/libs/WindowManager/Shell/res/values-gu/strings.xml b/libs/WindowManager/Shell/res/values-gu/strings.xml
index 9fa0395..85d98ed 100644
--- a/libs/WindowManager/Shell/res/values-gu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-gu/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"કૅમેરામાં સમસ્યાઓ છે?\nફરીથી ફિટ કરવા માટે ટૅપ કરો"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"સુધારો નથી થયો?\nપહેલાંના પર પાછું ફેરવવા માટે ટૅપ કરો"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"કૅમેરામાં કોઈ સમસ્યા નથી? છોડી દેવા માટે ટૅપ કરો."</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"અમુક ઍપ પોર્ટ્રેટ મોડમાં શ્રેષ્ઠ રીતે કાર્ય કરે છે"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"તમારી સ્પેસનો વધુને વધુ લાભ લેવા માટે, આ વિકલ્પોમાંથી કોઈ એક અજમાવો"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"પૂર્ણ સ્ક્રીન મોડ લાગુ કરવા માટે, તમારા ડિવાઇસને ફેરવો"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"કોઈ ઍપની જગ્યા બદલવા માટે, તેની બાજુમાં બે વાર ટૅપ કરો"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"જુઓ અને બીજું ઘણું કરો"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"સ્ક્રીન વિભાજન માટે કોઈ અન્ય ઍપમાં ખેંચો"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"કોઈ ઍપની જગ્યા બદલવા માટે, તેની બહાર બે વાર ટૅપ કરો"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"સમજાઈ ગયું"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"વધુ માહિતી માટે મોટું કરો."</string>
<string name="maximize_button_text" msgid="1650859196290301963">"મોટું કરો"</string>
diff --git a/libs/WindowManager/Shell/res/values-hi/strings.xml b/libs/WindowManager/Shell/res/values-hi/strings.xml
index 8e6ea7f..bd90b7e 100644
--- a/libs/WindowManager/Shell/res/values-hi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hi/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"क्या कैमरे से जुड़ी कोई समस्या है?\nफिर से फ़िट करने के लिए टैप करें"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"क्या समस्या ठीक नहीं हुई?\nपहले जैसा करने के लिए टैप करें"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"क्या कैमरे से जुड़ी कोई समस्या नहीं है? खारिज करने के लिए टैप करें."</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"कुछ ऐप्लिकेशन, पोर्ट्रेट मोड में सबसे अच्छी तरह काम करते हैं"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"जगह का पूरा इस्तेमाल करने के लिए, इनमें से किसी एक विकल्प को आज़माएं"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"फ़ुल स्क्रीन मोड में जाने के लिए, डिवाइस को घुमाएं"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"किसी ऐप्लिकेशन की जगह बदलने के लिए, उसके बगल में दो बार टैप करें"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"पूरी जानकारी लेकर, बेहतर तरीके से काम करें"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"स्प्लिट स्क्रीन के लिए, दूसरे ऐप्लिकेशन को खींचें और छोड़ें"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"किसी ऐप्लिकेशन की जगह बदलने के लिए, उसके बाहर दो बार टैप करें"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"ठीक है"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"ज़्यादा जानकारी के लिए बड़ा करें."</string>
<string name="maximize_button_text" msgid="1650859196290301963">"बड़ा करें"</string>
diff --git a/libs/WindowManager/Shell/res/values-hr/strings.xml b/libs/WindowManager/Shell/res/values-hr/strings.xml
index 75a2927..41df0df 100644
--- a/libs/WindowManager/Shell/res/values-hr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hr/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problemi s fotoaparatom?\nDodirnite za popravak"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Problem nije riješen?\nDodirnite za vraćanje"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nemate problema s fotoaparatom? Dodirnite za odbacivanje."</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Neke aplikacije najbolje funkcioniraju u portretnom usmjerenju"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Isprobajte jednu od ovih opcija da biste maksimalno iskoristili prostor"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Zakrenite uređaj radi prikaza na cijelom zaslonu"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Dvaput dodirnite pored aplikacije da biste joj promijenili položaj"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Gledajte i učinite više"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Povucite drugu aplikaciju unutra da biste podijelili zaslon"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Dvaput dodirnite izvan aplikacije da biste je premjestili"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Shvaćam"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Proširite da biste saznali više."</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maksimiziraj"</string>
diff --git a/libs/WindowManager/Shell/res/values-hu/strings.xml b/libs/WindowManager/Shell/res/values-hu/strings.xml
index b9eb214..9736a69 100644
--- a/libs/WindowManager/Shell/res/values-hu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hu/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Kamerával kapcsolatos problémába ütközött?\nKoppintson a megoldáshoz."</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nem sikerült a hiba kijavítása?\nKoppintson a visszaállításhoz."</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nincsenek problémái kamerával? Koppintson az elvetéshez."</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Egyes alkalmazások álló tájolásban működnek a leghatékonyabban"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Próbálja ki az alábbi beállítások egyikét, hogy a legjobban ki tudja használni képernyő területét"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"A teljes képernyős mód elindításához forgassa el az eszközt"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Koppintson duplán az alkalmazás mellett az áthelyezéséhez"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Több mindent láthat és tehet"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Húzzon ide egy másik alkalmazást az osztott képernyő használatához"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Koppintson duplán az alkalmazáson kívül az áthelyezéséhez"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Értem"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Kibontással további információkhoz juthat."</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Teljes méret"</string>
diff --git a/libs/WindowManager/Shell/res/values-hy/strings.xml b/libs/WindowManager/Shell/res/values-hy/strings.xml
index 438b045..3c64494 100644
--- a/libs/WindowManager/Shell/res/values-hy/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hy/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Տեսախցիկի հետ կապված խնդիրնե՞ր կան։\nՀպեք՝ վերակարգավորելու համար։"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Չհաջողվե՞ց շտկել։\nՀպեք՝ փոփոխությունները չեղարկելու համար։"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Տեսախցիկի հետ կապված խնդիրներ չկա՞ն։ Փակելու համար հպեք։"</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Որոշ հավելվածներ լավագույնս աշխատում են դիմանկարի ռեժիմում"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Փորձեք այս տարբերակներից մեկը՝ տարածքը հնարավորինս արդյունավետ օգտագործելու համար"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Պտտեք սարքը՝ լիաէկրան ռեժիմին անցնելու համար"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Կրկնակի հպեք հավելվածի կողքին՝ այն տեղափոխելու համար"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Միաժամանակ կատարեք մի քանի առաջադրանք"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Քաշեք մյուս հավելվածի մեջ՝ էկրանի տրոհումն օգտագործելու համար"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Կրկնակի հպեք հավելվածի կողքին՝ այն տեղափոխելու համար"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Եղավ"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Ծավալեք՝ ավելին իմանալու համար։"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Ծավալել"</string>
diff --git a/libs/WindowManager/Shell/res/values-in/strings.xml b/libs/WindowManager/Shell/res/values-in/strings.xml
index 2286b3c..61f3903 100644
--- a/libs/WindowManager/Shell/res/values-in/strings.xml
+++ b/libs/WindowManager/Shell/res/values-in/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Masalah kamera?\nKetuk untuk memperbaiki"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Tidak dapat diperbaiki?\nKetuk untuk mengembalikan"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Tidak ada masalah kamera? Ketuk untuk menutup."</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Beberapa aplikasi berfungsi paling baik dalam mode potret"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Coba salah satu opsi berikut untuk mengoptimalkan area layar Anda"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Putar perangkat untuk tampilan layar penuh"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Ketuk dua kali di samping aplikasi untuk mengubah posisinya"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Lihat dan lakukan lebih banyak hal"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Tarik aplikasi lain untuk menggunakan layar terpisah"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Ketuk dua kali di luar aplikasi untuk mengubah posisinya"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Oke"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Luaskan untuk melihat informasi selengkapnya."</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maksimalkan"</string>
diff --git a/libs/WindowManager/Shell/res/values-is/strings.xml b/libs/WindowManager/Shell/res/values-is/strings.xml
index 6842d21..044348c 100644
--- a/libs/WindowManager/Shell/res/values-is/strings.xml
+++ b/libs/WindowManager/Shell/res/values-is/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Myndavélavesen?\nÝttu til að breyta stærð"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Ennþá vesen?\nÝttu til að afturkalla"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Ekkert myndavélavesen? Ýttu til að hunsa."</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Sum forrit virka best í skammsniði"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Prófaðu einhvern af eftirfarandi valkostum til að nýta plássið sem best"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Snúðu tækinu til að nota allan skjáinn"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Ýttu tvisvar við hlið forritsins til að færa það"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Sjáðu og gerðu meira"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Dragðu annað forrit inn til að nota skjáskiptingu"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Ýttu tvisvar utan við forrit til að færa það"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Ég skil"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Stækka til að sjá frekari upplýsingar."</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Stækka"</string>
diff --git a/libs/WindowManager/Shell/res/values-it/strings.xml b/libs/WindowManager/Shell/res/values-it/strings.xml
index 2fb7a24..ca97693 100644
--- a/libs/WindowManager/Shell/res/values-it/strings.xml
+++ b/libs/WindowManager/Shell/res/values-it/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problemi con la fotocamera?\nTocca per risolverli"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Il problema non si è risolto?\nTocca per ripristinare"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nessun problema con la fotocamera? Tocca per ignorare."</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Alcune app funzionano in modo ottimale in verticale"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Prova una di queste opzioni per ottimizzare lo spazio a tua disposizione"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Ruota il dispositivo per passare alla modalità a schermo intero"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Tocca due volte accanto a un\'app per riposizionarla"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Visualizza più contenuti e fai di più"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Trascina in un\'altra app per usare lo schermo diviso"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Tocca due volte fuori da un\'app per riposizionarla"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Espandi per avere ulteriori informazioni."</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Ingrandisci"</string>
diff --git a/libs/WindowManager/Shell/res/values-iw/strings.xml b/libs/WindowManager/Shell/res/values-iw/strings.xml
index d7c0ab0..67de8a0 100644
--- a/libs/WindowManager/Shell/res/values-iw/strings.xml
+++ b/libs/WindowManager/Shell/res/values-iw/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"בעיות במצלמה?\nאפשר להקיש כדי לבצע התאמה מחדש"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"הבעיה לא נפתרה?\nאפשר להקיש כדי לחזור לגרסה הקודמת"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"אין בעיות במצלמה? אפשר להקיש כדי לסגור."</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"חלק מהאפליקציות פועלות בצורה הטובה ביותר במצב תצוגה לאורך"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"כדי להפיק את המרב משטח המסך, ניתן לנסות את אחת מהאפשרויות האלה"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"מסובבים את המכשיר כדי לעבור לתצוגה במסך מלא"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"מקישים הקשה כפולה ליד אפליקציה כדי למקם אותה מחדש"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"רוצה לראות ולעשות יותר?"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"צריך לגרור אפליקציה אחרת כדי להשתמש במסך מפוצל"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"צריך להקיש הקשה כפולה מחוץ לאפליקציה כדי למקם אותה מחדש"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"הבנתי"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"מרחיבים כדי לקבל מידע נוסף."</string>
<string name="maximize_button_text" msgid="1650859196290301963">"הגדלה"</string>
diff --git a/libs/WindowManager/Shell/res/values-ja/strings.xml b/libs/WindowManager/Shell/res/values-ja/strings.xml
index 8137c45..cc8527e 100644
--- a/libs/WindowManager/Shell/res/values-ja/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ja/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"カメラに関する問題の場合は、\nタップすると修正できます"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"修正されなかった場合は、\nタップすると元に戻ります"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"カメラに関する問題でない場合は、タップすると閉じます。"</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"アプリによっては縦向きにすると正常に動作します"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"スペースを最大限に活用するには、以下の方法のいずれかをお試しください"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"全画面表示にするにはデバイスを回転させてください"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"位置を変えるにはアプリの横をダブルタップしてください"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"表示を拡大して機能を強化"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"分割画面にするにはもう 1 つのアプリをドラッグしてください"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"位置を変えるにはアプリの外側をダブルタップしてください"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"開くと詳細が表示されます。"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"最大化"</string>
diff --git a/libs/WindowManager/Shell/res/values-ka/strings.xml b/libs/WindowManager/Shell/res/values-ka/strings.xml
index 3c47d52..0ef4563 100644
--- a/libs/WindowManager/Shell/res/values-ka/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ka/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"კამერად პრობლემები აქვს?\nშეეხეთ გამოსასწორებლად"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"არ გამოსწორდა?\nშეეხეთ წინა ვერსიის დასაბრუნებლად"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"კამერას პრობლემები არ აქვს? შეეხეთ უარყოფისთვის."</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"ზოგიერთი აპი უკეთ მუშაობს პორტრეტის რეჟიმში"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"გამოცადეთ ამ ვარიანტებიდან ერთ-ერთი, რათა მაქსიმალურად ისარგებლოთ თქვენი მეხსიერებით"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"მოატრიალეთ თქვენი მოწყობილობა სრული ეკრანის გასაშლელად"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"ორმაგად შეეხეთ აპის გვერდითა სივრცეს, რათა ის სხვაგან გადაიტანოთ"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"მეტის ნახვა და გაკეთება"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"ეკრანის გასაყოფად ჩავლებით გადაიტანეთ სხვა აპში"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"ორმაგად შეეხეთ აპის გარშემო სივრცეს, რათა ის სხვაგან გადაიტანოთ"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"გასაგებია"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"დამატებითი ინფორმაციისთვის გააფართოეთ."</string>
<string name="maximize_button_text" msgid="1650859196290301963">"მაქსიმალურად გაშლა"</string>
diff --git a/libs/WindowManager/Shell/res/values-kk/strings.xml b/libs/WindowManager/Shell/res/values-kk/strings.xml
index d739d4b..31bb209 100644
--- a/libs/WindowManager/Shell/res/values-kk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-kk/strings.xml
@@ -76,10 +76,12 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Камерада қателер шықты ма?\nЖөндеу үшін түртіңіз."</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Жөнделмеді ме?\nҚайтару үшін түртіңіз."</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Камерада қателер шықпады ма? Жабу үшін түртіңіз."</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Кейбір қолданба портреттік режимде жақсы жұмыс істейді"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Экранды тиімді пайдалану үшін мына опциялардың бірін байқап көріңіз."</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Толық экранға ауысу үшін құрылғыңызды бұрыңыз."</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Қолданбаның орнын ауыстыру үшін жанынан екі рет түртіңіз."</string>
+ <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+ <skip />
+ <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Түсінікті"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Толығырақ ақпарат алу үшін терезені жайыңыз."</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Жаю"</string>
diff --git a/libs/WindowManager/Shell/res/values-km/strings.xml b/libs/WindowManager/Shell/res/values-km/strings.xml
index 61f6d4f..03682d8 100644
--- a/libs/WindowManager/Shell/res/values-km/strings.xml
+++ b/libs/WindowManager/Shell/res/values-km/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"មានបញ្ហាពាក់ព័ន្ធនឹងកាមេរ៉ាឬ?\nចុចដើម្បីដោះស្រាយ"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"មិនបានដោះស្រាយបញ្ហានេះទេឬ?\nចុចដើម្បីត្រឡប់"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"មិនមានបញ្ហាពាក់ព័ន្ធនឹងកាមេរ៉ាទេឬ? ចុចដើម្បីច្រានចោល។"</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"កម្មវិធីមួយចំនួនដំណើរការបានប្រសើរបំផុតក្នុងទិសដៅបញ្ឈរ"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"សាកល្បងជម្រើសមួយក្នុងចំណោមទាំងនេះ ដើម្បីទទួលបានអត្ថប្រយោជន៍ច្រើនបំផុតពីកន្លែងទំនេររបស់អ្នក"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"បង្វិលឧបករណ៍របស់អ្នក ដើម្បីចូលប្រើអេក្រង់ពេញ"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"ចុចពីរដងនៅជាប់កម្មវិធីណាមួយ ដើម្បីប្ដូរទីតាំងកម្មវិធីនោះ"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"មើលឃើញ និងធ្វើបានកាន់តែច្រើន"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"អូសកម្មវិធីមួយទៀតចូល ដើម្បីប្រើមុខងារបំបែកអេក្រង់"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"ចុចពីរដងនៅក្រៅកម្មវិធី ដើម្បីប្ដូរទីតាំងកម្មវិធីនោះ"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"យល់ហើយ"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"ពង្រីកដើម្បីទទួលបានព័ត៌មានបន្ថែម។"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"ពង្រីក"</string>
diff --git a/libs/WindowManager/Shell/res/values-kn/strings.xml b/libs/WindowManager/Shell/res/values-kn/strings.xml
index 32645b4..167a38e 100644
--- a/libs/WindowManager/Shell/res/values-kn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-kn/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"ಕ್ಯಾಮರಾ ಸಮಸ್ಯೆಗಳಿವೆಯೇ?\nಮರುಹೊಂದಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"ಅದನ್ನು ಸರಿಪಡಿಸಲಿಲ್ಲವೇ?\nಹಿಂತಿರುಗಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"ಕ್ಯಾಮರಾ ಸಮಸ್ಯೆಗಳಿಲ್ಲವೇ? ವಜಾಗೊಳಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"ಕೆಲವು ಆ್ಯಪ್ಗಳು ಪೋರ್ಟ್ರೇಟ್ ಮೋಡ್ನಲ್ಲಿ ಅತ್ಯುತ್ತಮವಾಗಿ ಕಾರ್ಯನಿರ್ವಹಿಸುತ್ತವೆ"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"ನಿಮ್ಮ ಸ್ಥಳಾವಕಾಶದ ಅತಿಹೆಚ್ಚು ಪ್ರಯೋಜನ ಪಡೆಯಲು ಈ ಆಯ್ಕೆಗಳಲ್ಲಿ ಒಂದನ್ನು ಬಳಸಿ ನೋಡಿ"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"ಪೂರ್ಣ ಸ್ಕ್ರೀನ್ಗೆ ಹೋಗಲು ನಿಮ್ಮ ಸಾಧನವನ್ನು ತಿರುಗಿಸಿ"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"ಆ್ಯಪ್ ಒಂದರ ಸ್ಥಾನವನ್ನು ಬದಲಾಯಿಸಲು ಅದರ ಪಕ್ಕದಲ್ಲಿ ಡಬಲ್-ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"ನೋಡಿ ಮತ್ತು ಹೆಚ್ಚಿನದನ್ನು ಮಾಡಿ"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"ಸ್ಪ್ಲಿಟ್ ಸ್ಕ್ರೀನ್ಗಾಗಿ ಮತ್ತೊಂದು ಆ್ಯಪ್ನಲ್ಲಿ ಎಳೆಯಿರಿ"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"ಆ್ಯಪ್ ಒಂದರ ಸ್ಥಾನವನ್ನು ಬದಲಾಯಿಸಲು ಅದರ ಹೊರಗೆ ಡಬಲ್-ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"ಸರಿ"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"ಇನ್ನಷ್ಟು ಮಾಹಿತಿಗಾಗಿ ವಿಸ್ತೃತಗೊಳಿಸಿ."</string>
<string name="maximize_button_text" msgid="1650859196290301963">"ಹಿಗ್ಗಿಸಿ"</string>
diff --git a/libs/WindowManager/Shell/res/values-ko/strings.xml b/libs/WindowManager/Shell/res/values-ko/strings.xml
index 5e8a4da..1175a0e 100644
--- a/libs/WindowManager/Shell/res/values-ko/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ko/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"카메라 문제가 있나요?\n해결하려면 탭하세요."</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"해결되지 않았나요?\n되돌리려면 탭하세요."</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"카메라에 문제가 없나요? 닫으려면 탭하세요."</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"일부 앱은 세로 모드에서 가장 잘 작동함"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"공간을 최대한 이용할 수 있도록 이 옵션 중 하나를 시도해 보세요."</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"전체 화면 모드로 전환하려면 기기를 회전하세요."</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"앱 위치를 조정하려면 앱 옆을 두 번 탭하세요."</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"더 많은 정보를 보고 더 많은 작업을 처리하세요"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"화면 분할을 사용하려면 다른 앱을 드래그해 가져옵니다."</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"앱 위치를 조정하려면 앱 외부를 두 번 탭합니다."</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"확인"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"추가 정보는 펼쳐서 확인하세요."</string>
<string name="maximize_button_text" msgid="1650859196290301963">"최대화"</string>
diff --git a/libs/WindowManager/Shell/res/values-ky/strings.xml b/libs/WindowManager/Shell/res/values-ky/strings.xml
index 5b97577..b047863 100644
--- a/libs/WindowManager/Shell/res/values-ky/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ky/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Камерада маселелер келип чыктыбы?\nОңдоо үчүн таптаңыз"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Оңдолгон жокпу?\nАртка кайтаруу үчүн таптаңыз"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Камерада маселе жокпу? Этибарга албоо үчүн таптаңыз."</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Айрым колдонмолорду тигинен иштетүү туура болот"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Иш чөйрөсүнүн бардык мүмкүнчүлүктөрүн пайдалануу үчүн бул параметрлердин бирин колдонуп көрүңүз"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Толук экран режимине өтүү үчүн түзмөктү буруңуз"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Колдонмонун ракурсун өзгөртүү үчүн анын тушуна эки жолу басыңыз"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Көрүп, көбүрөөк нерселерди жасаңыз"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Экранды бөлүү үчүн башка колдонмону сүйрөңүз"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Колдонмону жылдыруу үчүн сырт жагын эки жолу таптаңыз"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Түшүндүм"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Толук маалымат алуу үчүн жайып көрүңүз."</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Чоңойтуу"</string>
diff --git a/libs/WindowManager/Shell/res/values-lo/strings.xml b/libs/WindowManager/Shell/res/values-lo/strings.xml
index 0406bf4..00bf7f4 100644
--- a/libs/WindowManager/Shell/res/values-lo/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lo/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"ມີບັນຫາກ້ອງຖ່າຍຮູບບໍ?\nແຕະເພື່ອປັບໃໝ່"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"ບໍ່ໄດ້ແກ້ໄຂມັນບໍ?\nແຕະເພື່ອແປງກັບຄືນ"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"ບໍ່ມີບັນຫາກ້ອງຖ່າຍຮູບບໍ? ແຕະເພື່ອປິດໄວ້."</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"ແອັບບາງຢ່າງເຮັດວຽກໄດ້ດີທີ່ສຸດໃນໂໝດລວງຕັ້ງ"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"ໃຫ້ລອງຕົວເລືອກໃດໜຶ່ງເຫຼົ່ານີ້ເພື່ອໃຊ້ປະໂຫຍດຈາກພື້ນທີ່ຂອງທ່ານໃຫ້ໄດ້ສູງສຸດ"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"ໝຸນອຸປະກອນຂອງທ່ານເພື່ອໃຊ້ແບບເຕັມຈໍ"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"ແຕະສອງເທື່ອໃສ່ຖັດຈາກແອັບໃດໜຶ່ງເພື່ອຈັດຕຳແໜ່ງຂອງມັນຄືນໃໝ່"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"ເບິ່ງ ແລະ ເຮັດຫຼາຍຂຶ້ນ"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"ລາກແອັບອື່ນເຂົ້າມາເພື່ອແບ່ງໜ້າຈໍ"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"ແຕະສອງເທື່ອໃສ່ນອກແອັບໃດໜຶ່ງເພື່ອຈັດຕຳແໜ່ງຂອງມັນຄືນໃໝ່"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"ເຂົ້າໃຈແລ້ວ"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"ຂະຫຍາຍເພື່ອເບິ່ງຂໍ້ມູນເພີ່ມເຕີມ."</string>
<string name="maximize_button_text" msgid="1650859196290301963">"ຂະຫຍາຍໃຫຍ່ສຸດ"</string>
diff --git a/libs/WindowManager/Shell/res/values-lt/strings.xml b/libs/WindowManager/Shell/res/values-lt/strings.xml
index 15fe08e..3981793 100644
--- a/libs/WindowManager/Shell/res/values-lt/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lt/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Iškilo problemų dėl kameros?\nPalieskite, kad pritaikytumėte iš naujo"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nepavyko pataisyti?\nPalieskite, kad grąžintumėte"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nėra jokių problemų dėl kameros? Palieskite, kad atsisakytumėte."</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Kai kurios programos geriausiai veikia stačiuoju režimu"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Pabandykite naudoti vieną iš šių parinkčių, kad išnaudotumėte visą vietą"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Pasukite įrenginį, kad įjungtumėte viso ekrano režimą"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Dukart palieskite šalia programos, kad pakeistumėte jos poziciją"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Daugiau turinio ir funkcijų"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Vilkite kitoje programoje, kad galėtumėte naudoti išskaidyto ekrano režimą"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Dukart palieskite už programos ribų, kad pakeistumėte jos poziciją"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Supratau"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Išskleiskite, jei reikia daugiau informacijos."</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Padidinti"</string>
diff --git a/libs/WindowManager/Shell/res/values-lv/strings.xml b/libs/WindowManager/Shell/res/values-lv/strings.xml
index 756640a..3599c14 100644
--- a/libs/WindowManager/Shell/res/values-lv/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lv/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Vai ir problēmas ar kameru?\nPieskarieties, lai tās novērstu."</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Vai problēma netika novērsta?\nPieskarieties, lai atjaunotu."</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Vai nav problēmu ar kameru? Pieskarieties, lai nerādītu."</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Dažas lietotnes vislabāk darbojas portreta režīmā"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Izmēģiniet vienu no šīm iespējām, lai efektīvi izmantotu pieejamo vietu"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Pagrieziet ierīci, lai aktivizētu pilnekrāna režīmu"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Veiciet dubultskārienu blakus lietotnei, lai manītu tās pozīciju"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Uzziniet un paveiciet vairāk"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Lai izmantotu sadalītu ekrānu, ievelciet vēl vienu lietotni"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Lai pārvietotu lietotni, veiciet dubultskārienu ārpus lietotnes"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Labi"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Izvērsiet, lai iegūtu plašāku informāciju."</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maksimizēt"</string>
diff --git a/libs/WindowManager/Shell/res/values-mk/strings.xml b/libs/WindowManager/Shell/res/values-mk/strings.xml
index f6fc778..6c41b0c 100644
--- a/libs/WindowManager/Shell/res/values-mk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mk/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Проблеми со камерата?\nДопрете за да се совпадне повторно"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Не се поправи?\nДопрете за враќање"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Нема проблеми со камерата? Допрете за отфрлање."</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Некои апликации најдобро работат во режим на портрет"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Испробајте една од опцииве за да го извлечете максимумот од вашиот простор"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Ротирајте го уредот за да отворите на цел екран"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Допрете двапати до некоја апликација за да ја преместите"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Погледнете и направете повеќе"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Повлечете во друга апликација за поделен екран"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Допрете двапати надвор од некоја апликација за да ја преместите"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Сфатив"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Проширете за повеќе информации."</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Зголеми"</string>
diff --git a/libs/WindowManager/Shell/res/values-ml/strings.xml b/libs/WindowManager/Shell/res/values-ml/strings.xml
index 15fe2b1..76dfc0d9 100644
--- a/libs/WindowManager/Shell/res/values-ml/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ml/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"ക്യാമറ പ്രശ്നങ്ങളുണ്ടോ?\nശരിയാക്കാൻ ടാപ്പ് ചെയ്യുക"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"അത് പരിഹരിച്ചില്ലേ?\nപുനഃസ്ഥാപിക്കാൻ ടാപ്പ് ചെയ്യുക"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"ക്യാമറാ പ്രശ്നങ്ങളൊന്നുമില്ലേ? നിരസിക്കാൻ ടാപ്പ് ചെയ്യുക."</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"ചില ആപ്പുകൾ പോർട്രെയ്റ്റിൽ മികച്ച രീതിയിൽ പ്രവർത്തിക്കുന്നു"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"നിങ്ങളുടെ ഇടം പരമാവധി പ്രയോജനപ്പെടുത്താൻ ഈ ഓപ്ഷനുകളിലൊന്ന് പരീക്ഷിക്കുക"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"പൂർണ്ണ സ്ക്രീനിലേക്ക് മാറാൻ ഈ ഉപകരണം റൊട്ടേറ്റ് ചെയ്യുക"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"ഒരു ആപ്പിന്റെ സ്ഥാനം മാറ്റാൻ, അതിന് തൊട്ടടുത്ത് ഡബിൾ ടാപ്പ് ചെയ്യുക"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"കൂടുതൽ കാണുക, ചെയ്യുക"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"സ്ക്രീൻ വിഭജന മോഡിന്, മറ്റൊരു ആപ്പ് വലിച്ചിടുക"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"ആപ്പിന്റെ സ്ഥാനം മാറ്റാൻ അതിന് പുറത്ത് ഡബിൾ ടാപ്പ് ചെയ്യുക"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"മനസ്സിലായി"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"കൂടുതൽ വിവരങ്ങൾക്ക് വികസിപ്പിക്കുക."</string>
<string name="maximize_button_text" msgid="1650859196290301963">"വലുതാക്കുക"</string>
diff --git a/libs/WindowManager/Shell/res/values-mn/strings.xml b/libs/WindowManager/Shell/res/values-mn/strings.xml
index 18880c9..a8bd85e 100644
--- a/libs/WindowManager/Shell/res/values-mn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mn/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Камерын асуудал гарсан уу?\nДахин тааруулахын тулд товшино уу"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Үүнийг засаагүй юу?\nБуцаахын тулд товшино уу"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Камерын асуудал байхгүй юу? Хаахын тулд товшино уу."</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Зарим апп нь босоо чиглэлд хамгийн сайн ажилладаг"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Орон зайгаа сайтар ашиглахын тулд эдгээр сонголтуудын аль нэгийг туршиж үзээрэй"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Төхөөрөмжөө бүтэн дэлгэцээр үзэхийн тулд эргүүлнэ"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Аппыг дахин байрлуулахын тулд хажууд нь хоёр товшино"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Харж илүү ихийг хий"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Дэлгэцийг хуваахын тулд өөр апп руу чирнэ үү"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Аппыг дахин байрлуулахын тулд гадна талд нь хоёр товшино"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Ойлголоо"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Нэмэлт мэдээлэл авах бол дэлгэнэ үү."</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Томруулах"</string>
diff --git a/libs/WindowManager/Shell/res/values-mr/strings.xml b/libs/WindowManager/Shell/res/values-mr/strings.xml
index 271de45..5874812 100644
--- a/libs/WindowManager/Shell/res/values-mr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mr/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"कॅमेराशी संबंधित काही समस्या आहेत का?\nपुन्हा फिट करण्यासाठी टॅप करा"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"निराकरण झाले नाही?\nरिव्हर्ट करण्यासाठी कृपया टॅप करा"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"कॅमेराशी संबंधित कोणत्याही समस्या नाहीत का? डिसमिस करण्यासाठी टॅप करा."</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"काही ॲप्स पोर्ट्रेटमध्ये सर्वोत्तम काम करतात"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"तुमच्या स्पेसचा पुरेपूर वापर करण्यासाठी, यांपैकी एक पर्याय वापरून पहा"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"फुल स्क्रीन करण्यासाठी, तुमचे डिव्हाइस फिरवा"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"ॲपची स्थिती पुन्हा बदलण्यासाठी, त्याच्या शेजारी दोनदा टॅप करा"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"पहा आणि आणखी बरेच काही करा"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"स्प्लिट-स्क्रीन वापरण्यासाठी दुसऱ्या ॲपमध्ये ड्रॅग करा"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"ॲपची स्थिती पुन्हा बदलण्यासाठी, त्याच्या बाहेर दोनदा टॅप करा"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"समजले"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"अधिक माहितीसाठी विस्तार करा."</string>
<string name="maximize_button_text" msgid="1650859196290301963">"मोठे करा"</string>
diff --git a/libs/WindowManager/Shell/res/values-ms/strings.xml b/libs/WindowManager/Shell/res/values-ms/strings.xml
index 42602d8..88270df 100644
--- a/libs/WindowManager/Shell/res/values-ms/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ms/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Isu kamera?\nKetik untuk memuatkan semula"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Isu tidak dibetulkan?\nKetik untuk kembali"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Tiada isu kamera? Ketik untuk mengetepikan."</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Sesetengah apl berfungsi paling baik dalam mod potret"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Cuba salah satu daripada pilihan ini untuk memanfaatkan ruang anda sepenuhnya"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Putar peranti anda untuk beralih ke skrin penuh"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Ketik dua kali bersebelahan apl untuk menempatkan semula apl"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Lihat dan lakukan lebih"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Seret apl lain untuk skrin pisah"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Ketik dua kali di luar apl untuk menempatkan semula apl itu"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Kembangkan untuk mendapatkan maklumat lanjut."</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maksimumkan"</string>
diff --git a/libs/WindowManager/Shell/res/values-my/strings.xml b/libs/WindowManager/Shell/res/values-my/strings.xml
index 3c54154..9a2d1ba 100644
--- a/libs/WindowManager/Shell/res/values-my/strings.xml
+++ b/libs/WindowManager/Shell/res/values-my/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"ကင်မရာပြဿနာလား။\nပြင်ဆင်ရန် တို့ပါ"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"ကောင်းမသွားဘူးလား။\nပြန်ပြောင်းရန် တို့ပါ"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"ကင်မရာပြဿနာ မရှိဘူးလား။ ပယ်ရန် တို့ပါ။"</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"အချို့အက်ပ်များသည် ဒေါင်လိုက်တွင် အကောင်းဆုံးလုပ်ဆောင်သည်"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"သင့်နေရာကို အကောင်းဆုံးအသုံးပြုနိုင်ရန် ဤရွေးစရာများထဲမှ တစ်ခုကို စမ်းကြည့်ပါ"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"ဖန်သားပြင်အပြည့်လုပ်ရန် သင့်စက်ကို လှည့်နိုင်သည်"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"အက်ပ်နေရာပြန်ချရန် ၎င်းဘေးတွင် နှစ်ချက်တို့နိုင်သည်"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"ကြည့်ပြီး ပိုမိုလုပ်ဆောင်ပါ"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"မျက်နှာပြင် ခွဲ၍ပြသနိုင်ရန် နောက်အက်ပ်တစ်ခုကို ဖိဆွဲပါ"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"နေရာပြန်ချရန် အက်ပ်အပြင်ဘက်ကို နှစ်ချက်တို့ပါ"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"ရပြီ"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"နောက်ထပ်အချက်အလက်များအတွက် ချဲ့နိုင်သည်။"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"ချဲ့ရန်"</string>
diff --git a/libs/WindowManager/Shell/res/values-nb/strings.xml b/libs/WindowManager/Shell/res/values-nb/strings.xml
index 9a6fb4e..ec9e635d 100644
--- a/libs/WindowManager/Shell/res/values-nb/strings.xml
+++ b/libs/WindowManager/Shell/res/values-nb/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Har du kameraproblemer?\nTrykk for å tilpasse"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Ble ikke problemet løst?\nTrykk for å gå tilbake"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Har du ingen kameraproblemer? Trykk for å lukke."</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Noen apper fungerer best i stående format"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Prøv et av disse alternativene for å få mest mulig ut av plassen din"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Roter enheten for å starte fullskjerm"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Dobbelttrykk ved siden av en app for å flytte den"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Se og gjør mer"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Dra inn en annen app for å bruke delt skjerm"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Dobbelttrykk utenfor en app for å flytte den"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Greit"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Vis for å få mer informasjon."</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maksimer"</string>
diff --git a/libs/WindowManager/Shell/res/values-ne/strings.xml b/libs/WindowManager/Shell/res/values-ne/strings.xml
index 504eb17..dc7d98d 100644
--- a/libs/WindowManager/Shell/res/values-ne/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ne/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"क्यामेरासम्बन्धी समस्या देखियो?\nसमस्या हल गर्न ट्याप गर्नुहोस्"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"समस्या हल भएन?\nपहिलेको जस्तै बनाउन ट्याप गर्नुहोस्"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"क्यामेरासम्बन्धी कुनै पनि समस्या छैन? खारेज गर्न ट्याप गर्नुहोस्।"</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"केही एपहरूले पोर्ट्रेटमा राम्रोसँग काम गर्छन्"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"तपाईं स्क्रिनको अधिकतम ठाउँ प्रयोग गर्न चाहनुहुन्छ भने यीमध्ये कुनै विकल्प प्रयोग गरी हेर्नुहोस्"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"तपाईं फुल स्क्रिन मोड हेर्न चाहनुहुन्छ भने आफ्नो डिभाइस रोटेट गर्नुहोस्"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"तपाईं जुन एपको स्थिति मिलाउन चाहनुहुन्छ सोही एपको छेउमा डबल ट्याप गर्नुहोस्"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"थप कुरा हेर्नुहोस् र गर्नुहोस्"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"स्प्लिट स्क्रिन मोड प्रयोग गर्न अर्को एप ड्रयाग एन्ड ड्रप गर्नुहोस्"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"तपाईं जुन एपको स्थिति मिलाउन चाहनुहुन्छ सोही एपको बाहिर डबल ट्याप गर्नुहोस्"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"बुझेँ"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"थप जानकारी प्राप्त गर्न चाहनुहुन्छ भने एक्स्पान्ड गर्नुहोस्।"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"ठुलो बनाउनुहोस्"</string>
diff --git a/libs/WindowManager/Shell/res/values-nl/strings.xml b/libs/WindowManager/Shell/res/values-nl/strings.xml
index 19acf92..5bae2a3 100644
--- a/libs/WindowManager/Shell/res/values-nl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-nl/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Cameraproblemen?\nTik om opnieuw passend te maken."</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Is dit geen oplossing?\nTik om terug te zetten."</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Geen cameraproblemen? Tik om te sluiten."</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Sommige apps werken het best in de staande stand"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Probeer een van deze opties om optimaal gebruik te maken van je ruimte"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Draai je apparaat om naar volledig scherm te schakelen"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Dubbeltik naast een app om deze opnieuw te positioneren"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Zie en doe meer"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Sleep een andere app hier naartoe om het scherm te splitsen"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Dubbeltik naast een app om deze opnieuw te positioneren"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Uitvouwen voor meer informatie."</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maximaliseren"</string>
diff --git a/libs/WindowManager/Shell/res/values-or/strings.xml b/libs/WindowManager/Shell/res/values-or/strings.xml
index 874dfcb..c5ef4f1 100644
--- a/libs/WindowManager/Shell/res/values-or/strings.xml
+++ b/libs/WindowManager/Shell/res/values-or/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"କ୍ୟାମେରାରେ ସମସ୍ୟା ଅଛି?\nପୁଣି ଫିଟ କରିବାକୁ ଟାପ କରନ୍ତୁ"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"ଏହାର ସମାଧାନ ହୋଇନାହିଁ?\nଫେରିଯିବା ପାଇଁ ଟାପ କରନ୍ତୁ"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"କ୍ୟାମେରାରେ କିଛି ସମସ୍ୟା ନାହିଁ? ଖାରଜ କରିବାକୁ ଟାପ କରନ୍ତୁ।"</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"କିଛି ଆପ ପୋର୍ଟ୍ରେଟରେ ସବୁଠାରୁ ଭଲ କାମ କରେ"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"ଆପଣଙ୍କ ସ୍ପେସରୁ ଅଧିକ ଲାଭ ପାଇବାକୁ ଏହି ବିକଳ୍ପଗୁଡ଼ିକ ମଧ୍ୟରୁ ଗୋଟିଏ ବ୍ୟବହାର କରି ଦେଖନ୍ତୁ"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"ପୂର୍ଣ୍ଣ-ସ୍କ୍ରିନ ବ୍ୟବହାର କରିବାକୁ ଆପଣଙ୍କ ଡିଭାଇସକୁ ରୋଟେଟ କରନ୍ତୁ"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"ଏକ ଆପକୁ ରିପୋଜିସନ କରିବା ପାଇଁ ଏହା ପାଖରେ ଦୁଇଥର-ଟାପ କରନ୍ତୁ"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"ଦେଖନ୍ତୁ ଏବଂ ଆହୁରି ଅନେକ କିଛି କରନ୍ତୁ"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"ସ୍ପ୍ଲିଟ-ସ୍କ୍ରିନ ପାଇଁ ଅନ୍ୟ ଏକ ଆପକୁ ଡ୍ରାଗ କରନ୍ତୁ"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"ଏକ ଆପକୁ ରିପୋଜିସନ କରିବା ପାଇଁ ଏହାର ବାହାରେ ଦୁଇଥର-ଟାପ କରନ୍ତୁ"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"ବୁଝିଗଲି"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"ଅଧିକ ସୂଚନା ପାଇଁ ବିସ୍ତାର କରନ୍ତୁ।"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"ବଡ଼ କରନ୍ତୁ"</string>
diff --git a/libs/WindowManager/Shell/res/values-pa/strings.xml b/libs/WindowManager/Shell/res/values-pa/strings.xml
index 19591ec..f026205 100644
--- a/libs/WindowManager/Shell/res/values-pa/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pa/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"ਕੀ ਕੈਮਰੇ ਸੰਬੰਧੀ ਸਮੱਸਿਆਵਾਂ ਹਨ?\nਮੁੜ-ਫਿੱਟ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"ਕੀ ਇਹ ਠੀਕ ਨਹੀਂ ਹੋਈ?\nਵਾਪਸ ਉਹੀ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"ਕੀ ਕੈਮਰੇ ਸੰਬੰਧੀ ਕੋਈ ਸਮੱਸਿਆ ਨਹੀਂ ਹੈ? ਖਾਰਜ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ।"</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"ਕੁਝ ਐਪਾਂ ਪੋਰਟਰੇਟ ਵਿੱਚ ਬਿਹਤਰ ਕੰਮ ਕਰਦੀਆਂ ਹਨ"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"ਆਪਣੀ ਜਗ੍ਹਾ ਦਾ ਵੱਧ ਤੋਂ ਵੱਧ ਲਾਹਾ ਲੈਣ ਲਈ ਇਨ੍ਹਾਂ ਵਿਕਲਪਾਂ ਵਿੱਚੋਂ ਕੋਈ ਇੱਕ ਵਰਤ ਕੇ ਦੇਖੋ"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"ਪੂਰੀ-ਸਕ੍ਰੀਨ ਮੋਡ \'ਤੇ ਜਾਣ ਲਈ ਆਪਣੇ ਡੀਵਾਈਸ ਨੂੰ ਘੁਮਾਓ"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"ਕਿਸੇ ਐਪ ਦੀ ਜਗ੍ਹਾ ਬਦਲਣ ਲਈ ਉਸ ਦੇ ਅੱਗੇ ਡਬਲ ਟੈਪ ਕਰੋ"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"ਦੇਖੋ ਅਤੇ ਹੋਰ ਬਹੁਤ ਕੁਝ ਕਰੋ"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"ਸਪਲਿਟ ਸਕ੍ਰੀਨ ਦੇ ਲਈ ਕਿਸੇ ਹੋਰ ਐਪ ਵਿੱਚ ਘਸੀਟੋ"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"ਕਿਸੇ ਐਪ ਦੀ ਜਗ੍ਹਾ ਬਦਲਣ ਲਈ ਉਸ ਦੇ ਬਾਹਰ ਡਬਲ ਟੈਪ ਕਰੋ"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"ਸਮਝ ਲਿਆ"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"ਹੋਰ ਜਾਣਕਾਰੀ ਲਈ ਵਿਸਤਾਰ ਕਰੋ।"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"ਵੱਡਾ ਕਰੋ"</string>
diff --git a/libs/WindowManager/Shell/res/values-pl/strings.xml b/libs/WindowManager/Shell/res/values-pl/strings.xml
index ad4f549..22c0c37 100644
--- a/libs/WindowManager/Shell/res/values-pl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pl/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problemy z aparatem?\nKliknij, aby dopasować"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Naprawa się nie udała?\nKliknij, aby cofnąć"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Brak problemów z aparatem? Kliknij, aby zamknąć"</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Niektóre aplikacje działają najlepiej w orientacji pionowej"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Wypróbuj jedną z tych opcji, aby jak najlepiej wykorzystać miejsce"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Obróć urządzenie, aby przejść do pełnego ekranu"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Kliknij dwukrotnie obok aplikacji, aby ją przenieść"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Zobacz i zrób więcej"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Przeciągnij drugą aplikację, aby podzielić ekran"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Kliknij dwukrotnie poza aplikacją, aby ją przenieść"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Rozwiń, aby wyświetlić więcej informacji."</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maksymalizuj"</string>
diff --git a/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml b/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml
index 6de450e..0bbffb3 100644
--- a/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problemas com a câmera?\nToque para ajustar o enquadramento"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"O problema não foi corrigido?\nToque para reverter"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Não tem problemas com a câmera? Toque para dispensar."</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Alguns apps funcionam melhor em modo retrato"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Tente uma destas opções para aproveitar seu espaço ao máximo"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Gire o dispositivo para entrar no modo de tela cheia"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Toque duas vezes ao lado de um app para reposicionar"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Veja e faça mais"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Arraste outro app para a tela dividida"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Toque duas vezes fora de um app para reposicionar"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Entendi"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Abra para ver mais informações."</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maximizar"</string>
diff --git a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
index be1a531..07dd4d7 100644
--- a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problemas com a câmara?\nToque aqui para reajustar"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Não foi corrigido?\nToque para reverter"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nenhum problema com a câmara? Toque para ignorar."</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Algumas apps funcionam melhor no modo vertical"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Experimente uma destas opções para aproveitar ao máximo o seu espaço"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Rode o dispositivo para ficar em ecrã inteiro"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Toque duas vezes junto a uma app para a reposicionar"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Veja e faça mais"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Arraste outra app para usar o ecrã dividido"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Toque duas vezes fora de uma app para a reposicionar"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Expandir para obter mais informações"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maximizar"</string>
diff --git a/libs/WindowManager/Shell/res/values-pt/strings.xml b/libs/WindowManager/Shell/res/values-pt/strings.xml
index 6de450e..0bbffb3 100644
--- a/libs/WindowManager/Shell/res/values-pt/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problemas com a câmera?\nToque para ajustar o enquadramento"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"O problema não foi corrigido?\nToque para reverter"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Não tem problemas com a câmera? Toque para dispensar."</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Alguns apps funcionam melhor em modo retrato"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Tente uma destas opções para aproveitar seu espaço ao máximo"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Gire o dispositivo para entrar no modo de tela cheia"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Toque duas vezes ao lado de um app para reposicionar"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Veja e faça mais"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Arraste outro app para a tela dividida"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Toque duas vezes fora de um app para reposicionar"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Entendi"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Abra para ver mais informações."</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maximizar"</string>
diff --git a/libs/WindowManager/Shell/res/values-ro/strings.xml b/libs/WindowManager/Shell/res/values-ro/strings.xml
index e4130e2..3ec4f1b 100644
--- a/libs/WindowManager/Shell/res/values-ro/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ro/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Aveți probleme cu camera foto?\nAtingeți pentru a reîncadra"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nu ați remediat problema?\nAtingeți pentru a reveni"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nu aveți probleme cu camera foto? Atingeți pentru a închide."</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Unele aplicații funcționează cel mai bine în orientarea portret"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Încercați una dintre aceste opțiuni pentru a profita din plin de spațiu"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Rotiți dispozitivul pentru a trece în modul ecran complet"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Atingeți de două ori lângă o aplicație pentru a o repoziționa"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Vezi și fă mai multe"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Trage în altă aplicație pentru a folosi ecranul împărțit"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Atinge de două ori lângă o aplicație pentru a o repoziționa"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Extindeți pentru mai multe informații"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maximizați"</string>
diff --git a/libs/WindowManager/Shell/res/values-ru/strings.xml b/libs/WindowManager/Shell/res/values-ru/strings.xml
index 00f3aa4..f1ff000 100644
--- a/libs/WindowManager/Shell/res/values-ru/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ru/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Проблемы с камерой?\nНажмите, чтобы исправить."</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Не помогло?\nНажмите, чтобы отменить изменения."</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Нет проблем с камерой? Нажмите, чтобы закрыть."</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Некоторые приложения лучше работают в вертикальном режиме"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Чтобы эффективно использовать экранное пространство, выполните одно из следующих действий:"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Чтобы перейти в полноэкранный режим, поверните устройство."</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Чтобы переместить приложение, нажмите на него дважды."</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Выполняйте несколько задач одновременно"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Перетащите сюда другое приложение, чтобы использовать разделение экрана."</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Чтобы переместить приложение, дважды нажмите рядом с ним."</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"ОК"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Развернуть, чтобы узнать больше."</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Развернуть"</string>
diff --git a/libs/WindowManager/Shell/res/values-si/strings.xml b/libs/WindowManager/Shell/res/values-si/strings.xml
index b54d681..39bd260 100644
--- a/libs/WindowManager/Shell/res/values-si/strings.xml
+++ b/libs/WindowManager/Shell/res/values-si/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"කැමරා ගැටලුද?\nයළි සවි කිරීමට තට්ටු කරන්න"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"එය විසඳුවේ නැතිද?\nප්රතිවර්තනය කිරීමට තට්ටු කරන්න"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"කැමරා ගැටලු නොමැතිද? ඉවත දැමීමට තට්ටු කරන්න"</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"සමහර යෙදුම් ප්රතිමූර්තිය තුළ හොඳින්ම ක්රියා කරයි"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"ඔබගේ ඉඩෙන් උපරිම ප්රයෝජන ගැනීමට මෙම විකල්පවලින් එකක් උත්සාහ කරන්න"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"සම්පූර්ණ තිරයට යාමට ඔබගේ උපාංගය කරකවන්න"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"එය නැවත ස්ථානගත කිරීමට යෙදුමකට යාබදව දෙවරක් තට්ටු කරන්න"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"බලන්න සහ තවත් දේ කරන්න"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"බෙදුම් තිරය සඳහා වෙනත් යෙදුමකට අදින්න"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"යෙදුමක් නැවත ස්ථානගත කිරීමට පිටතින් දෙවරක් තට්ටු කරන්න"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"තේරුණා"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"වැඩිදුර තොරතුරු සඳහා දිග හරින්න"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"විහිදන්න"</string>
diff --git a/libs/WindowManager/Shell/res/values-sk/strings.xml b/libs/WindowManager/Shell/res/values-sk/strings.xml
index bc7f151..8859231 100644
--- a/libs/WindowManager/Shell/res/values-sk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sk/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problémy s kamerou?\nKlepnutím znova upravte."</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nevyriešilo sa to?\nKlepnutím sa vráťte."</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nemáte problémy s kamerou? Klepnutím zatvoríte."</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Niektoré aplikácie fungujú najlepšie v režime na výšku"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Vyskúšajte jednu z týchto možností a využívajte svoj priestor naplno"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Otočením zariadenia prejdete do režimu celej obrazovky"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Dvojitým klepnutím vedľa aplikácie zmeníte jej pozíciu"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Zobrazte si a zvládnite toho viac"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Rozdelenú obrazovku aktivujete presunutím ďalšie aplikácie"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Dvojitým klepnutím mimo aplikácie zmeníte jej pozíciu"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Dobre"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Po rozbalení sa dozviete viac."</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maximalizovať"</string>
diff --git a/libs/WindowManager/Shell/res/values-sl/strings.xml b/libs/WindowManager/Shell/res/values-sl/strings.xml
index d2b39b4..22fe0f8 100644
--- a/libs/WindowManager/Shell/res/values-sl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sl/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Težave s fotoaparatom?\nDotaknite se za vnovično prilagoditev"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"To ni odpravilo težave?\nDotaknite se za povrnitev"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nimate težav s fotoaparatom? Dotaknite se za opustitev."</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Nekatere aplikacije najbolje delujejo v navpični postavitvi"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Poskusite eno od teh možnosti za čim boljši izkoristek prostora"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Če želite preklopiti v celozaslonski način, zasukajte napravo."</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Dvakrat se dotaknite ob aplikaciji, če jo želite prestaviti."</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Oglejte si in naredite več"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Za razdeljeni zaslon povlecite sem še eno aplikacijo."</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Dvakrat se dotaknite zunaj aplikacije, če jo želite prestaviti."</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"V redu"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Razširitev za več informacij"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maksimiraj"</string>
diff --git a/libs/WindowManager/Shell/res/values-sq/strings.xml b/libs/WindowManager/Shell/res/values-sq/strings.xml
index 61f669e..2a3671b 100644
--- a/libs/WindowManager/Shell/res/values-sq/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sq/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Ka probleme me kamerën?\nTrokit për ta ripërshtatur"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nuk u rregullua?\nTrokit për ta rikthyer"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nuk ka probleme me kamerën? Trokit për ta shpërfillur."</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Disa aplikacione funksionojnë më mirë në modalitetin vertikal"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Provo një nga këto opsione për ta shfrytëzuar sa më mirë hapësirën"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Rrotullo ekranin për të kaluar në ekran të plotë"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Trokit dy herë pranë një aplikacioni për ta ripozicionuar"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Shiko dhe bëj më shumë"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Zvarrite në një aplikacion tjetër për ekranin e ndarë"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Trokit dy herë jashtë një aplikacioni për ta ripozicionuar"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"E kuptova"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Zgjeroje për më shumë informacion."</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maksimizo"</string>
diff --git a/libs/WindowManager/Shell/res/values-sr/strings.xml b/libs/WindowManager/Shell/res/values-sr/strings.xml
index a6aabf7..09471037 100644
--- a/libs/WindowManager/Shell/res/values-sr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sr/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Имате проблема са камером?\nДодирните да бисте поново уклопили"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Проблем није решен?\nДодирните да бисте вратили"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Немате проблема са камером? Додирните да бисте одбацили."</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Неке апликације најбоље функционишу у усправном режиму"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Испробајте једну од ових опција да бисте на најбољи начин искористили простор"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Ротирајте уређај за приказ преко целог екрана"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Двапут додирните поред апликације да бисте променили њену позицију"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Видите и урадите више"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Превуците другу апликацију да бисте користили подељени екран"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Двапут додирните изван апликације да бисте променили њену позицију"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Важи"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Проширите за још информација."</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Увећајте"</string>
diff --git a/libs/WindowManager/Shell/res/values-sv/strings.xml b/libs/WindowManager/Shell/res/values-sv/strings.xml
index 9a729ce..70282a4b 100644
--- a/libs/WindowManager/Shell/res/values-sv/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sv/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problem med kameran?\nTryck för att anpassa på nytt"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Löstes inte problemet?\nTryck för att återställa"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Inga problem med kameran? Tryck för att ignorera."</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Vissa appar fungerar bäst i stående läge"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Testa med ett av dessa alternativ för att få ut mest möjliga av ytan"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Rotera skärmen för att gå över till helskärmsläge"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Tryck snabbt två gånger bredvid en app för att flytta den"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Se och gör mer"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Dra till en annan app för läget Delad skärm"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Tryck snabbt två gånger utanför en app för att flytta den"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Utöka för mer information."</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Utöka"</string>
diff --git a/libs/WindowManager/Shell/res/values-sw/strings.xml b/libs/WindowManager/Shell/res/values-sw/strings.xml
index 179b842..1aab85c 100644
--- a/libs/WindowManager/Shell/res/values-sw/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sw/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Je, kuna hitilafu za kamera?\nGusa ili urekebishe"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Umeshindwa kurekebisha?\nGusa ili urejeshe nakala ya awali"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Je, hakuna hitilafu za kamera? Gusa ili uondoe."</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Baadhi ya programu hufanya kazi vizuri zaidi zikiwa wima"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Jaribu moja kati ya chaguo hizi ili utumie nafasi ya skrini yako kwa ufanisi"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Zungusha kifaa chako ili uende kwenye hali ya skrini nzima"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Gusa mara mbili karibu na programu ili uihamishe"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Angalia na ufanye zaidi"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Buruta ndani programu nyingine ili utumie hali ya skrini iliyogawanywa"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Gusa mara mbili nje ya programu ili uihamishe"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Nimeelewa"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Panua ili upate maelezo zaidi."</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Panua"</string>
diff --git a/libs/WindowManager/Shell/res/values-ta/strings.xml b/libs/WindowManager/Shell/res/values-ta/strings.xml
index 534474a..befc8eb 100644
--- a/libs/WindowManager/Shell/res/values-ta/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ta/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"கேமரா தொடர்பான சிக்கல்களா?\nமீண்டும் பொருத்த தட்டவும்"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"சிக்கல்கள் சரிசெய்யப்படவில்லையா?\nமாற்றியமைக்க தட்டவும்"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"கேமரா தொடர்பான சிக்கல்கள் எதுவும் இல்லையா? நிராகரிக்க தட்டவும்."</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"சில ஆப்ஸ் \'போர்ட்ரெய்ட்டில்\' சிறப்பாகச் செயல்படும்"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"ஸ்பேஸ்களிலிருந்து அதிகப் பலன்களைப் பெற இந்த விருப்பங்களில் ஒன்றைப் பயன்படுத்துங்கள்"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"முழுத்திரைக்குச் செல்ல உங்கள் சாதனத்தைச் சுழற்றவும்"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"ஆப்ஸை இடம் மாற்ற, ஆப்ஸுக்கு அடுத்து இருமுறை தட்டவும்"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"பலவற்றைப் பார்த்தல் மற்றும் செய்தல்"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"திரைப் பிரிப்புக்கு மற்றொரு ஆப்ஸை இழுக்கலாம்"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"ஆப்ஸை இடம் மாற்ற அதன் வெளியில் இருமுறை தட்டலாம்"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"சரி"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"கூடுதல் தகவல்களுக்கு விரிவாக்கலாம்."</string>
<string name="maximize_button_text" msgid="1650859196290301963">"பெரிதாக்கும்"</string>
diff --git a/libs/WindowManager/Shell/res/values-te/strings.xml b/libs/WindowManager/Shell/res/values-te/strings.xml
index 5ee7c53..88bb130 100644
--- a/libs/WindowManager/Shell/res/values-te/strings.xml
+++ b/libs/WindowManager/Shell/res/values-te/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"కెమెరా సమస్యలు ఉన్నాయా?\nరీఫిట్ చేయడానికి ట్యాప్ చేయండి"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"దాని సమస్యను పరిష్కరించలేదా?\nపూర్వస్థితికి మార్చడానికి ట్యాప్ చేయండి"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"కెమెరా సమస్యలు లేవా? తీసివేయడానికి ట్యాప్ చేయండి."</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"కొన్ని యాప్లు పోర్ట్రెయిట్లో ఉత్తమంగా పని చేస్తాయి"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"మీ ప్రదేశాన్ని ఎక్కువగా ఉపయోగించుకోవడానికి ఈ ఆప్షన్లలో ఒకదాన్ని ట్రై చేయండి"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"ఫుల్ స్క్రీన్కు వెళ్లడానికి మీ పరికరాన్ని తిప్పండి"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"యాప్ స్థానాన్ని మార్చడానికి దాని పక్కన డబుల్-ట్యాప్ చేయండి"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"చూసి, మరిన్ని చేయండి"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"స్ప్లిట్-స్క్రీన్ కోసం మరొక యాప్లోకి లాగండి"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"యాప్ స్థానాన్ని మార్చడానికి దాని వెలుపల డబుల్-ట్యాప్ చేయండి"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"అర్థమైంది"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"మరింత సమాచారం కోసం విస్తరించండి."</string>
<string name="maximize_button_text" msgid="1650859196290301963">"గరిష్టీకరించండి"</string>
diff --git a/libs/WindowManager/Shell/res/values-th/strings.xml b/libs/WindowManager/Shell/res/values-th/strings.xml
index 97db4d9..63d3bb8 100644
--- a/libs/WindowManager/Shell/res/values-th/strings.xml
+++ b/libs/WindowManager/Shell/res/values-th/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"หากพบปัญหากับกล้อง\nแตะเพื่อแก้ไข"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"หากไม่ได้แก้ไข\nแตะเพื่อเปลี่ยนกลับ"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"หากไม่พบปัญหากับกล้อง แตะเพื่อปิด"</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"บางแอปทำงานได้ดีที่สุดในแนวตั้ง"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"ลองใช้หนึ่งในตัวเลือกเหล่านี้เพื่อให้ได้ประโยชน์สูงสุดจากพื้นที่ว่าง"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"หมุนอุปกรณ์ให้แสดงเต็มหน้าจอ"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"แตะสองครั้งข้างแอปเพื่อเปลี่ยนตำแหน่ง"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"รับชมและทำสิ่งต่างๆ ได้มากขึ้น"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"ลากไปไว้ในแอปอื่นเพื่อแยกหน้าจอ"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"แตะสองครั้งด้านนอกแอปเพื่อเปลี่ยนตำแหน่ง"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"รับทราบ"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"ขยายเพื่อดูข้อมูลเพิ่มเติม"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"ขยายใหญ่สุด"</string>
diff --git a/libs/WindowManager/Shell/res/values-tl/strings.xml b/libs/WindowManager/Shell/res/values-tl/strings.xml
index 8e8ee96..50334f5 100644
--- a/libs/WindowManager/Shell/res/values-tl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-tl/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"May mga isyu sa camera?\nI-tap para i-refit"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Hindi ito naayos?\nI-tap para i-revert"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Walang isyu sa camera? I-tap para i-dismiss."</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"May ilang app na pinakamainam gamitin nang naka-portrait"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Subukan ang isa sa mga opsyong ito para masulit ang iyong space"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"I-rotate ang iyong device para mag-full screen"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Mag-double tap sa tabi ng isang app para iposisyon ito ulit"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Tumingin at gumawa ng higit pa"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Mag-drag ng ibang app para sa split screen"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Mag-double tap sa labas ng app para baguhin ang posisyon nito"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"I-expand para sa higit pang impormasyon."</string>
<string name="maximize_button_text" msgid="1650859196290301963">"I-maximize"</string>
diff --git a/libs/WindowManager/Shell/res/values-tr/strings.xml b/libs/WindowManager/Shell/res/values-tr/strings.xml
index ed3540b..e1ea0df 100644
--- a/libs/WindowManager/Shell/res/values-tr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-tr/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Kameranızda sorun mu var?\nDüzeltmek için dokunun"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Bu işlem sorunu düzeltmedi mi?\nİşlemi geri almak için dokunun"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Kameranızda sorun yok mu? Kapatmak için dokunun."</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Bazı uygulamalar dikey modda en iyi performansı gösterir"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Alanınızı en verimli şekilde kullanmak için bu seçeneklerden birini deneyin"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Tam ekrana geçmek için cihazınızı döndürün"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Yeniden konumlandırmak için uygulamanın yanına iki kez dokunun"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Daha fazlasını görün ve yapın"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Bölünmüş ekran için başka bir uygulamayı sürükleyin"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Yeniden konumlandırmak için uygulamanın dışına iki kez dokunun"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Anladım"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Daha fazla bilgi için genişletin."</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Ekranı Kapla"</string>
diff --git a/libs/WindowManager/Shell/res/values-uk/strings.xml b/libs/WindowManager/Shell/res/values-uk/strings.xml
index 23d1951..9e713c7 100644
--- a/libs/WindowManager/Shell/res/values-uk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-uk/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Проблеми з камерою?\nНатисніть, щоб пристосувати"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Проблему не вирішено?\nНатисніть, щоб скасувати зміни"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Немає проблем із камерою? Торкніться, щоб закрити."</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Деякі додатки найкраще працюють у вертикальній орієнтації"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Щоб максимально ефективно використовувати місце на екрані, спробуйте виконати одну з наведених нижче дій"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Щоб перейти в повноекранний режим, поверніть пристрій"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Щоб перемістити додаток, двічі торкніться області поруч із ним"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Більше простору та можливостей"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Щоб перейти в режим розділення екрана, перетягніть сюди інший додаток"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Щоб перемістити додаток, двічі торкніться області поза ним"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"ОK"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Розгорніть, щоб дізнатися більше."</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Збільшити"</string>
diff --git a/libs/WindowManager/Shell/res/values-ur/strings.xml b/libs/WindowManager/Shell/res/values-ur/strings.xml
index 70df7f0..596cf4b 100644
--- a/libs/WindowManager/Shell/res/values-ur/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ur/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"کیمرے کے مسائل؟\nدوبارہ فٹ کرنے کیلئے تھپتھپائیں"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"یہ حل نہیں ہوا؟\nلوٹانے کیلئے تھپتھپائیں"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"کوئی کیمرے کا مسئلہ نہیں ہے؟ برخاست کرنے کیلئے تھپتھپائیں۔"</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"کچھ ایپس پورٹریٹ میں بہترین کام کرتی ہیں"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"اپنی اسپیس کا زیادہ سے زیادہ فائدہ اٹھانے کے لیے ان اختیارات میں سے ایک کو آزمائیں"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"پوری اسکرین پر جانے کیلئے اپنا آلہ گھمائیں"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"کسی ایپ کی پوزیشن تبدیل کرنے کے لیے اس کے آگے دو بار تھپتھپائیں"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"دیکھیں اور بہت کچھ کریں"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"اسپلٹ اسکرین کے ليے دوسری ایپ میں گھسیٹیں"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"کسی ایپ کی پوزیشن تبدیل کرنے کے لیے اس ایپ کے باہر دو بار تھپتھپائیں"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"سمجھ آ گئی"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"مزید معلومات کے لیے پھیلائیں۔"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"بڑا کریں"</string>
diff --git a/libs/WindowManager/Shell/res/values-uz/strings.xml b/libs/WindowManager/Shell/res/values-uz/strings.xml
index 7be8637..275940a 100644
--- a/libs/WindowManager/Shell/res/values-uz/strings.xml
+++ b/libs/WindowManager/Shell/res/values-uz/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Kamera nosozmi?\nQayta moslash uchun bosing"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Tuzatilmadimi?\nQaytarish uchun bosing"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Kamera muammosizmi? Yopish uchun bosing."</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Ayrim ilovalar tik holatda ishlashga eng mos"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Muhitdan yanada samarali foydalanish uchun quyidagilardan birini sinang"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Butun ekranda ochish uchun qurilmani buring"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Qayta joylash uchun keyingi ilova ustiga ikki marta bosing"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Yana boshqa amallar"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Ekranni ikkiga ajratish uchun boshqa ilovani bu yerga torting"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Qayta joylash uchun ilova tashqarisiga ikki marta bosing"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Batafsil axborot olish uchun kengaytiring."</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Yoyish"</string>
diff --git a/libs/WindowManager/Shell/res/values-vi/strings.xml b/libs/WindowManager/Shell/res/values-vi/strings.xml
index daf3a41..24fb1ca 100644
--- a/libs/WindowManager/Shell/res/values-vi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-vi/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Có vấn đề với máy ảnh?\nHãy nhấn để sửa lỗi"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Bạn chưa khắc phục vấn đề?\nHãy nhấn để hủy bỏ"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Không có vấn đề với máy ảnh? Hãy nhấn để đóng."</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Một số ứng dụng hoạt động tốt nhất ở chế độ dọc"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Hãy thử một trong các tuỳ chọn sau để tận dụng không gian"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Xoay thiết bị để chuyển sang chế độ toàn màn hình"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Nhấn đúp vào bên cạnh ứng dụng để đặt lại vị trí"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Xem và làm được nhiều việc hơn"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Kéo vào một ứng dụng khác để chia đôi màn hình"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Nhấn đúp bên ngoài ứng dụng để đặt lại vị trí"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Mở rộng để xem thêm thông tin."</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Phóng to"</string>
diff --git a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
index 62b077c..e52a7b5 100644
--- a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"相机有问题?\n点按即可整修"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"没有解决此问题?\n点按即可恢复"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"相机没有问题?点按即可忽略。"</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"某些应用在纵向模式下才能发挥最佳效果"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"这些选项都有助于您最大限度地利用屏幕空间,不妨从中择一试试"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"旋转设备即可进入全屏模式"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"在某个应用旁边连续点按两次,即可调整它的位置"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"查看和处理更多任务"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"拖入另一个应用,即可使用分屏模式"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"在某个应用外连续点按两次,即可调整它的位置"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"知道了"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"展开即可了解详情。"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"最大化"</string>
diff --git a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
index c0754d9..bb156c1 100644
--- a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"相機有問題?\n輕按即可修正"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"未能修正問題?\n輕按即可還原"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"相機冇問題?㩒一下就可以即可閂咗佢。"</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"部分應用程式需要使用直向模式才能發揮最佳效果"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"請嘗試以下選項,充分運用螢幕的畫面空間"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"旋轉裝置方向即可進入全螢幕模式"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"在應用程式旁輕按兩下即可調整位置"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"瀏覽更多內容及執行更多操作"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"拖進另一個應用程式即可使用分割畫面模式"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"在應用程式外輕觸兩下即可調整位置"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"知道了"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"展開即可查看詳情。"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"最大化"</string>
diff --git a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
index b193f2e..f9f28ab 100644
--- a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"相機有問題嗎?\n輕觸即可修正"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"未修正問題嗎?\n輕觸即可還原"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"相機沒問題嗎?輕觸即可關閉。"</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"某些應用程式在直向模式下才能發揮最佳效果"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"請試試這裡的任一方式,以充分運用螢幕畫面的空間"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"旋轉裝置方向即可進入全螢幕模式"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"在應用程式旁輕觸兩下即可調整位置"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"瀏覽更多內容及執行更多操作"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"拖進另一個應用程式即可使用分割畫面模式"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"在應用程式外輕觸兩下即可調整位置"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"我知道了"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"展開即可查看詳細資訊。"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"最大化"</string>
diff --git a/libs/WindowManager/Shell/res/values-zu/strings.xml b/libs/WindowManager/Shell/res/values-zu/strings.xml
index bf819b1..ddb6a4c 100644
--- a/libs/WindowManager/Shell/res/values-zu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zu/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Izinkinga zekhamera?\nThepha ukuze uyilinganise kabusha"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Akuyilungisanga?\nThepha ukuze ubuyele"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Azikho izinkinga zekhamera? Thepha ukuze ucashise."</string>
- <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Amanye ama-app asebenza ngcono uma eme ngobude"</string>
- <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Zama enye yalezi zinketho ukuze usebenzise isikhala sakho ngokugcwele"</string>
- <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Zungezisa idivayisi yakho ukuze uye esikrinini esigcwele"</string>
- <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Thepha kabili eduze kwe-app ukuze uyimise kabusha"</string>
+ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Bona futhi wenze okuningi"</string>
+ <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Hudula kwenye i-app mayelana nokuhlukanisa isikrini"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Thepha kabili ngaphandle kwe-app ukuze uyimise kabusha"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Ngiyezwa"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Nweba ukuze uthole ulwazi olwengeziwe"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Khulisa"</string>
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index d2dd8d6b..5696b8d 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -81,6 +81,9 @@
<!-- The width and height of the background for custom action in PiP menu. -->
<dimen name="pip_custom_close_bg_size">32dp</dimen>
+ <!-- Extra padding between picture-in-picture windows and any registered keep clear areas. -->
+ <dimen name="pip_keep_clear_areas_padding">16dp</dimen>
+
<dimen name="dismiss_target_x_size">24dp</dimen>
<dimen name="floating_dismiss_bottom_margin">50dp</dimen>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ProtoLogController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ProtoLogController.java
new file mode 100644
index 0000000..d276002
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ProtoLogController.java
@@ -0,0 +1,112 @@
+/*
+ * 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.wm.shell;
+
+import com.android.wm.shell.protolog.ShellProtoLogImpl;
+import com.android.wm.shell.sysui.ShellCommandHandler;
+import com.android.wm.shell.sysui.ShellInit;
+
+import java.io.PrintWriter;
+import java.util.Arrays;
+
+/**
+ * Controls the {@link ShellProtoLogImpl} in WMShell via adb shell commands.
+ *
+ * Use with {@code adb shell dumpsys activity service SystemUIService WMShell protolog ...}.
+ */
+public class ProtoLogController implements ShellCommandHandler.ShellCommandActionHandler {
+ private final ShellCommandHandler mShellCommandHandler;
+ private final ShellProtoLogImpl mShellProtoLog;
+
+ public ProtoLogController(ShellInit shellInit,
+ ShellCommandHandler shellCommandHandler) {
+ shellInit.addInitCallback(this::onInit, this);
+ mShellCommandHandler = shellCommandHandler;
+ mShellProtoLog = ShellProtoLogImpl.getSingleInstance();
+ }
+
+ void onInit() {
+ mShellCommandHandler.addCommandCallback("protolog", this, this);
+ }
+
+ @Override
+ public boolean onShellCommand(String[] args, PrintWriter pw) {
+ switch (args[0]) {
+ case "status": {
+ pw.println(mShellProtoLog.getStatus());
+ return true;
+ }
+ case "start": {
+ mShellProtoLog.startProtoLog(pw);
+ return true;
+ }
+ case "stop": {
+ mShellProtoLog.stopProtoLog(pw, true /* writeToFile */);
+ return true;
+ }
+ case "enable-text": {
+ String[] groups = Arrays.copyOfRange(args, 1, args.length);
+ int result = mShellProtoLog.startTextLogging(groups, pw);
+ if (result == 0) {
+ pw.println("Starting logging on groups: " + Arrays.toString(groups));
+ return true;
+ }
+ return false;
+ }
+ case "disable-text": {
+ String[] groups = Arrays.copyOfRange(args, 1, args.length);
+ int result = mShellProtoLog.stopTextLogging(groups, pw);
+ if (result == 0) {
+ pw.println("Stopping logging on groups: " + Arrays.toString(groups));
+ return true;
+ }
+ return false;
+ }
+ case "enable": {
+ String[] groups = Arrays.copyOfRange(args, 1, args.length);
+ return mShellProtoLog.startTextLogging(groups, pw) == 0;
+ }
+ case "disable": {
+ String[] groups = Arrays.copyOfRange(args, 1, args.length);
+ return mShellProtoLog.stopTextLogging(groups, pw) == 0;
+ }
+ default: {
+ pw.println("Invalid command: " + args[0]);
+ printShellCommandHelp(pw, "");
+ return false;
+ }
+ }
+ }
+
+ @Override
+ public void printShellCommandHelp(PrintWriter pw, String prefix) {
+ pw.println(prefix + "status");
+ pw.println(prefix + " Get current ProtoLog status.");
+ pw.println(prefix + "start");
+ pw.println(prefix + " Start proto logging.");
+ pw.println(prefix + "stop");
+ pw.println(prefix + " Stop proto logging and flush to file.");
+ pw.println(prefix + "enable [group...]");
+ pw.println(prefix + " Enable proto logging for given groups.");
+ pw.println(prefix + "disable [group...]");
+ pw.println(prefix + " Disable proto logging for given groups.");
+ pw.println(prefix + "enable-text [group...]");
+ pw.println(prefix + " Enable logcat logging for given groups.");
+ pw.println(prefix + "disable-text [group...]");
+ pw.println(prefix + " Disable logcat logging for given groups.");
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
index d5d4935..4367936 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
@@ -16,6 +16,7 @@
package com.android.wm.shell;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
@@ -695,15 +696,19 @@
/**
* Create a {@link WindowContainerTransaction} to clear task bounds.
*
+ * Only affects tasks that have {@link RunningTaskInfo#getActivityType()} set to
+ * {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD}.
+ *
* @param displayId display id for tasks that will have bounds cleared
* @return {@link WindowContainerTransaction} with pending operations to clear bounds
*/
- public WindowContainerTransaction prepareClearBoundsForTasks(int displayId) {
+ public WindowContainerTransaction prepareClearBoundsForStandardTasks(int displayId) {
ProtoLog.d(WM_SHELL_DESKTOP_MODE, "prepareClearBoundsForTasks: displayId=%d", displayId);
WindowContainerTransaction wct = new WindowContainerTransaction();
for (int i = 0; i < mTasks.size(); i++) {
RunningTaskInfo taskInfo = mTasks.valueAt(i).getTaskInfo();
- if (taskInfo.displayId == displayId) {
+ if ((taskInfo.displayId == displayId) && (taskInfo.getActivityType()
+ == WindowConfiguration.ACTIVITY_TYPE_STANDARD)) {
ProtoLog.d(WM_SHELL_DESKTOP_MODE, "clearing bounds for token=%s taskInfo=%s",
taskInfo.token, taskInfo);
wct.setBounds(taskInfo.token, null);
@@ -715,17 +720,21 @@
/**
* Create a {@link WindowContainerTransaction} to clear task level freeform setting.
*
+ * Only affects tasks that have {@link RunningTaskInfo#getActivityType()} set to
+ * {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD}.
+ *
* @param displayId display id for tasks that will have windowing mode reset to {@link
* WindowConfiguration#WINDOWING_MODE_UNDEFINED}
* @return {@link WindowContainerTransaction} with pending operations to clear windowing mode
*/
- public WindowContainerTransaction prepareClearFreeformForTasks(int displayId) {
+ public WindowContainerTransaction prepareClearFreeformForStandardTasks(int displayId) {
ProtoLog.d(WM_SHELL_DESKTOP_MODE, "prepareClearFreeformForTasks: displayId=%d", displayId);
WindowContainerTransaction wct = new WindowContainerTransaction();
for (int i = 0; i < mTasks.size(); i++) {
RunningTaskInfo taskInfo = mTasks.valueAt(i).getTaskInfo();
if (taskInfo.displayId == displayId
- && taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) {
+ && taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM
+ && taskInfo.getActivityType() == ACTIVITY_TYPE_STANDARD) {
ProtoLog.d(WM_SHELL_DESKTOP_MODE,
"clearing windowing mode for token=%s taskInfo=%s", taskInfo.token,
taskInfo);
@@ -867,8 +876,12 @@
pkg = info.getTaskInfo().baseActivity.getPackageName();
}
Rect bounds = info.getTaskInfo().getConfiguration().windowConfiguration.getBounds();
+ boolean running = info.getTaskInfo().isRunning;
+ boolean visible = info.getTaskInfo().isVisible;
+ boolean focused = info.getTaskInfo().isFocused;
pw.println(innerPrefix + "#" + i + " task=" + key + " listener=" + listener
- + " wmMode=" + windowingMode + " pkg=" + pkg + " bounds=" + bounds);
+ + " wmMode=" + windowingMode + " pkg=" + pkg + " bounds=" + bounds
+ + " running=" + running + " visible=" + visible + " focused=" + focused);
}
pw.println();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
index 99b8885..b5a5754 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
@@ -170,7 +170,8 @@
@VisibleForTesting(visibility = PRIVATE)
public Bubble(@NonNull final String key, @NonNull final ShortcutInfo shortcutInfo,
final int desiredHeight, final int desiredHeightResId, @Nullable final String title,
- int taskId, @Nullable final String locus, Executor mainExecutor) {
+ int taskId, @Nullable final String locus, Executor mainExecutor,
+ final Bubbles.BubbleMetadataFlagListener listener) {
Objects.requireNonNull(key);
Objects.requireNonNull(shortcutInfo);
mMetadataShortcutId = shortcutInfo.getId();
@@ -188,11 +189,12 @@
mShowBubbleUpdateDot = false;
mMainExecutor = mainExecutor;
mTaskId = taskId;
+ mBubbleMetadataFlagListener = listener;
}
@VisibleForTesting(visibility = PRIVATE)
public Bubble(@NonNull final BubbleEntry entry,
- @Nullable final Bubbles.BubbleMetadataFlagListener listener,
+ final Bubbles.BubbleMetadataFlagListener listener,
final Bubbles.PendingIntentCanceledListener intentCancelListener,
Executor mainExecutor) {
mKey = entry.getKey();
@@ -830,6 +832,7 @@
pw.print(" desiredHeight: "); pw.println(getDesiredHeightString());
pw.print(" suppressNotif: "); pw.println(shouldSuppressNotification());
pw.print(" autoExpand: "); pw.println(shouldAutoExpand());
+ pw.print(" bubbleMetadataFlagListener null: " + (mBubbleMetadataFlagListener == null));
if (mExpandedView != null) {
mExpandedView.dump(pw);
}
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 d63c25d..0dfba34 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
@@ -309,6 +309,7 @@
protected void onInit() {
mBubbleData.setListener(mBubbleDataListener);
mBubbleData.setSuppressionChangedListener(this::onBubbleMetadataFlagChanged);
+ mDataRepository.setSuppressionChangedListener(this::onBubbleMetadataFlagChanged);
mBubbleData.setPendingIntentCancelledListener(bubble -> {
if (bubble.getBubbleIntent() == null) {
@@ -1336,19 +1337,7 @@
}
mSysuiProxy.updateNotificationBubbleButton(bubble.getKey());
}
-
}
- mSysuiProxy.getPendingOrActiveEntry(bubble.getKey(), (entry) -> {
- mMainExecutor.execute(() -> {
- if (entry != null) {
- final String groupKey = entry.getStatusBarNotification().getGroupKey();
- if (getBubblesInGroup(groupKey).isEmpty()) {
- // Time to potentially remove the summary
- mSysuiProxy.notifyMaybeCancelSummary(bubble.getKey());
- }
- }
- });
- });
}
mDataRepository.removeBubbles(mCurrentUserId, bubblesToBeRemovedFromRepository);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
index c64133f..af31391 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
@@ -158,7 +158,6 @@
@Nullable
private Listener mListener;
- @Nullable
private Bubbles.BubbleMetadataFlagListener mBubbleMetadataFlagListener;
private Bubbles.PendingIntentCanceledListener mCancelledListener;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDataRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDataRepository.kt
index 97560f4..3a59614 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDataRepository.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDataRepository.kt
@@ -25,6 +25,7 @@
import android.content.pm.UserInfo
import android.os.UserHandle
import android.util.Log
+import com.android.wm.shell.bubbles.Bubbles.BubbleMetadataFlagListener
import com.android.wm.shell.bubbles.storage.BubbleEntity
import com.android.wm.shell.bubbles.storage.BubblePersistentRepository
import com.android.wm.shell.bubbles.storage.BubbleVolatileRepository
@@ -47,6 +48,13 @@
private val ioScope = CoroutineScope(Dispatchers.IO)
private var job: Job? = null
+ // For use in Bubble construction.
+ private lateinit var bubbleMetadataFlagListener: BubbleMetadataFlagListener
+
+ fun setSuppressionChangedListener(listener: BubbleMetadataFlagListener) {
+ bubbleMetadataFlagListener = listener
+ }
+
/**
* Adds the bubble in memory, then persists the snapshot after adding the bubble to disk
* asynchronously.
@@ -197,7 +205,8 @@
entity.title,
entity.taskId,
entity.locus,
- mainExecutor
+ mainExecutor,
+ bubbleMetadataFlagListener
)
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
index 453b34e..b3104b5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
@@ -276,8 +276,6 @@
void notifyInvalidateNotifications(String reason);
- void notifyMaybeCancelSummary(String key);
-
void updateNotificationBubbleButton(String key);
void onStackExpandChanged(boolean shouldExpand);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java
index 47f1e2e..96efeeb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java
@@ -96,7 +96,8 @@
/**
* Different from {@link #equals(Object)}, this method compares the basic geometry properties
- * of two {@link DisplayLayout} objects including width, height, rotation, density and cutout.
+ * of two {@link DisplayLayout} objects including width, height, rotation, density, cutout and
+ * insets.
* @return {@code true} if the given {@link DisplayLayout} is identical geometry wise.
*/
public boolean isSameGeometry(@NonNull DisplayLayout other) {
@@ -104,7 +105,8 @@
&& mHeight == other.mHeight
&& mRotation == other.mRotation
&& mDensityDpi == other.mDensityDpi
- && Objects.equals(mCutout, other.mCutout);
+ && Objects.equals(mCutout, other.mCutout)
+ && Objects.equals(mStableInsets, other.mStableInsets);
}
@Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
index 7a736cc..c39602032 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
@@ -27,6 +27,7 @@
import com.android.internal.logging.UiEventLogger;
import com.android.launcher3.icons.IconProvider;
+import com.android.wm.shell.ProtoLogController;
import com.android.wm.shell.RootDisplayAreaOrganizer;
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.ShellTaskOrganizer;
@@ -699,6 +700,7 @@
Optional<ActivityEmbeddingController> activityEmbeddingOptional,
Transitions transitions,
StartingWindowController startingWindow,
+ ProtoLogController protoLogController,
@ShellCreateTriggerOverride Optional<Object> overriddenCreateTrigger) {
return new Object();
}
@@ -714,4 +716,12 @@
static ShellCommandHandler provideShellCommandHandler() {
return new ShellCommandHandler();
}
+
+ @WMSingleton
+ @Provides
+ static ProtoLogController provideProtoLogController(
+ ShellInit shellInit,
+ ShellCommandHandler shellCommandHandler) {
+ return new ProtoLogController(shellInit, shellCommandHandler);
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
index 31596f3..18ce364 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
@@ -49,7 +49,7 @@
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.common.annotations.ShellBackgroundThread;
import com.android.wm.shell.common.annotations.ShellMainThread;
-import com.android.wm.shell.desktopmode.DesktopModeConstants;
+import com.android.wm.shell.desktopmode.DesktopMode;
import com.android.wm.shell.desktopmode.DesktopModeController;
import com.android.wm.shell.draganddrop.DragAndDropController;
import com.android.wm.shell.freeform.FreeformComponents;
@@ -72,9 +72,9 @@
import com.android.wm.shell.pip.PipTransitionController;
import com.android.wm.shell.pip.PipTransitionState;
import com.android.wm.shell.pip.PipUiEventLogger;
+import com.android.wm.shell.pip.phone.PhonePipKeepClearAlgorithm;
import com.android.wm.shell.pip.phone.PhonePipMenuController;
import com.android.wm.shell.pip.phone.PipController;
-import com.android.wm.shell.pip.phone.PipKeepClearAlgorithm;
import com.android.wm.shell.pip.phone.PipMotionHelper;
import com.android.wm.shell.pip.phone.PipTouchHandler;
import com.android.wm.shell.recents.RecentTasksController;
@@ -82,7 +82,7 @@
import com.android.wm.shell.sysui.ShellCommandHandler;
import com.android.wm.shell.sysui.ShellController;
import com.android.wm.shell.sysui.ShellInit;
-import com.android.wm.shell.transition.SplitscreenPipMixedHandler;
+import com.android.wm.shell.transition.DefaultMixedHandler;
import com.android.wm.shell.transition.Transitions;
import com.android.wm.shell.unfold.ShellUnfoldProgressProvider;
import com.android.wm.shell.unfold.UnfoldAnimationController;
@@ -220,13 +220,14 @@
Context context,
ShellInit shellInit,
ShellTaskOrganizer shellTaskOrganizer,
+ Optional<RecentTasksController> recentTasksController,
WindowDecorViewModel<?> windowDecorViewModel) {
// TODO(b/238217847): Temporarily add this check here until we can remove the dynamic
// override for this controller from the base module
ShellInit init = FreeformComponents.isFreeformEnabled(context)
? shellInit
: null;
- return new FreeformTaskListener<>(init, shellTaskOrganizer,
+ return new FreeformTaskListener<>(init, shellTaskOrganizer, recentTasksController,
windowDecorViewModel);
}
@@ -320,7 +321,7 @@
DisplayController displayController,
PipAppOpsListener pipAppOpsListener,
PipBoundsAlgorithm pipBoundsAlgorithm,
- PipKeepClearAlgorithm pipKeepClearAlgorithm,
+ PhonePipKeepClearAlgorithm pipKeepClearAlgorithm,
PipBoundsState pipBoundsState,
PipMotionHelper pipMotionHelper,
PipMediaController pipMediaController,
@@ -332,6 +333,7 @@
WindowManagerShellWrapper windowManagerShellWrapper,
TaskStackListenerImpl taskStackListener,
PipParamsChangedForwarder pipParamsChangedForwarder,
+ DisplayInsetsController displayInsetsController,
Optional<OneHandedController> oneHandedController,
@ShellMainThread ShellExecutor mainExecutor) {
return Optional.ofNullable(PipController.create(
@@ -340,7 +342,7 @@
pipBoundsState, pipMotionHelper, pipMediaController, phonePipMenuController,
pipTaskOrganizer, pipTransitionState, pipTouchHandler, pipTransitionController,
windowManagerShellWrapper, taskStackListener, pipParamsChangedForwarder,
- oneHandedController, mainExecutor));
+ displayInsetsController, oneHandedController, mainExecutor));
}
@WMSingleton
@@ -357,15 +359,17 @@
@WMSingleton
@Provides
- static PipKeepClearAlgorithm providePipKeepClearAlgorithm() {
- return new PipKeepClearAlgorithm();
+ static PhonePipKeepClearAlgorithm providePhonePipKeepClearAlgorithm(Context context) {
+ return new PhonePipKeepClearAlgorithm(context);
}
@WMSingleton
@Provides
static PipBoundsAlgorithm providesPipBoundsAlgorithm(Context context,
- PipBoundsState pipBoundsState, PipSnapAlgorithm pipSnapAlgorithm) {
- return new PipBoundsAlgorithm(context, pipBoundsState, pipSnapAlgorithm);
+ PipBoundsState pipBoundsState, PipSnapAlgorithm pipSnapAlgorithm,
+ PhonePipKeepClearAlgorithm pipKeepClearAlgorithm) {
+ return new PipBoundsAlgorithm(context, pipBoundsState, pipSnapAlgorithm,
+ pipKeepClearAlgorithm);
}
// Handler is used by Icon.loadDrawableAsync
@@ -481,13 +485,13 @@
@WMSingleton
@Provides
- static SplitscreenPipMixedHandler provideSplitscreenPipMixedHandler(
+ static DefaultMixedHandler provideDefaultMixedHandler(
ShellInit shellInit,
Optional<SplitScreenController> splitScreenOptional,
Optional<PipTouchHandler> pipTouchHandlerOptional,
Transitions transitions) {
- return new SplitscreenPipMixedHandler(shellInit, splitScreenOptional,
- pipTouchHandlerOptional, transitions);
+ return new DefaultMixedHandler(shellInit, transitions, splitScreenOptional,
+ pipTouchHandlerOptional);
}
//
@@ -597,7 +601,7 @@
RootDisplayAreaOrganizer rootDisplayAreaOrganizer,
@ShellMainThread Handler mainHandler
) {
- if (DesktopModeConstants.IS_FEATURE_ENABLED) {
+ if (DesktopMode.IS_SUPPORTED) {
return Optional.of(new DesktopModeController(context, shellInit, shellTaskOrganizer,
rootDisplayAreaOrganizer,
mainHandler));
@@ -616,7 +620,7 @@
@ShellCreateTriggerOverride
@Provides
static Object provideIndependentShellComponentsToCreate(
- SplitscreenPipMixedHandler splitscreenPipMixedHandler,
+ DefaultMixedHandler defaultMixedHandler,
Optional<DesktopModeController> desktopModeController) {
return new Object();
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMode.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMode.java
new file mode 100644
index 0000000..8993d54
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMode.java
@@ -0,0 +1,58 @@
+/*
+ * 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.wm.shell.desktopmode;
+
+import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE;
+
+import android.content.Context;
+import android.os.SystemProperties;
+import android.os.UserHandle;
+import android.provider.Settings;
+
+import com.android.internal.protolog.common.ProtoLog;
+
+/**
+ * Constants for desktop mode feature
+ */
+public class DesktopMode {
+
+ /**
+ * Flag to indicate whether desktop mode is available on the device
+ */
+ public static final boolean IS_SUPPORTED = SystemProperties.getBoolean(
+ "persist.wm.debug.desktop_mode", false);
+
+ /**
+ * Check if desktop mode is active
+ *
+ * @return {@code true} if active
+ */
+ public static boolean isActive(Context context) {
+ if (!IS_SUPPORTED) {
+ return false;
+ }
+ try {
+ int result = Settings.System.getIntForUser(context.getContentResolver(),
+ Settings.System.DESKTOP_MODE, UserHandle.USER_CURRENT);
+ ProtoLog.d(WM_SHELL_DESKTOP_MODE, "isDesktopModeEnabled=%s", result);
+ return result != 0;
+ } catch (Exception e) {
+ ProtoLog.e(WM_SHELL_DESKTOP_MODE, "Failed to read DESKTOP_MODE setting %s", e);
+ return false;
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java
index 5849e16..7d34ea4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java
@@ -62,25 +62,29 @@
private void onInit() {
ProtoLog.d(WM_SHELL_DESKTOP_MODE, "Initialize DesktopModeController");
mSettingsObserver.observe();
+ if (DesktopMode.isActive(mContext)) {
+ updateDesktopModeActive(true);
+ }
}
@VisibleForTesting
- void updateDesktopModeEnabled(boolean enabled) {
- ProtoLog.d(WM_SHELL_DESKTOP_MODE, "updateDesktopModeState: enabled=%s", enabled);
+ void updateDesktopModeActive(boolean active) {
+ ProtoLog.d(WM_SHELL_DESKTOP_MODE, "updateDesktopModeActive: active=%s", active);
int displayId = mContext.getDisplayId();
WindowContainerTransaction wct = new WindowContainerTransaction();
// Reset freeform windowing mode that is set per task level (tasks should inherit
// container value)
- wct.merge(mShellTaskOrganizer.prepareClearFreeformForTasks(displayId), true /* transfer */);
+ wct.merge(mShellTaskOrganizer.prepareClearFreeformForStandardTasks(displayId),
+ true /* transfer */);
int targetWindowingMode;
- if (enabled) {
+ if (active) {
targetWindowingMode = WINDOWING_MODE_FREEFORM;
} else {
targetWindowingMode = WINDOWING_MODE_FULLSCREEN;
// Clear any resized bounds
- wct.merge(mShellTaskOrganizer.prepareClearBoundsForTasks(displayId),
+ wct.merge(mShellTaskOrganizer.prepareClearBoundsForStandardTasks(displayId),
true /* transfer */);
}
wct.merge(mRootDisplayAreaOrganizer.prepareWindowingModeChange(displayId,
@@ -118,20 +122,8 @@
}
private void desktopModeSettingChanged() {
- boolean enabled = isDesktopModeEnabled();
- updateDesktopModeEnabled(enabled);
- }
-
- private boolean isDesktopModeEnabled() {
- try {
- int result = Settings.System.getIntForUser(mContext.getContentResolver(),
- Settings.System.DESKTOP_MODE, UserHandle.USER_CURRENT);
- ProtoLog.d(WM_SHELL_DESKTOP_MODE, "isDesktopModeEnabled=%s", result);
- return result != 0;
- } catch (Settings.SettingNotFoundException e) {
- ProtoLog.e(WM_SHELL_DESKTOP_MODE, "Failed to read DESKTOP_MODE setting %s", e);
- return false;
- }
+ boolean enabled = DesktopMode.isActive(mContext);
+ updateDesktopModeActive(enabled);
}
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
index 4697a01..b59fe18 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
@@ -258,12 +258,12 @@
break;
case ACTION_DRAG_ENTERED:
pd.dragLayout.show();
- pd.dragLayout.update(event);
break;
case ACTION_DRAG_LOCATION:
pd.dragLayout.update(event);
break;
case ACTION_DROP: {
+ pd.dragLayout.update(event);
return handleDrop(event, pd);
}
case ACTION_DRAG_EXITED: {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java
index 8dcdda1..1baac71 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java
@@ -28,12 +28,15 @@
import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.desktopmode.DesktopMode;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
+import com.android.wm.shell.recents.RecentTasksController;
import com.android.wm.shell.sysui.ShellInit;
import com.android.wm.shell.transition.Transitions;
import com.android.wm.shell.windowdecor.WindowDecorViewModel;
import java.io.PrintWriter;
+import java.util.Optional;
/**
* {@link ShellTaskOrganizer.TaskListener} for {@link
@@ -46,6 +49,7 @@
private static final String TAG = "FreeformTaskListener";
private final ShellTaskOrganizer mShellTaskOrganizer;
+ private final Optional<RecentTasksController> mRecentTasksOptional;
private final WindowDecorViewModel<T> mWindowDecorationViewModel;
private final SparseArray<State<T>> mTasks = new SparseArray<>();
@@ -60,9 +64,11 @@
public FreeformTaskListener(
ShellInit shellInit,
ShellTaskOrganizer shellTaskOrganizer,
+ Optional<RecentTasksController> recentTasksController,
WindowDecorViewModel<T> windowDecorationViewModel) {
mShellTaskOrganizer = shellTaskOrganizer;
mWindowDecorationViewModel = windowDecorationViewModel;
+ mRecentTasksOptional = recentTasksController;
if (shellInit != null) {
shellInit.addInitCallback(this::onInit, this);
}
@@ -83,6 +89,12 @@
mWindowDecorationViewModel.createWindowDecoration(taskInfo, leash, t, t);
t.apply();
}
+
+ if (DesktopMode.IS_SUPPORTED && taskInfo.isVisible) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE,
+ "Adding active freeform task: #%d", taskInfo.taskId);
+ mRecentTasksOptional.ifPresent(rt -> rt.addActiveFreeformTask(taskInfo.taskId));
+ }
}
private State<T> createOrUpdateTaskState(RunningTaskInfo taskInfo, SurfaceControl leash) {
@@ -111,6 +123,12 @@
taskInfo.taskId);
mTasks.remove(taskInfo.taskId);
+ if (DesktopMode.IS_SUPPORTED) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE,
+ "Removing active freeform task: #%d", taskInfo.taskId);
+ mRecentTasksOptional.ifPresent(rt -> rt.removeActiveFreeformTask(taskInfo.taskId));
+ }
+
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
// Save window decorations of closing tasks so that we can hand them over to the
// transition system if this method happens before the transition. In case where the
@@ -131,6 +149,14 @@
if (state.mWindowDecoration != null) {
mWindowDecorationViewModel.onTaskInfoChanged(state.mTaskInfo, state.mWindowDecoration);
}
+
+ if (DesktopMode.IS_SUPPORTED) {
+ if (taskInfo.isVisible) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE,
+ "Adding active freeform task: #%d", taskInfo.taskId);
+ mRecentTasksOptional.ifPresent(rt -> rt.addActiveFreeformTask(taskInfo.taskId));
+ }
+ }
}
private State<T> updateTaskInfo(RunningTaskInfo taskInfo) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPip.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPip.aidl
index e03421d..4def15d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPip.aidl
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPip.aidl
@@ -37,12 +37,13 @@
* @param activityInfo ActivityInfo tied to the Activity
* @param pictureInPictureParams PictureInPictureParams tied to the Activity
* @param launcherRotation Launcher rotation to calculate the PiP destination bounds
- * @param shelfHeight Shelf height of launcher to calculate the PiP destination bounds
+ * @param hotseatKeepClearArea Bounds of Hotseat to avoid used to calculate PiP destination
+ bounds
* @return destination bounds the PiP window should land into
*/
Rect startSwipePipToHome(in ComponentName componentName, in ActivityInfo activityInfo,
in PictureInPictureParams pictureInPictureParams,
- int launcherRotation, int shelfHeight) = 1;
+ int launcherRotation, in Rect hotseatKeepClearArea) = 1;
/**
* Notifies the swiping Activity to PiP onto home transition is finished
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java
index 7397e52..cd61dbb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java
@@ -47,6 +47,7 @@
private final @NonNull PipBoundsState mPipBoundsState;
private final PipSnapAlgorithm mSnapAlgorithm;
+ private final PipKeepClearAlgorithm mPipKeepClearAlgorithm;
private float mDefaultSizePercent;
private float mMinAspectRatioForMinSize;
@@ -60,9 +61,11 @@
protected Point mScreenEdgeInsets;
public PipBoundsAlgorithm(Context context, @NonNull PipBoundsState pipBoundsState,
- @NonNull PipSnapAlgorithm pipSnapAlgorithm) {
+ @NonNull PipSnapAlgorithm pipSnapAlgorithm,
+ @NonNull PipKeepClearAlgorithm pipKeepClearAlgorithm) {
mPipBoundsState = pipBoundsState;
mSnapAlgorithm = pipSnapAlgorithm;
+ mPipKeepClearAlgorithm = pipKeepClearAlgorithm;
reloadResources(context);
// Initialize the aspect ratio to the default aspect ratio. Don't do this in reload
// resources as it would clobber mAspectRatio when entering PiP from fullscreen which
@@ -129,8 +132,21 @@
return getDefaultBounds(INVALID_SNAP_FRACTION, null /* size */);
}
- /** Returns the destination bounds to place the PIP window on entry. */
+ /**
+ * Returns the destination bounds to place the PIP window on entry.
+ * If there are any keep clear areas registered, the position will try to avoid occluding them.
+ */
public Rect getEntryDestinationBounds() {
+ Rect entryBounds = getEntryDestinationBoundsIgnoringKeepClearAreas();
+ Rect insets = new Rect();
+ getInsetBounds(insets);
+ return mPipKeepClearAlgorithm.findUnoccludedPosition(entryBounds,
+ mPipBoundsState.getRestrictedKeepClearAreas(),
+ mPipBoundsState.getUnrestrictedKeepClearAreas(), insets);
+ }
+
+ /** Returns the destination bounds to place the PIP window on entry. */
+ public Rect getEntryDestinationBoundsIgnoringKeepClearAreas() {
final PipBoundsState.PipReentryState reentryState = mPipBoundsState.getReentryState();
final Rect destinationBounds = reentryState != null
@@ -138,9 +154,10 @@
: getDefaultBounds();
final boolean useCurrentSize = reentryState != null && reentryState.getSize() != null;
- return transformBoundsToAspectRatioIfValid(destinationBounds,
+ Rect aspectRatioBounds = transformBoundsToAspectRatioIfValid(destinationBounds,
mPipBoundsState.getAspectRatio(), false /* useCurrentMinEdgeSize */,
useCurrentSize);
+ return aspectRatioBounds;
}
/** Returns the current bounds adjusted to the new aspect ratio, if valid. */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipKeepClearAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipKeepClearAlgorithm.java
new file mode 100644
index 0000000..e3495e1
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipKeepClearAlgorithm.java
@@ -0,0 +1,53 @@
+/*
+ * 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.wm.shell.pip;
+
+import android.graphics.Rect;
+
+import java.util.Set;
+
+/**
+ * Interface for interacting with keep clear algorithm used to move PiP window out of the way of
+ * keep clear areas.
+ */
+public interface PipKeepClearAlgorithm {
+
+ /**
+ * Adjust the position of picture in picture window based on the registered keep clear areas.
+ * @param pipBoundsState state of the PiP to use for the calculations
+ * @param pipBoundsAlgorithm algorithm implementation used to get the entry destination bounds
+ * @return
+ */
+ default Rect adjust(PipBoundsState pipBoundsState, PipBoundsAlgorithm pipBoundsAlgorithm) {
+ return pipBoundsState.getBounds();
+ }
+
+ /**
+ * Calculate the bounds so that none of the keep clear areas are occluded, while the bounds stay
+ * within the allowed bounds. If such position is not feasible, return original bounds.
+ * @param defaultBounds initial bounds used in the calculation
+ * @param restrictedKeepClearAreas registered restricted keep clear areas
+ * @param unrestrictedKeepClearAreas registered unrestricted keep clear areas
+ * @param allowedBounds bounds that define the allowed space for the output, result will always
+ * be inside those bounds
+ * @return bounds that don't cover any of the keep clear areas and are within allowed bounds
+ */
+ default Rect findUnoccludedPosition(Rect defaultBounds, Set<Rect> restrictedKeepClearAreas,
+ Set<Rect> unrestrictedKeepClearAreas, Rect allowedBounds) {
+ return defaultBounds;
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index b46eff6..f170e77 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -966,7 +966,7 @@
// Re-set the PIP bounds to none.
mPipBoundsState.setBounds(new Rect());
mPipUiEventLoggerLogger.setTaskInfo(null);
- mMainExecutor.executeDelayed(() -> mPipMenuController.detach(), 0);
+ mPipMenuController.detach();
mLeash = null;
if (info.displayId != Display.DEFAULT_DISPLAY && mOnDisplayIdChangeCallback != null) {
@@ -1306,6 +1306,12 @@
return;
}
+ if (mLeash == null || !mLeash.isValid()) {
+ Log.e(TAG, String.format("scheduleFinishResizePip with null leash! mState=%d",
+ mPipTransitionState.getTransitionState()));
+ return;
+ }
+
finishResize(createFinishResizeSurfaceTransaction(destinationBounds), destinationBounds,
direction, -1);
if (updateBoundsCallback != null) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionState.java
index 1a4be3b..c6b5ce9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionState.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionState.java
@@ -88,6 +88,11 @@
return isInPip(mState);
}
+ /** Returns true if activity has fully entered PiP mode. */
+ public boolean hasEnteredPip() {
+ return hasEnteredPip(mState);
+ }
+
public void setInSwipePipToHomeTransition(boolean inSwipePipToHomeTransition) {
mInSwipePipToHomeTransition = inSwipePipToHomeTransition;
}
@@ -120,6 +125,11 @@
return state >= TASK_APPEARED && state != EXITING_PIP;
}
+ /** Returns true if activity has fully entered PiP mode. */
+ public static boolean hasEnteredPip(@TransitionState int state) {
+ return state == ENTERED_PIP;
+ }
+
public interface OnPipTransitionStateChangedListener {
void onPipTransitionStateChanged(@TransitionState int oldState,
@TransitionState int newState);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipKeepClearAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipKeepClearAlgorithm.java
new file mode 100644
index 0000000..6dd02e4
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipKeepClearAlgorithm.java
@@ -0,0 +1,147 @@
+/*
+ * 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.wm.shell.pip.phone;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Rect;
+import android.util.ArraySet;
+import android.view.Gravity;
+
+import com.android.wm.shell.R;
+import com.android.wm.shell.pip.PipBoundsAlgorithm;
+import com.android.wm.shell.pip.PipBoundsState;
+import com.android.wm.shell.pip.PipKeepClearAlgorithm;
+
+import java.util.Set;
+
+/**
+ * Calculates the adjusted position that does not occlude keep clear areas.
+ */
+public class PhonePipKeepClearAlgorithm implements PipKeepClearAlgorithm {
+
+ protected int mKeepClearAreasPadding;
+
+ public PhonePipKeepClearAlgorithm(Context context) {
+ reloadResources(context);
+ }
+
+ private void reloadResources(Context context) {
+ final Resources res = context.getResources();
+ mKeepClearAreasPadding = res.getDimensionPixelSize(R.dimen.pip_keep_clear_areas_padding);
+ }
+
+ /**
+ * Adjusts the current position of PiP to avoid occluding keep clear areas. This will push PiP
+ * towards the closest edge and then apply calculations to avoid occluding keep clear areas.
+ */
+ public Rect adjust(PipBoundsState pipBoundsState, PipBoundsAlgorithm pipBoundsAlgorithm) {
+ Rect startingBounds = pipBoundsState.getBounds().isEmpty()
+ ? pipBoundsAlgorithm.getEntryDestinationBoundsIgnoringKeepClearAreas()
+ : pipBoundsState.getBounds();
+ float snapFraction = pipBoundsAlgorithm.getSnapFraction(startingBounds);
+ int verticalGravity;
+ int horizontalGravity;
+ if (snapFraction < 1.5f || snapFraction >= 3.5f) {
+ verticalGravity = Gravity.NO_GRAVITY;
+ } else {
+ verticalGravity = Gravity.BOTTOM;
+ }
+ if (snapFraction >= 0.5f && snapFraction < 2.5f) {
+ horizontalGravity = Gravity.RIGHT;
+ } else {
+ horizontalGravity = Gravity.LEFT;
+ }
+ // push the bounds based on the gravity
+ Rect insets = new Rect();
+ pipBoundsAlgorithm.getInsetBounds(insets);
+ if (pipBoundsState.isImeShowing()) {
+ insets.bottom -= pipBoundsState.getImeHeight();
+ }
+ Rect pushedBounds = new Rect(startingBounds);
+ if (verticalGravity == Gravity.BOTTOM) {
+ pushedBounds.offsetTo(pushedBounds.left,
+ insets.bottom - pushedBounds.height());
+ }
+ if (horizontalGravity == Gravity.RIGHT) {
+ pushedBounds.offsetTo(insets.right - pushedBounds.width(), pushedBounds.top);
+ } else {
+ pushedBounds.offsetTo(insets.left, pushedBounds.top);
+ }
+ return findUnoccludedPosition(pushedBounds, pipBoundsState.getRestrictedKeepClearAreas(),
+ pipBoundsState.getUnrestrictedKeepClearAreas(), insets);
+ }
+
+ /** Returns a new {@code Rect} that does not occlude the provided keep clear areas. */
+ public Rect findUnoccludedPosition(Rect defaultBounds, Set<Rect> restrictedKeepClearAreas,
+ Set<Rect> unrestrictedKeepClearAreas, Rect allowedBounds) {
+ if (restrictedKeepClearAreas.isEmpty() && unrestrictedKeepClearAreas.isEmpty()) {
+ return defaultBounds;
+ }
+ Set<Rect> keepClearAreas = new ArraySet<>();
+ if (!restrictedKeepClearAreas.isEmpty()) {
+ keepClearAreas.addAll(restrictedKeepClearAreas);
+ }
+ if (!unrestrictedKeepClearAreas.isEmpty()) {
+ keepClearAreas.addAll(unrestrictedKeepClearAreas);
+ }
+ Rect outBounds = new Rect(defaultBounds);
+ for (Rect r : keepClearAreas) {
+ Rect tmpRect = new Rect(r);
+ // add extra padding to the keep clear area
+ tmpRect.inset(-mKeepClearAreasPadding, -mKeepClearAreasPadding);
+ if (Rect.intersects(r, outBounds)) {
+ if (tryOffsetUp(outBounds, tmpRect, allowedBounds)) continue;
+ if (tryOffsetLeft(outBounds, tmpRect, allowedBounds)) continue;
+ if (tryOffsetDown(outBounds, tmpRect, allowedBounds)) continue;
+ if (tryOffsetRight(outBounds, tmpRect, allowedBounds)) continue;
+ }
+ }
+ return outBounds;
+ }
+
+ private static boolean tryOffsetLeft(Rect rectToMove, Rect rectToAvoid, Rect allowedBounds) {
+ return tryOffset(rectToMove, rectToAvoid, allowedBounds,
+ rectToAvoid.left - rectToMove.right, 0);
+ }
+
+ private static boolean tryOffsetRight(Rect rectToMove, Rect rectToAvoid, Rect allowedBounds) {
+ return tryOffset(rectToMove, rectToAvoid, allowedBounds,
+ rectToAvoid.right - rectToMove.left, 0);
+ }
+
+ private static boolean tryOffsetUp(Rect rectToMove, Rect rectToAvoid, Rect allowedBounds) {
+ return tryOffset(rectToMove, rectToAvoid, allowedBounds,
+ 0, rectToAvoid.top - rectToMove.bottom);
+ }
+
+ private static boolean tryOffsetDown(Rect rectToMove, Rect rectToAvoid, Rect allowedBounds) {
+ return tryOffset(rectToMove, rectToAvoid, allowedBounds,
+ 0, rectToAvoid.bottom - rectToMove.top);
+ }
+
+ private static boolean tryOffset(Rect rectToMove, Rect rectToAvoid, Rect allowedBounds,
+ int dx, int dy) {
+ Rect tmp = new Rect(rectToMove);
+ tmp.offset(dx, dy);
+ if (!Rect.intersects(rectToAvoid, tmp) && allowedBounds.contains(tmp)) {
+ rectToMove.offsetTo(tmp.left, tmp.top);
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
index ac3407d..3d879b6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
@@ -43,11 +43,13 @@
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.RemoteException;
+import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.Pair;
import android.util.Size;
import android.view.DisplayInfo;
+import android.view.InsetsState;
import android.view.SurfaceControl;
import android.view.WindowManagerGlobal;
import android.window.WindowContainerTransaction;
@@ -63,6 +65,7 @@
import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.common.DisplayChangeController;
import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.DisplayInsetsController;
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.RemoteCallable;
import com.android.wm.shell.common.ShellExecutor;
@@ -79,6 +82,7 @@
import com.android.wm.shell.pip.PipAppOpsListener;
import com.android.wm.shell.pip.PipBoundsAlgorithm;
import com.android.wm.shell.pip.PipBoundsState;
+import com.android.wm.shell.pip.PipKeepClearAlgorithm;
import com.android.wm.shell.pip.PipMediaController;
import com.android.wm.shell.pip.PipParamsChangedForwarder;
import com.android.wm.shell.pip.PipSnapAlgorithm;
@@ -110,6 +114,17 @@
UserChangeListener {
private static final String TAG = "PipController";
+ private static final long PIP_KEEP_CLEAR_AREAS_DELAY =
+ SystemProperties.getLong("persist.wm.debug.pip_keep_clear_areas_delay", 200);
+
+ private boolean mEnablePipKeepClearAlgorithm =
+ SystemProperties.getBoolean("persist.wm.debug.enable_pip_keep_clear_algorithm", false);
+
+ @VisibleForTesting
+ void setEnablePipKeepClearAlgorithm(boolean value) {
+ mEnablePipKeepClearAlgorithm = value;
+ }
+
private Context mContext;
protected ShellExecutor mMainExecutor;
private DisplayController mDisplayController;
@@ -125,6 +140,7 @@
private PipTransitionController mPipTransitionController;
private TaskStackListenerImpl mTaskStackListener;
private PipParamsChangedForwarder mPipParamsChangedForwarder;
+ private DisplayInsetsController mDisplayInsetsController;
private Optional<OneHandedController> mOneHandedController;
private final ShellCommandHandler mShellCommandHandler;
private final ShellController mShellController;
@@ -133,6 +149,8 @@
private final Rect mTmpInsetBounds = new Rect();
private final int mEnterAnimationDuration;
+ private final Runnable mMovePipInResponseToKeepClearAreasChangeCallback;
+
private boolean mIsInFixedRotation;
private PipAnimationListener mPinnedStackAnimationRecentsCallback;
@@ -262,7 +280,15 @@
public void onKeepClearAreasChanged(int displayId, Set<Rect> restricted,
Set<Rect> unrestricted) {
if (mPipBoundsState.getDisplayId() == displayId) {
- mPipBoundsState.setKeepClearAreas(restricted, unrestricted);
+ if (mEnablePipKeepClearAlgorithm) {
+ mPipBoundsState.setKeepClearAreas(restricted, unrestricted);
+
+ mMainExecutor.removeCallbacks(
+ mMovePipInResponseToKeepClearAreasChangeCallback);
+ mMainExecutor.executeDelayed(
+ mMovePipInResponseToKeepClearAreasChangeCallback,
+ PIP_KEEP_CLEAR_AREAS_DELAY);
+ }
}
}
};
@@ -318,6 +344,7 @@
WindowManagerShellWrapper windowManagerShellWrapper,
TaskStackListenerImpl taskStackListener,
PipParamsChangedForwarder pipParamsChangedForwarder,
+ DisplayInsetsController displayInsetsController,
Optional<OneHandedController> oneHandedController,
ShellExecutor mainExecutor) {
if (!context.getPackageManager().hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)) {
@@ -331,7 +358,7 @@
pipBoundsState, pipMotionHelper, pipMediaController, phonePipMenuController,
pipTaskOrganizer, pipTransitionState, pipTouchHandler, pipTransitionController,
windowManagerShellWrapper, taskStackListener, pipParamsChangedForwarder,
- oneHandedController, mainExecutor)
+ displayInsetsController, oneHandedController, mainExecutor)
.mImpl;
}
@@ -354,6 +381,7 @@
WindowManagerShellWrapper windowManagerShellWrapper,
TaskStackListenerImpl taskStackListener,
PipParamsChangedForwarder pipParamsChangedForwarder,
+ DisplayInsetsController displayInsetsController,
Optional<OneHandedController> oneHandedController,
ShellExecutor mainExecutor
) {
@@ -386,7 +414,17 @@
mEnterAnimationDuration = mContext.getResources()
.getInteger(R.integer.config_pipEnterAnimationDuration);
+ mMovePipInResponseToKeepClearAreasChangeCallback = () -> {
+ // only move if already in pip, other transitions account for keep clear areas
+ if (mPipTransitionState.hasEnteredPip()) {
+ Rect destBounds = mPipKeepClearAlgorithm.adjust(mPipBoundsState,
+ mPipBoundsAlgorithm);
+ mPipTaskOrganizer.scheduleAnimateResizePip(destBounds,
+ mEnterAnimationDuration, null);
+ }
+ };
mPipParamsChangedForwarder = pipParamsChangedForwarder;
+ mDisplayInsetsController = displayInsetsController;
shellInit.addInitCallback(this::onInit, this);
}
@@ -529,6 +567,16 @@
}
});
+ mDisplayInsetsController.addInsetsChangedListener(mPipBoundsState.getDisplayId(),
+ new DisplayInsetsController.OnInsetsChangedListener() {
+ @Override
+ public void insetsChanged(InsetsState insetsState) {
+ onDisplayChanged(
+ mDisplayController.getDisplayLayout(mPipBoundsState.getDisplayId()),
+ false /* saveRestoreSnapFraction */);
+ }
+ });
+
mOneHandedController.ifPresent(controller -> {
controller.registerTransitionCallback(
new OneHandedTransitionCallback() {
@@ -759,8 +807,16 @@
private Rect startSwipePipToHome(ComponentName componentName, ActivityInfo activityInfo,
PictureInPictureParams pictureInPictureParams,
- int launcherRotation, int shelfHeight) {
- setShelfHeightLocked(shelfHeight > 0 /* visible */, shelfHeight);
+ int launcherRotation, Rect hotseatKeepClearArea) {
+
+ if (mEnablePipKeepClearAlgorithm) {
+ // pre-emptively add the keep clear area for Hotseat, so that it is taken into account
+ // when calculating the entry destination bounds of PiP window
+ mPipBoundsState.getRestrictedKeepClearAreas().add(hotseatKeepClearArea);
+ } else {
+ int shelfHeight = hotseatKeepClearArea.height();
+ setShelfHeightLocked(shelfHeight > 0 /* visible */, shelfHeight);
+ }
onDisplayRotationChangedNotInPip(mContext, launcherRotation);
final Rect entryBounds = mPipTaskOrganizer.startSwipePipToHome(componentName, activityInfo,
pictureInPictureParams);
@@ -1059,12 +1115,12 @@
@Override
public Rect startSwipePipToHome(ComponentName componentName, ActivityInfo activityInfo,
PictureInPictureParams pictureInPictureParams, int launcherRotation,
- int shelfHeight) {
+ Rect keepClearArea) {
Rect[] result = new Rect[1];
executeRemoteCallWithTaskPermission(mController, "startSwipePipToHome",
(controller) -> {
result[0] = controller.startSwipePipToHome(componentName, activityInfo,
- pictureInPictureParams, launcherRotation, shelfHeight);
+ pictureInPictureParams, launcherRotation, keepClearArea);
}, true /* blocking */);
return result[0];
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDoubleTapHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDoubleTapHelper.java
new file mode 100644
index 0000000..acc0caf
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDoubleTapHelper.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.pip.phone;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.graphics.Rect;
+
+import com.android.wm.shell.pip.PipBoundsState;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Static utilities to get appropriate {@link PipDoubleTapHelper.PipSizeSpec} on a double tap.
+ */
+public class PipDoubleTapHelper {
+
+ /**
+ * Should not be instantiated as a stateless class.
+ */
+ private PipDoubleTapHelper() {}
+
+ /**
+ * A constant that represents a pip screen size.
+ *
+ * <p>CUSTOM - user resized screen size (by pinching in/out)</p>
+ * <p>DEFAULT - normal screen size used as default when entering pip mode</p>
+ * <p>MAX - maximum allowed screen size</p>
+ */
+ @IntDef(value = {
+ SIZE_SPEC_CUSTOM,
+ SIZE_SPEC_DEFAULT,
+ SIZE_SPEC_MAX
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface PipSizeSpec {}
+
+ static final int SIZE_SPEC_CUSTOM = 2;
+ static final int SIZE_SPEC_DEFAULT = 0;
+ static final int SIZE_SPEC_MAX = 1;
+
+ /**
+ * Returns MAX or DEFAULT {@link PipSizeSpec} to toggle to/from.
+ *
+ * <p>Each double tap toggles back and forth between {@code PipSizeSpec.CUSTOM} and
+ * either {@code PipSizeSpec.MAX} or {@code PipSizeSpec.DEFAULT}. The choice between
+ * the latter two sizes is determined based on the current state of the pip screen.</p>
+ *
+ * @param mPipBoundsState current state of the pip screen
+ */
+ @PipSizeSpec
+ private static int getMaxOrDefaultPipSizeSpec(@NonNull PipBoundsState mPipBoundsState) {
+ // determine the average pip screen width
+ int averageWidth = (mPipBoundsState.getMaxSize().x
+ + mPipBoundsState.getMinSize().x) / 2;
+
+ // If pip screen width is above average, DEFAULT is the size spec we need to
+ // toggle to. Otherwise, we choose MAX.
+ return (mPipBoundsState.getBounds().width() > averageWidth)
+ ? SIZE_SPEC_DEFAULT
+ : SIZE_SPEC_MAX;
+ }
+
+ /**
+ * Determines the {@link PipSizeSpec} to toggle to on double tap.
+ *
+ * @param mPipBoundsState current state of the pip screen
+ * @param userResizeBounds latest user resized bounds (by pinching in/out)
+ * @return pip screen size to switch to
+ */
+ @PipSizeSpec
+ static int nextSizeSpec(@NonNull PipBoundsState mPipBoundsState,
+ @NonNull Rect userResizeBounds) {
+ // is pip screen at its maximum
+ boolean isScreenMax = mPipBoundsState.getBounds().width()
+ == mPipBoundsState.getMaxSize().x;
+
+ // is pip screen at its normal default size
+ boolean isScreenDefault = (mPipBoundsState.getBounds().width()
+ == mPipBoundsState.getNormalBounds().width())
+ && (mPipBoundsState.getBounds().height()
+ == mPipBoundsState.getNormalBounds().height());
+
+ // edge case 1
+ // if user hasn't resized screen yet, i.e. CUSTOM size does not exist yet
+ // or if user has resized exactly to DEFAULT, then we just want to maximize
+ if (isScreenDefault
+ && userResizeBounds.width() == mPipBoundsState.getNormalBounds().width()) {
+ return SIZE_SPEC_MAX;
+ }
+
+ // edge case 2
+ // if user has maximized, then we want to toggle to DEFAULT
+ if (isScreenMax
+ && userResizeBounds.width() == mPipBoundsState.getMaxSize().x) {
+ return SIZE_SPEC_DEFAULT;
+ }
+
+ // otherwise in general we want to toggle back to user's CUSTOM size
+ if (isScreenDefault || isScreenMax) {
+ return SIZE_SPEC_CUSTOM;
+ }
+
+ // if we are currently in user resized CUSTOM size state
+ // then we toggle either to MAX or DEFAULT depending on the current pip screen state
+ return getMaxOrDefaultPipSizeSpec(mPipBoundsState);
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipKeepClearAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipKeepClearAlgorithm.java
deleted file mode 100644
index 78084fa..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipKeepClearAlgorithm.java
+++ /dev/null
@@ -1,97 +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.wm.shell.pip.phone;
-
-import android.graphics.Rect;
-import android.util.ArraySet;
-
-import com.android.wm.shell.pip.PipBoundsAlgorithm;
-import com.android.wm.shell.pip.PipBoundsState;
-
-import java.util.Set;
-
-/**
- * Calculates the adjusted position that does not occlude keep clear areas.
- */
-public class PipKeepClearAlgorithm {
-
- /**
- * Adjusts the current position of PiP to avoid occluding keep clear areas. If the user has
- * moved PiP manually, the unmodified current position will be returned instead.
- */
- public Rect adjust(PipBoundsState boundsState, PipBoundsAlgorithm boundsAlgorithm) {
- if (boundsState.hasUserResizedPip()) {
- return boundsState.getBounds();
- }
- return adjust(boundsAlgorithm.getEntryDestinationBounds(),
- boundsState.getRestrictedKeepClearAreas(),
- boundsState.getUnrestrictedKeepClearAreas(), boundsState.getDisplayBounds());
- }
-
- /** Returns a new {@code Rect} that does not occlude the provided keep clear areas. */
- public Rect adjust(Rect defaultBounds, Set<Rect> restrictedKeepClearAreas,
- Set<Rect> unrestrictedKeepClearAreas, Rect displayBounds) {
- if (restrictedKeepClearAreas.isEmpty()) {
- return defaultBounds;
- }
- Set<Rect> keepClearAreas = new ArraySet<>();
- if (!restrictedKeepClearAreas.isEmpty()) {
- keepClearAreas.addAll(restrictedKeepClearAreas);
- }
- Rect outBounds = new Rect(defaultBounds);
- for (Rect r : keepClearAreas) {
- if (Rect.intersects(r, outBounds)) {
- if (tryOffsetUp(outBounds, r, displayBounds)) continue;
- if (tryOffsetLeft(outBounds, r, displayBounds)) continue;
- if (tryOffsetDown(outBounds, r, displayBounds)) continue;
- if (tryOffsetRight(outBounds, r, displayBounds)) continue;
- }
- }
- return outBounds;
- }
-
- private boolean tryOffsetLeft(Rect rectToMove, Rect rectToAvoid, Rect displayBounds) {
- return tryOffset(rectToMove, rectToAvoid, displayBounds,
- rectToAvoid.left - rectToMove.right, 0);
- }
-
- private boolean tryOffsetRight(Rect rectToMove, Rect rectToAvoid, Rect displayBounds) {
- return tryOffset(rectToMove, rectToAvoid, displayBounds,
- rectToAvoid.right - rectToMove.left, 0);
- }
-
- private boolean tryOffsetUp(Rect rectToMove, Rect rectToAvoid, Rect displayBounds) {
- return tryOffset(rectToMove, rectToAvoid, displayBounds,
- 0, rectToAvoid.top - rectToMove.bottom);
- }
-
- private boolean tryOffsetDown(Rect rectToMove, Rect rectToAvoid, Rect displayBounds) {
- return tryOffset(rectToMove, rectToAvoid, displayBounds,
- 0, rectToAvoid.bottom - rectToMove.top);
- }
-
- private boolean tryOffset(Rect rectToMove, Rect rectToAvoid, Rect displayBounds,
- int dx, int dy) {
- Rect tmp = new Rect(rectToMove);
- tmp.offset(dx, dy);
- if (!Rect.intersects(rectToAvoid, tmp) && displayBounds.contains(tmp)) {
- rectToMove.offsetTo(tmp.left, tmp.top);
- return true;
- }
- return false;
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
index 1958157..979b7c7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
@@ -207,6 +207,9 @@
}
});
+ // this disables the ripples
+ mEnterSplitButton.setEnabled(false);
+
findViewById(R.id.resize_handle).setAlpha(0);
mActionsGroup = findViewById(R.id.actions_group);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
index a2fa058..84d9217 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
@@ -929,9 +929,18 @@
if (mMenuController.isMenuVisible()) {
mMenuController.hideMenu(ANIM_TYPE_NONE, false /* resize */);
}
- if (toExpand) {
+
+ // the size to toggle to after a double tap
+ int nextSize = PipDoubleTapHelper
+ .nextSizeSpec(mPipBoundsState, getUserResizeBounds());
+
+ // actually toggle to the size chosen
+ if (nextSize == PipDoubleTapHelper.SIZE_SPEC_MAX) {
mPipResizeGestureHandler.setUserResizeBounds(mPipBoundsState.getBounds());
animateToMaximizedState(null);
+ } else if (nextSize == PipDoubleTapHelper.SIZE_SPEC_DEFAULT) {
+ mPipResizeGestureHandler.setUserResizeBounds(mPipBoundsState.getBounds());
+ animateToNormalSize(null);
} else {
animateToUnexpandedState(getUserResizeBounds());
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsAlgorithm.java
index a2eadcd..ce34d2f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsAlgorithm.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsAlgorithm.java
@@ -39,6 +39,7 @@
import com.android.wm.shell.R;
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.pip.PipBoundsAlgorithm;
+import com.android.wm.shell.pip.PipKeepClearAlgorithm;
import com.android.wm.shell.pip.PipSnapAlgorithm;
import com.android.wm.shell.pip.tv.TvPipKeepClearAlgorithm.Placement;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
@@ -63,7 +64,8 @@
public TvPipBoundsAlgorithm(Context context,
@NonNull TvPipBoundsState tvPipBoundsState,
@NonNull PipSnapAlgorithm pipSnapAlgorithm) {
- super(context, tvPipBoundsState, pipSnapAlgorithm);
+ super(context, tvPipBoundsState, pipSnapAlgorithm,
+ new PipKeepClearAlgorithm() {});
this.mTvPipBoundsState = tvPipBoundsState;
this.mKeepClearAlgorithm = new TvPipKeepClearAlgorithm();
reloadResources(context);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java
index 93c7529..3fef823 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java
@@ -32,7 +32,7 @@
Consts.TAG_WM_SHELL),
WM_SHELL_TRANSITIONS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, true,
Consts.TAG_WM_SHELL),
- WM_SHELL_DRAG_AND_DROP(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
+ WM_SHELL_DRAG_AND_DROP(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, true,
Consts.TAG_WM_SHELL),
WM_SHELL_STARTING_WINDOW(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
Consts.TAG_WM_STARTING_WINDOW),
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
index 7b42350..27bc1a1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
@@ -43,6 +43,7 @@
import com.android.wm.shell.common.TaskStackListenerImpl;
import com.android.wm.shell.common.annotations.ExternalThread;
import com.android.wm.shell.common.annotations.ShellMainThread;
+import com.android.wm.shell.desktopmode.DesktopMode;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.sysui.ShellCommandHandler;
import com.android.wm.shell.sysui.ShellInit;
@@ -52,6 +53,7 @@
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
@@ -82,6 +84,15 @@
private final Map<Integer, SplitBounds> mTaskSplitBoundsMap = new HashMap<>();
/**
+ * Set of taskId's that have been launched in freeform mode.
+ * This includes tasks that are currently running, visible and in freeform mode. And also
+ * includes tasks that are running in the background, are no longer visible, but at some point
+ * were visible to the user.
+ * This is used to decide which freeform apps belong to the user's desktop.
+ */
+ private final HashSet<Integer> mActiveFreeformTasks = new HashSet<>();
+
+ /**
* Creates {@link RecentTasksController}, returns {@code null} if the feature is not
* supported.
*/
@@ -206,6 +217,22 @@
notifyRecentTasksChanged();
}
+ /**
+ * Mark a task with given {@code taskId} as active in freeform
+ */
+ public void addActiveFreeformTask(int taskId) {
+ mActiveFreeformTasks.add(taskId);
+ notifyRecentTasksChanged();
+ }
+
+ /**
+ * Remove task with given {@code taskId} from active freeform tasks
+ */
+ public void removeActiveFreeformTask(int taskId) {
+ mActiveFreeformTasks.remove(taskId);
+ notifyRecentTasksChanged();
+ }
+
@VisibleForTesting
void notifyRecentTasksChanged() {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENT_TASKS, "Notify recent tasks changed");
@@ -273,6 +300,9 @@
rawMapping.put(taskInfo.taskId, taskInfo);
}
+ boolean desktopModeActive = DesktopMode.isActive(mContext);
+ ArrayList<ActivityManager.RecentTaskInfo> freeformTasks = new ArrayList<>();
+
// Pull out the pairs as we iterate back in the list
ArrayList<GroupedRecentTaskInfo> recentTasks = new ArrayList<>();
for (int i = 0; i < rawList.size(); i++) {
@@ -282,16 +312,31 @@
continue;
}
+ if (desktopModeActive && mActiveFreeformTasks.contains(taskInfo.taskId)) {
+ // Freeform tasks will be added as a separate entry
+ freeformTasks.add(taskInfo);
+ continue;
+ }
+
final int pairedTaskId = mSplitTasks.get(taskInfo.taskId);
- if (pairedTaskId != INVALID_TASK_ID && rawMapping.contains(pairedTaskId)) {
+ if (!desktopModeActive && pairedTaskId != INVALID_TASK_ID && rawMapping.contains(
+ pairedTaskId)) {
final ActivityManager.RecentTaskInfo pairedTaskInfo = rawMapping.get(pairedTaskId);
rawMapping.remove(pairedTaskId);
- recentTasks.add(new GroupedRecentTaskInfo(taskInfo, pairedTaskInfo,
+ recentTasks.add(GroupedRecentTaskInfo.forSplitTasks(taskInfo, pairedTaskInfo,
mTaskSplitBoundsMap.get(pairedTaskId)));
} else {
- recentTasks.add(new GroupedRecentTaskInfo(taskInfo));
+ recentTasks.add(GroupedRecentTaskInfo.forSingleTask(taskInfo));
}
}
+
+ // Add a special entry for freeform tasks
+ if (!freeformTasks.isEmpty()) {
+ // First task is added separately
+ recentTasks.add(0, GroupedRecentTaskInfo.forFreeformTasks(
+ freeformTasks.toArray(new ActivityManager.RecentTaskInfo[0])));
+ }
+
return recentTasks;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl
index 51921e7..3714fe7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl
@@ -18,6 +18,7 @@
import android.app.PendingIntent;
import android.content.Intent;
+import android.content.pm.ShortcutInfo;
import android.os.Bundle;
import android.os.UserHandle;
import android.view.RemoteAnimationAdapter;
@@ -89,7 +90,7 @@
float splitRatio, in RemoteAnimationAdapter adapter) = 11;
/**
- * Start a pair of intent and task using legacy transition system.
+ * Starts a pair of intent and task using legacy transition system.
*/
oneway void startIntentAndTaskWithLegacyTransition(in PendingIntent pendingIntent,
in Intent fillInIntent, int taskId, in Bundle mainOptions,in Bundle sideOptions,
@@ -108,4 +109,11 @@
* does not expect split to currently be running.
*/
RemoteAnimationTarget[] onStartingSplitLegacy(in RemoteAnimationTarget[] appTargets) = 14;
+
+ /**
+ * Starts a pair of shortcut and task using legacy transition system.
+ */
+ oneway void startShortcutAndTaskWithLegacyTransition(in ShortcutInfo shortcutInfo, int taskId,
+ in Bundle mainOptions, in Bundle sideOptions, int sidePosition, float splitRatio,
+ in RemoteAnimationAdapter adapter) = 15;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index 2117b69..9206afb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -40,6 +40,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.pm.LauncherApps;
+import android.content.pm.ShortcutInfo;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.RemoteException;
@@ -146,7 +147,6 @@
private final DragAndDropController mDragAndDropController;
private final Transitions mTransitions;
private final TransactionPool mTransactionPool;
- private final SplitscreenEventLogger mLogger;
private final IconProvider mIconProvider;
private final Optional<RecentTasksController> mRecentTasksOptional;
private final SplitScreenShellCommandHandler mSplitScreenShellCommandHandler;
@@ -185,7 +185,6 @@
mDragAndDropController = dragAndDropController;
mTransitions = transitions;
mTransactionPool = transactionPool;
- mLogger = new SplitscreenEventLogger();
mIconProvider = iconProvider;
mRecentTasksOptional = recentTasks;
mSplitScreenShellCommandHandler = new SplitScreenShellCommandHandler(this);
@@ -212,14 +211,18 @@
mShellController.addKeyguardChangeListener(this);
if (mStageCoordinator == null) {
// TODO: Multi-display
- mStageCoordinator = new StageCoordinator(mContext, DEFAULT_DISPLAY, mSyncQueue,
- mTaskOrganizer, mDisplayController, mDisplayImeController,
- mDisplayInsetsController, mTransitions, mTransactionPool, mLogger,
- mIconProvider, mMainExecutor, mRecentTasksOptional);
+ mStageCoordinator = createStageCoordinator();
}
mDragAndDropController.setSplitScreenController(this);
}
+ protected StageCoordinator createStageCoordinator() {
+ return new StageCoordinator(mContext, DEFAULT_DISPLAY, mSyncQueue,
+ mTaskOrganizer, mDisplayController, mDisplayImeController,
+ mDisplayInsetsController, mTransitions, mTransactionPool,
+ mIconProvider, mMainExecutor, mRecentTasksOptional);
+ }
+
@Override
public Context getContext() {
return mContext;
@@ -788,6 +791,17 @@
}
@Override
+ public void startShortcutAndTaskWithLegacyTransition(ShortcutInfo shortcutInfo,
+ int taskId, @Nullable Bundle mainOptions, @Nullable Bundle sideOptions,
+ @SplitPosition int sidePosition, float splitRatio, RemoteAnimationAdapter adapter) {
+ executeRemoteCallWithTaskPermission(mController,
+ "startShortcutAndTaskWithLegacyTransition", (controller) ->
+ controller.mStageCoordinator.startShortcutAndTaskWithLegacyTransition(
+ shortcutInfo, taskId, mainOptions, sideOptions, sidePosition,
+ splitRatio, adapter));
+ }
+
+ @Override
public void startTasks(int mainTaskId, @Nullable Bundle mainOptions,
int sideTaskId, @Nullable Bundle sideOptions,
@SplitPosition int sidePosition, float splitRatio,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index c08aa5a..8ed16ce 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -69,11 +69,12 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
-import android.app.ActivityOptions;
+import android.app.IActivityTaskManager;
import android.app.PendingIntent;
import android.app.WindowConfiguration;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ShortcutInfo;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.hardware.devicestate.DeviceStateManager;
@@ -81,11 +82,11 @@
import android.os.Debug;
import android.os.IBinder;
import android.os.RemoteException;
+import android.os.ServiceManager;
import android.util.Log;
import android.util.Slog;
import android.view.Choreographer;
import android.view.IRemoteAnimationFinishedCallback;
-import android.view.IRemoteAnimationRunner;
import android.view.RemoteAnimationAdapter;
import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
@@ -245,18 +246,18 @@
}
};
- StageCoordinator(Context context, int displayId, SyncTransactionQueue syncQueue,
+ protected StageCoordinator(Context context, int displayId, SyncTransactionQueue syncQueue,
ShellTaskOrganizer taskOrganizer, DisplayController displayController,
DisplayImeController displayImeController,
DisplayInsetsController displayInsetsController, Transitions transitions,
- TransactionPool transactionPool, SplitscreenEventLogger logger,
+ TransactionPool transactionPool,
IconProvider iconProvider, ShellExecutor mainExecutor,
Optional<RecentTasksController> recentTasks) {
mContext = context;
mDisplayId = displayId;
mSyncQueue = syncQueue;
mTaskOrganizer = taskOrganizer;
- mLogger = logger;
+ mLogger = new SplitscreenEventLogger();
mMainExecutor = mainExecutor;
mRecentTasks = recentTasks;
@@ -300,7 +301,7 @@
DisplayController displayController, DisplayImeController displayImeController,
DisplayInsetsController displayInsetsController, SplitLayout splitLayout,
Transitions transitions, TransactionPool transactionPool,
- SplitscreenEventLogger logger, ShellExecutor mainExecutor,
+ ShellExecutor mainExecutor,
Optional<RecentTasksController> recentTasks) {
mContext = context;
mDisplayId = displayId;
@@ -315,7 +316,7 @@
mSplitLayout = splitLayout;
mSplitTransitions = new SplitScreenTransitions(transactionPool, transitions,
this::onTransitionAnimationComplete, this);
- mLogger = logger;
+ mLogger = new SplitscreenEventLogger();
mMainExecutor = mainExecutor;
mRecentTasks = recentTasks;
mDisplayController.addDisplayWindowListener(this);
@@ -531,133 +532,136 @@
void startTasksWithLegacyTransition(int mainTaskId, @Nullable Bundle mainOptions,
int sideTaskId, @Nullable Bundle sideOptions, @SplitPosition int sidePosition,
float splitRatio, RemoteAnimationAdapter adapter) {
- startWithLegacyTransition(mainTaskId, sideTaskId, null /* pendingIntent */,
- null /* fillInIntent */, mainOptions, sideOptions, sidePosition, splitRatio,
- adapter);
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+ if (sideOptions == null) sideOptions = new Bundle();
+ addActivityOptions(sideOptions, mSideStage);
+ wct.startTask(sideTaskId, sideOptions);
+
+ startWithLegacyTransition(wct, mainTaskId, mainOptions, sidePosition, splitRatio, adapter);
}
/** Start an intent and a task ordered by {@code intentFirst}. */
void startIntentAndTaskWithLegacyTransition(PendingIntent pendingIntent, Intent fillInIntent,
int taskId, @Nullable Bundle mainOptions, @Nullable Bundle sideOptions,
@SplitPosition int sidePosition, float splitRatio, RemoteAnimationAdapter adapter) {
- startWithLegacyTransition(taskId, INVALID_TASK_ID, pendingIntent, fillInIntent,
- mainOptions, sideOptions, sidePosition, splitRatio, adapter);
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+ if (sideOptions == null) sideOptions = new Bundle();
+ addActivityOptions(sideOptions, mSideStage);
+ wct.sendPendingIntent(pendingIntent, fillInIntent, sideOptions);
+
+ startWithLegacyTransition(wct, taskId, mainOptions, sidePosition, splitRatio, adapter);
}
- private void startWithLegacyTransition(int mainTaskId, int sideTaskId,
- @Nullable PendingIntent pendingIntent, @Nullable Intent fillInIntent,
- @Nullable Bundle mainOptions, @Nullable Bundle sideOptions,
+ void startShortcutAndTaskWithLegacyTransition(ShortcutInfo shortcutInfo,
+ int taskId, @Nullable Bundle mainOptions, @Nullable Bundle sideOptions,
@SplitPosition int sidePosition, float splitRatio, RemoteAnimationAdapter adapter) {
- final boolean withIntent = pendingIntent != null && fillInIntent != null;
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+ if (sideOptions == null) sideOptions = new Bundle();
+ addActivityOptions(sideOptions, mSideStage);
+ wct.startShortcut(mContext.getPackageName(), shortcutInfo, sideOptions);
+
+ startWithLegacyTransition(wct, taskId, mainOptions, sidePosition, splitRatio, adapter);
+ }
+
+ private void startWithLegacyTransition(WindowContainerTransaction sideWct, int mainTaskId,
+ @Nullable Bundle mainOptions, @SplitPosition int sidePosition, float splitRatio,
+ RemoteAnimationAdapter adapter) {
// Init divider first to make divider leash for remote animation target.
mSplitLayout.init();
+ mSplitLayout.setDivideRatio(splitRatio);
+
// Set false to avoid record new bounds with old task still on top;
mShouldUpdateRecents = false;
mIsDividerRemoteAnimating = true;
- final WindowContainerTransaction wct = new WindowContainerTransaction();
- final WindowContainerTransaction evictWct = new WindowContainerTransaction();
- prepareEvictChildTasks(SPLIT_POSITION_TOP_OR_LEFT, evictWct);
- prepareEvictChildTasks(SPLIT_POSITION_BOTTOM_OR_RIGHT, evictWct);
- // Need to add another wrapper here in shell so that we can inject the divider bar
- // and also manage the process elevation via setRunningRemote
- IRemoteAnimationRunner wrapper = new IRemoteAnimationRunner.Stub() {
+
+ LegacyTransitions.ILegacyTransition transition = new LegacyTransitions.ILegacyTransition() {
@Override
- public void onAnimationStart(@WindowManager.TransitionOldType int transit,
- RemoteAnimationTarget[] apps,
- RemoteAnimationTarget[] wallpapers,
- RemoteAnimationTarget[] nonApps,
- final IRemoteAnimationFinishedCallback finishedCallback) {
- RemoteAnimationTarget[] augmentedNonApps =
- new RemoteAnimationTarget[nonApps.length + 1];
- for (int i = 0; i < nonApps.length; ++i) {
- augmentedNonApps[i] = nonApps[i];
+ public void onAnimationStart(int transit, RemoteAnimationTarget[] apps,
+ RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps,
+ IRemoteAnimationFinishedCallback finishedCallback,
+ SurfaceControl.Transaction t) {
+ if (apps == null || apps.length == 0) {
+ updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */);
+ setDividerVisibility(true, t);
+ t.apply();
+ onRemoteAnimationFinished(apps);
+ try {
+ adapter.getRunner().onAnimationCancelled(mKeyguardShowing);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Error starting remote animation", e);
+ }
+ return;
}
- augmentedNonApps[augmentedNonApps.length - 1] = getDividerBarLegacyTarget();
+
+ // Wrap the divider bar into non-apps target to animate together.
+ nonApps = ArrayUtils.appendElement(RemoteAnimationTarget.class, nonApps,
+ getDividerBarLegacyTarget());
+
+ updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */);
+ setDividerVisibility(true, t);
+ for (int i = 0; i < apps.length; ++i) {
+ if (apps[i].mode == MODE_OPENING) {
+ t.show(apps[i].leash);
+ // Reset the surface position of the opening app to prevent double-offset.
+ t.setPosition(apps[i].leash, 0, 0);
+ }
+ }
+ t.apply();
IRemoteAnimationFinishedCallback wrapCallback =
new IRemoteAnimationFinishedCallback.Stub() {
@Override
public void onAnimationFinished() throws RemoteException {
- onRemoteAnimationFinishedOrCancelled(false /* cancel */, evictWct);
+ onRemoteAnimationFinished(apps);
finishedCallback.onAnimationFinished();
}
};
Transitions.setRunningRemoteTransitionDelegate(adapter.getCallingApplication());
try {
- adapter.getRunner().onAnimationStart(transit, apps, wallpapers,
- augmentedNonApps, wrapCallback);
- } catch (RemoteException e) {
- Slog.e(TAG, "Error starting remote animation", e);
- }
- }
-
- @Override
- public void onAnimationCancelled(boolean isKeyguardOccluded) {
- onRemoteAnimationFinishedOrCancelled(true /* cancel */, evictWct);
- try {
- adapter.getRunner().onAnimationCancelled(isKeyguardOccluded);
+ adapter.getRunner().onAnimationStart(
+ transit, apps, wallpapers, nonApps, wrapCallback);
} catch (RemoteException e) {
Slog.e(TAG, "Error starting remote animation", e);
}
}
};
- RemoteAnimationAdapter wrappedAdapter = new RemoteAnimationAdapter(
- wrapper, adapter.getDuration(), adapter.getStatusBarTransitionDelay());
- if (mainOptions == null) {
- mainOptions = ActivityOptions.makeRemoteAnimation(wrappedAdapter).toBundle();
- } else {
- ActivityOptions mainActivityOptions = ActivityOptions.fromBundle(mainOptions);
- mainActivityOptions.update(ActivityOptions.makeRemoteAnimation(wrappedAdapter));
- mainOptions = mainActivityOptions.toBundle();
- }
-
- sideOptions = sideOptions != null ? sideOptions : new Bundle();
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
setSideStagePosition(sidePosition, wct);
-
- mSplitLayout.setDivideRatio(splitRatio);
if (!mMainStage.isActive()) {
- // Build a request WCT that will launch both apps such that task 0 is on the main stage
- // while task 1 is on the side stage.
mMainStage.activate(wct, false /* reparent */);
}
+
+ if (mainOptions == null) mainOptions = new Bundle();
+ addActivityOptions(mainOptions, mMainStage);
+ wct.startTask(mainTaskId, mainOptions);
+ wct.merge(sideWct, true);
+
updateWindowBounds(mSplitLayout, wct);
wct.reorder(mRootTaskInfo.token, true);
wct.setForceTranslucent(mRootTaskInfo.token, false);
- // Make sure the launch options will put tasks in the corresponding split roots
- addActivityOptions(mainOptions, mMainStage);
- addActivityOptions(sideOptions, mSideStage);
-
- // Add task launch requests
- wct.startTask(mainTaskId, mainOptions);
- if (withIntent) {
- wct.sendPendingIntent(pendingIntent, fillInIntent, sideOptions);
- } else {
- wct.startTask(sideTaskId, sideOptions);
- }
-
- mSyncQueue.queue(wct);
- mSyncQueue.runInSync(t -> {
- setDividerVisibility(true, t);
- updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */);
- });
+ mSyncQueue.queue(transition, WindowManager.TRANSIT_OPEN, wct);
}
- private void onRemoteAnimationFinishedOrCancelled(boolean cancel,
- WindowContainerTransaction evictWct) {
+ private void onRemoteAnimationFinished(RemoteAnimationTarget[] apps) {
mIsDividerRemoteAnimating = false;
mShouldUpdateRecents = true;
- // If any stage has no child after animation finished, it means that split will display
- // nothing, such status will happen if task and intent is same app but not support
- // multi-instance, we should exit split and expand that app as full screen.
- if (!cancel && (mMainStage.getChildCount() == 0 || mSideStage.getChildCount() == 0)) {
- mMainExecutor.execute(() ->
- exitSplitScreen(mMainStage.getChildCount() == 0
- ? mSideStage : mMainStage, EXIT_REASON_UNKNOWN));
- } else {
- mSyncQueue.queue(evictWct);
+ if (apps == null || apps.length == 0) return;
+
+ // If any stage has no child after finished animation, that side of the split will display
+ // nothing. This might happen if starting the same app on the both sides while not
+ // supporting multi-instance. Exit the split screen and expand that app to full screen.
+ if (mMainStage.getChildCount() == 0 || mSideStage.getChildCount() == 0) {
+ mMainExecutor.execute(() -> exitSplitScreen(mMainStage.getChildCount() == 0
+ ? mSideStage : mMainStage, EXIT_REASON_UNKNOWN));
+ return;
}
+
+ final WindowContainerTransaction evictWct = new WindowContainerTransaction();
+ prepareEvictNonOpeningChildTasks(SPLIT_POSITION_TOP_OR_LEFT, apps, evictWct);
+ prepareEvictNonOpeningChildTasks(SPLIT_POSITION_BOTTOM_OR_RIGHT, apps, evictWct);
+ mSyncQueue.queue(evictWct);
}
/**
@@ -878,6 +882,8 @@
WindowContainerTransaction wct, @ExitReason int exitReason) {
if (!mMainStage.isActive() || mIsExiting) return;
+ onSplitScreenExit();
+
mRecentTasks.ifPresent(recentTasks -> {
// Notify recents if we are exiting in a way that breaks the pair, and disable further
// updates to splits in the recents until we enter split again
@@ -947,6 +953,47 @@
}
/**
+ * Overridden by child classes.
+ */
+ protected void onSplitScreenEnter() {
+ }
+
+ /**
+ * Overridden by child classes.
+ */
+ protected void onSplitScreenExit() {
+ }
+
+ /**
+ * Exits the split screen by finishing one of the tasks.
+ */
+ protected void exitStage(@SplitPosition int stageToClose) {
+ if (ENABLE_SHELL_TRANSITIONS) {
+ StageTaskListener stageToTop = mSideStagePosition == stageToClose
+ ? mMainStage
+ : mSideStage;
+ exitSplitScreen(stageToTop, EXIT_REASON_APP_FINISHED);
+ } else {
+ boolean toEnd = stageToClose == SPLIT_POSITION_BOTTOM_OR_RIGHT;
+ mSplitLayout.flingDividerToDismiss(toEnd, EXIT_REASON_APP_FINISHED);
+ }
+ }
+
+ /**
+ * Grants focus to the main or the side stages.
+ */
+ protected void grantFocusToStage(@SplitPosition int stageToFocus) {
+ IActivityTaskManager activityTaskManagerService = IActivityTaskManager.Stub.asInterface(
+ ServiceManager.getService(Context.ACTIVITY_TASK_SERVICE));
+ try {
+ activityTaskManagerService.setFocusedTask(getTaskId(stageToFocus));
+ } catch (RemoteException | NullPointerException e) {
+ ProtoLog.e(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
+ "%s: Unable to update focus on the chosen stage, %s", TAG, e);
+ }
+ }
+
+ /**
* Returns whether the split pair in the recent tasks list should be broken.
*/
private boolean shouldBreakPairedTaskInRecents(@ExitReason int exitReason) {
@@ -993,6 +1040,7 @@
@Nullable ActivityManager.RunningTaskInfo taskInfo, @SplitPosition int startPosition) {
if (mMainStage.isActive()) return;
+ onSplitScreenEnter();
if (taskInfo != null) {
setSideStagePosition(startPosition, wct);
mSideStage.addTask(taskInfo, wct);
@@ -1386,6 +1434,7 @@
}
} else if (isSideStage && hasChildren && !mMainStage.isActive()) {
// TODO (b/238697912) : Add the validation to prevent entering non-recovered status
+ onSplitScreenEnter();
final WindowContainerTransaction wct = new WindowContainerTransaction();
mSplitLayout.init();
mSplitLayout.setDividerAtBorder(mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT);
@@ -1838,7 +1887,6 @@
// properly for the animation itself.
mSplitLayout.release();
mSplitLayout.resetDividerPosition();
- mSideStagePosition = SPLIT_POSITION_BOTTOM_OR_RIGHT;
mTopStageAfterFoldDismiss = STAGE_TYPE_UNDEFINED;
}
}
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 e26c259..bcf4fbd 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
@@ -35,10 +35,14 @@
import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.pip.PipTransitionController;
+import com.android.wm.shell.pip.phone.PipTouchHandler;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
+import com.android.wm.shell.splitscreen.SplitScreenController;
import com.android.wm.shell.splitscreen.StageCoordinator;
+import com.android.wm.shell.sysui.ShellInit;
import java.util.ArrayList;
+import java.util.Optional;
/**
* A handler for dealing with transitions involving multiple other handlers. For example: an
@@ -47,8 +51,8 @@
public class DefaultMixedHandler implements Transitions.TransitionHandler {
private final Transitions mPlayer;
- private final PipTransitionController mPipHandler;
- private final StageCoordinator mSplitHandler;
+ private PipTransitionController mPipHandler;
+ private StageCoordinator mSplitHandler;
private static class MixedTransition {
static final int TYPE_ENTER_PIP_FROM_SPLIT = 1;
@@ -77,13 +81,22 @@
mTransition = transition;
}
}
+
private final ArrayList<MixedTransition> mActiveTransitions = new ArrayList<>();
- public DefaultMixedHandler(@NonNull Transitions player,
- @NonNull PipTransitionController pipHandler, @NonNull StageCoordinator splitHandler) {
+ public DefaultMixedHandler(@NonNull ShellInit shellInit, @NonNull Transitions player,
+ Optional<SplitScreenController> splitScreenControllerOptional,
+ Optional<PipTouchHandler> pipTouchHandlerOptional) {
mPlayer = player;
- mPipHandler = pipHandler;
- mSplitHandler = splitHandler;
+ if (Transitions.ENABLE_SHELL_TRANSITIONS && pipTouchHandlerOptional.isPresent()
+ && splitScreenControllerOptional.isPresent()) {
+ // Add after dependencies because it is higher priority
+ shellInit.addInitCallback(() -> {
+ mPipHandler = pipTouchHandlerOptional.get().getTransitionHandler();
+ mSplitHandler = splitScreenControllerOptional.get().getTransitionHandler();
+ mPlayer.addHandler(this);
+ }, this);
+ }
}
@Nullable
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
index cff60f5..4c927b6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
@@ -554,6 +554,12 @@
private void edgeExtendWindow(TransitionInfo.Change change,
Animation a, SurfaceControl.Transaction startTransaction,
SurfaceControl.Transaction finishTransaction) {
+ // Do not create edge extension surface for transfer starting window change.
+ // The app surface could be empty thus nothing can draw on the hardware renderer, which will
+ // block this thread when calling Surface#unlockCanvasAndPost.
+ if ((change.getFlags() & FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT) != 0) {
+ return;
+ }
final Transformation transformationAtStart = new Transformation();
a.getTransformationAt(0, transformationAtStart);
final Transformation transformationAtEnd = new Transformation();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java
index 6388ca1..b647f43 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java
@@ -139,39 +139,48 @@
.build();
try {
- SurfaceControl.LayerCaptureArgs args =
- new SurfaceControl.LayerCaptureArgs.Builder(mSurfaceControl)
- .setCaptureSecureLayers(true)
- .setAllowProtected(true)
- .setSourceCrop(new Rect(0, 0, mStartWidth, mStartHeight))
- .build();
- SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer =
- SurfaceControl.captureLayers(args);
- if (screenshotBuffer == null) {
- Slog.w(TAG, "Unable to take screenshot of display");
- return;
- }
+ if (change.getSnapshot() != null) {
+ mScreenshotLayer = change.getSnapshot();
+ t.reparent(mScreenshotLayer, mAnimLeash);
+ mStartLuma = change.getSnapshotLuma();
+ } else {
+ SurfaceControl.LayerCaptureArgs args =
+ new SurfaceControl.LayerCaptureArgs.Builder(mSurfaceControl)
+ .setCaptureSecureLayers(true)
+ .setAllowProtected(true)
+ .setSourceCrop(new Rect(0, 0, mStartWidth, mStartHeight))
+ .build();
+ SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer =
+ SurfaceControl.captureLayers(args);
+ if (screenshotBuffer == null) {
+ Slog.w(TAG, "Unable to take screenshot of display");
+ return;
+ }
- mScreenshotLayer = new SurfaceControl.Builder(session)
- .setParent(mAnimLeash)
- .setBLASTLayer()
- .setSecure(screenshotBuffer.containsSecureLayers())
- .setOpaque(true)
- .setCallsite("ShellRotationAnimation")
- .setName("RotationLayer")
- .build();
+ mScreenshotLayer = new SurfaceControl.Builder(session)
+ .setParent(mAnimLeash)
+ .setBLASTLayer()
+ .setSecure(screenshotBuffer.containsSecureLayers())
+ .setOpaque(true)
+ .setCallsite("ShellRotationAnimation")
+ .setName("RotationLayer")
+ .build();
+
+ final ColorSpace colorSpace = screenshotBuffer.getColorSpace();
+ final HardwareBuffer hardwareBuffer = screenshotBuffer.getHardwareBuffer();
+ t.setDataSpace(mScreenshotLayer, colorSpace.getDataSpace());
+ t.setBuffer(mScreenshotLayer, hardwareBuffer);
+ t.show(mScreenshotLayer);
+ if (!isCustomRotate()) {
+ mStartLuma = getMedianBorderLuma(hardwareBuffer, colorSpace);
+ }
+ }
t.setLayer(mAnimLeash, SCREEN_FREEZE_LAYER_BASE);
t.show(mAnimLeash);
// Crop the real content in case it contains a larger child layer, e.g. wallpaper.
t.setCrop(mSurfaceControl, new Rect(0, 0, mEndWidth, mEndHeight));
- final ColorSpace colorSpace = screenshotBuffer.getColorSpace();
- final HardwareBuffer hardwareBuffer = screenshotBuffer.getHardwareBuffer();
- t.setDataSpace(mScreenshotLayer, colorSpace.getDataSpace());
- t.setBuffer(mScreenshotLayer, hardwareBuffer);
- t.show(mScreenshotLayer);
-
if (!isCustomRotate()) {
mBackColorSurface = new SurfaceControl.Builder(session)
.setParent(rootLeash)
@@ -181,8 +190,6 @@
.setName("BackColorSurface")
.build();
- mStartLuma = getMedianBorderLuma(hardwareBuffer, colorSpace);
-
t.setLayer(mBackColorSurface, -1);
t.setColor(mBackColorSurface, new float[]{mStartLuma, mStartLuma, mStartLuma});
t.show(mBackColorSurface);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/SplitscreenPipMixedHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/SplitscreenPipMixedHandler.java
deleted file mode 100644
index 678e91f..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/SplitscreenPipMixedHandler.java
+++ /dev/null
@@ -1,55 +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.wm.shell.transition;
-
-import com.android.wm.shell.pip.phone.PipTouchHandler;
-import com.android.wm.shell.splitscreen.SplitScreenController;
-import com.android.wm.shell.sysui.ShellInit;
-
-import java.util.Optional;
-
-/**
- * Handles transitions between the Splitscreen and PIP components.
- */
-public class SplitscreenPipMixedHandler {
-
- private final Optional<SplitScreenController> mSplitScreenOptional;
- private final Optional<PipTouchHandler> mPipTouchHandlerOptional;
- private final Transitions mTransitions;
-
- public SplitscreenPipMixedHandler(ShellInit shellInit,
- Optional<SplitScreenController> splitScreenControllerOptional,
- Optional<PipTouchHandler> pipTouchHandlerOptional,
- Transitions transitions) {
- mSplitScreenOptional = splitScreenControllerOptional;
- mPipTouchHandlerOptional = pipTouchHandlerOptional;
- mTransitions = transitions;
- if (Transitions.ENABLE_SHELL_TRANSITIONS
- && mSplitScreenOptional.isPresent() && mPipTouchHandlerOptional.isPresent()) {
- shellInit.addInitCallback(this::onInit, this);
- }
- }
-
- private void onInit() {
- // Special handling for initializing based on multiple components
- final DefaultMixedHandler mixedHandler = new DefaultMixedHandler(mTransitions,
- mPipTouchHandlerOptional.get().getTransitionHandler(),
- mSplitScreenOptional.get().getTransitionHandler());
- // Added at end so that it has highest priority.
- mTransitions.addHandler(mixedHandler);
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/util/GroupedRecentTaskInfo.java b/libs/WindowManager/Shell/src/com/android/wm/shell/util/GroupedRecentTaskInfo.java
index 2cff171..c045ceb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/util/GroupedRecentTaskInfo.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/util/GroupedRecentTaskInfo.java
@@ -16,6 +16,7 @@
package com.android.wm.shell.util;
+import android.annotation.IntDef;
import android.app.ActivityManager;
import android.app.WindowConfiguration;
import android.os.Parcel;
@@ -24,40 +25,143 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import java.util.Arrays;
+import java.util.List;
+
/**
* Simple container for recent tasks. May contain either a single or pair of tasks.
*/
public class GroupedRecentTaskInfo implements Parcelable {
- public @NonNull ActivityManager.RecentTaskInfo mTaskInfo1;
- public @Nullable ActivityManager.RecentTaskInfo mTaskInfo2;
- public @Nullable SplitBounds mSplitBounds;
- public GroupedRecentTaskInfo(@NonNull ActivityManager.RecentTaskInfo task1) {
- this(task1, null, null);
+ public static final int TYPE_SINGLE = 1;
+ public static final int TYPE_SPLIT = 2;
+ public static final int TYPE_FREEFORM = 3;
+
+ @IntDef(prefix = {"TYPE_"}, value = {
+ TYPE_SINGLE,
+ TYPE_SPLIT,
+ TYPE_FREEFORM
+ })
+ public @interface GroupType {}
+
+ @NonNull
+ private final ActivityManager.RecentTaskInfo[] mTasks;
+ @Nullable
+ private final SplitBounds mSplitBounds;
+ @GroupType
+ private final int mType;
+
+ /**
+ * Create new for a single task
+ */
+ public static GroupedRecentTaskInfo forSingleTask(
+ @NonNull ActivityManager.RecentTaskInfo task) {
+ return new GroupedRecentTaskInfo(new ActivityManager.RecentTaskInfo[]{task}, null,
+ TYPE_SINGLE);
}
- public GroupedRecentTaskInfo(@NonNull ActivityManager.RecentTaskInfo task1,
- @Nullable ActivityManager.RecentTaskInfo task2,
- @Nullable SplitBounds splitBounds) {
- mTaskInfo1 = task1;
- mTaskInfo2 = task2;
+ /**
+ * Create new for a pair of tasks in split screen
+ */
+ public static GroupedRecentTaskInfo forSplitTasks(@NonNull ActivityManager.RecentTaskInfo task1,
+ @NonNull ActivityManager.RecentTaskInfo task2, @Nullable SplitBounds splitBounds) {
+ return new GroupedRecentTaskInfo(new ActivityManager.RecentTaskInfo[]{task1, task2},
+ splitBounds, TYPE_SPLIT);
+ }
+
+ /**
+ * Create new for a group of freeform tasks
+ */
+ public static GroupedRecentTaskInfo forFreeformTasks(
+ @NonNull ActivityManager.RecentTaskInfo... tasks) {
+ return new GroupedRecentTaskInfo(tasks, null, TYPE_FREEFORM);
+ }
+
+ private GroupedRecentTaskInfo(@NonNull ActivityManager.RecentTaskInfo[] tasks,
+ @Nullable SplitBounds splitBounds, @GroupType int type) {
+ mTasks = tasks;
mSplitBounds = splitBounds;
+ mType = type;
}
GroupedRecentTaskInfo(Parcel parcel) {
- mTaskInfo1 = parcel.readTypedObject(ActivityManager.RecentTaskInfo.CREATOR);
- mTaskInfo2 = parcel.readTypedObject(ActivityManager.RecentTaskInfo.CREATOR);
+ mTasks = parcel.createTypedArray(ActivityManager.RecentTaskInfo.CREATOR);
mSplitBounds = parcel.readTypedObject(SplitBounds.CREATOR);
+ mType = parcel.readInt();
+ }
+
+ /**
+ * Get primary {@link ActivityManager.RecentTaskInfo}
+ */
+ @NonNull
+ public ActivityManager.RecentTaskInfo getTaskInfo1() {
+ return mTasks[0];
+ }
+
+ /**
+ * Get secondary {@link ActivityManager.RecentTaskInfo}.
+ *
+ * Used in split screen.
+ */
+ @Nullable
+ public ActivityManager.RecentTaskInfo getTaskInfo2() {
+ if (mTasks.length > 1) {
+ return mTasks[1];
+ }
+ return null;
+ }
+
+ /**
+ * Get all {@link ActivityManager.RecentTaskInfo}s grouped together.
+ */
+ @NonNull
+ public List<ActivityManager.RecentTaskInfo> getTaskInfoList() {
+ return Arrays.asList(mTasks);
+ }
+
+ /**
+ * Return {@link SplitBounds} if this is a split screen entry or {@code null}
+ */
+ @Nullable
+ public SplitBounds getSplitBounds() {
+ return mSplitBounds;
+ }
+
+ /**
+ * Get type of this recents entry. One of {@link GroupType}
+ */
+ @GroupType
+ public int getType() {
+ return mType;
}
@Override
public String toString() {
- String taskString = "Task1: " + getTaskInfo(mTaskInfo1)
- + ", Task2: " + getTaskInfo(mTaskInfo2);
- if (mSplitBounds != null) {
- taskString += ", SplitBounds: " + mSplitBounds.toString();
+ StringBuilder taskString = new StringBuilder();
+ for (int i = 0; i < mTasks.length; i++) {
+ if (i == 0) {
+ taskString.append("Task");
+ } else {
+ taskString.append(", Task");
+ }
+ taskString.append(i + 1).append(": ").append(getTaskInfo(mTasks[i]));
}
- return taskString;
+ if (mSplitBounds != null) {
+ taskString.append(", SplitBounds: ").append(mSplitBounds);
+ }
+ taskString.append(", Type=");
+ switch (mType) {
+ case TYPE_SINGLE:
+ taskString.append("TYPE_SINGLE");
+ break;
+ case TYPE_SPLIT:
+ taskString.append("TYPE_SPLIT");
+ break;
+ case TYPE_FREEFORM:
+ taskString.append("TYPE_FREEFORM");
+ break;
+ }
+ return taskString.toString();
}
private String getTaskInfo(ActivityManager.RecentTaskInfo taskInfo) {
@@ -74,9 +178,9 @@
@Override
public void writeToParcel(Parcel parcel, int flags) {
- parcel.writeTypedObject(mTaskInfo1, flags);
- parcel.writeTypedObject(mTaskInfo2, flags);
+ parcel.writeTypedArray(mTasks, flags);
parcel.writeTypedObject(mSplitBounds, flags);
+ parcel.writeInt(mType);
}
@Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
index 8b13721..5040bc3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
@@ -34,7 +34,7 @@
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.SyncTransactionQueue;
-import com.android.wm.shell.desktopmode.DesktopModeConstants;
+import com.android.wm.shell.desktopmode.DesktopMode;
/**
* Defines visuals and behaviors of a window decoration of a caption bar and shadows. It works with
@@ -164,7 +164,7 @@
View caption = mResult.mRootView.findViewById(R.id.caption);
caption.setOnTouchListener(mOnCaptionTouchListener);
View maximize = caption.findViewById(R.id.maximize_window);
- if (DesktopModeConstants.IS_FEATURE_ENABLED) {
+ if (DesktopMode.IS_SUPPORTED) {
// Hide maximize button when desktop mode is available
maximize.setVisibility(View.GONE);
} else {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java
index f512b0d..3d01495 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java
@@ -87,7 +87,7 @@
try {
mWindowSession.grantInputChannel(
mDisplayId,
- new SurfaceControl(mDecorationSurface, TAG),
+ mDecorationSurface,
mFakeWindow,
null /* hostInputToken */,
FLAG_NOT_FOCUSABLE,
@@ -150,8 +150,7 @@
mWindowSession.updateInputChannel(
mInputChannel.getToken(),
mDisplayId,
- new SurfaceControl(
- mDecorationSurface, "DragResizeInputListener#setTouchRegion"),
+ mDecorationSurface,
FLAG_NOT_FOCUSABLE,
PRIVATE_FLAG_TRUSTED_OVERLAY,
touchRegion);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
index 2f41aa9..3e3a864 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
@@ -66,6 +66,7 @@
final DisplayController mDisplayController;
final ShellTaskOrganizer mTaskOrganizer;
final Supplier<SurfaceControl.Builder> mSurfaceControlBuilderSupplier;
+ final Supplier<SurfaceControl.Transaction> mSurfaceControlTransactionSupplier;
final Supplier<WindowContainerTransaction> mWindowContainerTransactionSupplier;
final SurfaceControlViewHostFactory mSurfaceControlViewHostFactory;
private final DisplayController.OnDisplaysChangedListener mOnDisplaysChangedListener =
@@ -104,8 +105,8 @@
RunningTaskInfo taskInfo,
SurfaceControl taskSurface) {
this(context, displayController, taskOrganizer, taskInfo, taskSurface,
- SurfaceControl.Builder::new, WindowContainerTransaction::new,
- new SurfaceControlViewHostFactory() {});
+ SurfaceControl.Builder::new, SurfaceControl.Transaction::new,
+ WindowContainerTransaction::new, new SurfaceControlViewHostFactory() {});
}
WindowDecoration(
@@ -115,6 +116,7 @@
RunningTaskInfo taskInfo,
SurfaceControl taskSurface,
Supplier<SurfaceControl.Builder> surfaceControlBuilderSupplier,
+ Supplier<SurfaceControl.Transaction> surfaceControlTransactionSupplier,
Supplier<WindowContainerTransaction> windowContainerTransactionSupplier,
SurfaceControlViewHostFactory surfaceControlViewHostFactory) {
mContext = context;
@@ -123,6 +125,7 @@
mTaskInfo = taskInfo;
mTaskSurface = taskSurface;
mSurfaceControlBuilderSupplier = surfaceControlBuilderSupplier;
+ mSurfaceControlTransactionSupplier = surfaceControlTransactionSupplier;
mWindowContainerTransactionSupplier = windowContainerTransactionSupplier;
mSurfaceControlViewHostFactory = surfaceControlViewHostFactory;
@@ -320,19 +323,28 @@
mCaptionWindowManager = null;
+ final SurfaceControl.Transaction t = mSurfaceControlTransactionSupplier.get();
+ boolean released = false;
if (mCaptionContainerSurface != null) {
- mCaptionContainerSurface.release();
+ t.remove(mCaptionContainerSurface);
mCaptionContainerSurface = null;
+ released = true;
}
if (mDecorationContainerSurface != null) {
- mDecorationContainerSurface.release();
+ t.remove(mDecorationContainerSurface);
mDecorationContainerSurface = null;
+ released = true;
}
if (mTaskBackgroundSurface != null) {
- mTaskBackgroundSurface.release();
+ t.remove(mTaskBackgroundSurface);
mTaskBackgroundSurface = null;
+ released = true;
+ }
+
+ if (released) {
+ t.apply();
}
final WindowContainerTransaction wct = mWindowContainerTransactionSupplier.get();
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
index 9ba5166..61ac498 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
@@ -132,7 +132,7 @@
testSpec.assertLayers {
val pipLayerList = this.layers { it.name.contains(layerName) && it.isVisible }
pipLayerList.zipWithNext { previous, current ->
- current.visibleRegion.coversAtMost(previous.visibleRegion.region)
+ current.visibleRegion.notBiggerThan(previous.visibleRegion.region)
}
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt
index f50097d..7680f4d 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt
@@ -43,7 +43,7 @@
/**
* Test entering pip while changing orientation (from app in landscape to pip window in portrait)
*
- * To run this test: `atest EnterPipToOtherOrientationTest:EnterPipToOtherOrientationTest`
+ * To run this test: `atest WMShellFlickerTests:EnterPipToOtherOrientationTest`
*
* Actions:
* Launch [testApp] on a fixed portrait orientation
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java
index b29c436..7cbace5 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java
@@ -16,6 +16,8 @@
package com.android.wm.shell;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
@@ -637,26 +639,22 @@
}
@Test
- public void testPrepareClearBoundsForTasks() {
- RunningTaskInfo task1 = createTaskInfo(1, WINDOWING_MODE_UNDEFINED);
- task1.displayId = 1;
+ public void testPrepareClearBoundsForStandardTasks() {
MockToken token1 = new MockToken();
- task1.token = token1.token();
+ RunningTaskInfo task1 = createTaskInfo(1, WINDOWING_MODE_UNDEFINED, token1);
mOrganizer.onTaskAppeared(task1, null);
- RunningTaskInfo task2 = createTaskInfo(2, WINDOWING_MODE_UNDEFINED);
- task2.displayId = 1;
MockToken token2 = new MockToken();
- task2.token = token2.token();
+ RunningTaskInfo task2 = createTaskInfo(2, WINDOWING_MODE_UNDEFINED, token2);
mOrganizer.onTaskAppeared(task2, null);
- RunningTaskInfo otherDisplayTask = createTaskInfo(3, WINDOWING_MODE_UNDEFINED);
- otherDisplayTask.displayId = 2;
MockToken otherDisplayToken = new MockToken();
- otherDisplayTask.token = otherDisplayToken.token();
+ RunningTaskInfo otherDisplayTask = createTaskInfo(3, WINDOWING_MODE_UNDEFINED,
+ otherDisplayToken);
+ otherDisplayTask.displayId = 2;
mOrganizer.onTaskAppeared(otherDisplayTask, null);
- WindowContainerTransaction wct = mOrganizer.prepareClearBoundsForTasks(1);
+ WindowContainerTransaction wct = mOrganizer.prepareClearBoundsForStandardTasks(1);
assertEquals(wct.getChanges().size(), 2);
Change boundsChange1 = wct.getChanges().get(token1.binder());
@@ -673,26 +671,40 @@
}
@Test
- public void testPrepareClearFreeformForTasks() {
- RunningTaskInfo task1 = createTaskInfo(1, WINDOWING_MODE_FREEFORM);
- task1.displayId = 1;
+ public void testPrepareClearBoundsForStandardTasks_onlyClearActivityTypeStandard() {
MockToken token1 = new MockToken();
- task1.token = token1.token();
+ RunningTaskInfo task1 = createTaskInfo(1, WINDOWING_MODE_UNDEFINED, token1);
mOrganizer.onTaskAppeared(task1, null);
- RunningTaskInfo task2 = createTaskInfo(2, WINDOWING_MODE_MULTI_WINDOW);
- task2.displayId = 1;
MockToken token2 = new MockToken();
- task2.token = token2.token();
+ RunningTaskInfo task2 = createTaskInfo(2, WINDOWING_MODE_UNDEFINED, token2);
+ task2.configuration.windowConfiguration.setActivityType(ACTIVITY_TYPE_HOME);
mOrganizer.onTaskAppeared(task2, null);
- RunningTaskInfo otherDisplayTask = createTaskInfo(3, WINDOWING_MODE_FREEFORM);
- otherDisplayTask.displayId = 2;
+ WindowContainerTransaction wct = mOrganizer.prepareClearBoundsForStandardTasks(1);
+
+ // Only clear bounds for task1
+ assertEquals(1, wct.getChanges().size());
+ assertNotNull(wct.getChanges().get(token1.binder()));
+ }
+
+ @Test
+ public void testPrepareClearFreeformForStandardTasks() {
+ MockToken token1 = new MockToken();
+ RunningTaskInfo task1 = createTaskInfo(1, WINDOWING_MODE_FREEFORM, token1);
+ mOrganizer.onTaskAppeared(task1, null);
+
+ MockToken token2 = new MockToken();
+ RunningTaskInfo task2 = createTaskInfo(2, WINDOWING_MODE_MULTI_WINDOW, token2);
+ mOrganizer.onTaskAppeared(task2, null);
+
MockToken otherDisplayToken = new MockToken();
- otherDisplayTask.token = otherDisplayToken.token();
+ RunningTaskInfo otherDisplayTask = createTaskInfo(3, WINDOWING_MODE_FREEFORM,
+ otherDisplayToken);
+ otherDisplayTask.displayId = 2;
mOrganizer.onTaskAppeared(otherDisplayTask, null);
- WindowContainerTransaction wct = mOrganizer.prepareClearFreeformForTasks(1);
+ WindowContainerTransaction wct = mOrganizer.prepareClearFreeformForStandardTasks(1);
// Only task with freeform windowing mode and the right display should be updated
assertEquals(wct.getChanges().size(), 1);
@@ -701,6 +713,24 @@
assertEquals(wmModeChange1.getWindowingMode(), WINDOWING_MODE_UNDEFINED);
}
+ @Test
+ public void testPrepareClearFreeformForStandardTasks_onlyClearActivityTypeStandard() {
+ MockToken token1 = new MockToken();
+ RunningTaskInfo task1 = createTaskInfo(1, WINDOWING_MODE_FREEFORM, token1);
+ mOrganizer.onTaskAppeared(task1, null);
+
+ MockToken token2 = new MockToken();
+ RunningTaskInfo task2 = createTaskInfo(2, WINDOWING_MODE_FREEFORM, token2);
+ task2.configuration.windowConfiguration.setActivityType(ACTIVITY_TYPE_HOME);
+ mOrganizer.onTaskAppeared(task2, null);
+
+ WindowContainerTransaction wct = mOrganizer.prepareClearFreeformForStandardTasks(1);
+
+ // Only clear freeform for task1
+ assertEquals(1, wct.getChanges().size());
+ assertNotNull(wct.getChanges().get(token1.binder()));
+ }
+
private static RunningTaskInfo createTaskInfo(int taskId, int windowingMode) {
RunningTaskInfo taskInfo = new RunningTaskInfo();
taskInfo.taskId = taskId;
@@ -708,6 +738,14 @@
return taskInfo;
}
+ private static RunningTaskInfo createTaskInfo(int taskId, int windowingMode, MockToken token) {
+ RunningTaskInfo taskInfo = createTaskInfo(taskId, windowingMode);
+ taskInfo.displayId = 1;
+ taskInfo.token = token.token();
+ taskInfo.configuration.windowConfiguration.setActivityType(ACTIVITY_TYPE_STANDARD);
+ return taskInfo;
+ }
+
private static class MockToken {
private final WindowContainerToken mToken;
private final IBinder mBinder;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeControllerTest.java
index 58f20da..ef532e4 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeControllerTest.java
@@ -88,8 +88,8 @@
WindowContainerTransaction taskWct = new WindowContainerTransaction();
MockToken taskMockToken = new MockToken();
taskWct.setWindowingMode(taskMockToken.token(), WINDOWING_MODE_UNDEFINED);
- when(mShellTaskOrganizer.prepareClearFreeformForTasks(mContext.getDisplayId())).thenReturn(
- taskWct);
+ when(mShellTaskOrganizer.prepareClearFreeformForStandardTasks(
+ mContext.getDisplayId())).thenReturn(taskWct);
// Create a fake WCT to simulate setting display windowing mode to freeform
WindowContainerTransaction displayWct = new WindowContainerTransaction();
@@ -99,7 +99,7 @@
WINDOWING_MODE_FREEFORM)).thenReturn(displayWct);
// The test
- mController.updateDesktopModeEnabled(true);
+ mController.updateDesktopModeActive(true);
ArgumentCaptor<WindowContainerTransaction> arg = ArgumentCaptor.forClass(
WindowContainerTransaction.class);
@@ -126,15 +126,15 @@
WindowContainerTransaction taskWmWct = new WindowContainerTransaction();
MockToken taskWmMockToken = new MockToken();
taskWmWct.setWindowingMode(taskWmMockToken.token(), WINDOWING_MODE_UNDEFINED);
- when(mShellTaskOrganizer.prepareClearFreeformForTasks(mContext.getDisplayId())).thenReturn(
- taskWmWct);
+ when(mShellTaskOrganizer.prepareClearFreeformForStandardTasks(
+ mContext.getDisplayId())).thenReturn(taskWmWct);
// Create a fake WCT to simulate clearing task bounds
WindowContainerTransaction taskBoundsWct = new WindowContainerTransaction();
MockToken taskBoundsMockToken = new MockToken();
taskBoundsWct.setBounds(taskBoundsMockToken.token(), null);
- when(mShellTaskOrganizer.prepareClearBoundsForTasks(mContext.getDisplayId())).thenReturn(
- taskBoundsWct);
+ when(mShellTaskOrganizer.prepareClearBoundsForStandardTasks(
+ mContext.getDisplayId())).thenReturn(taskBoundsWct);
// Create a fake WCT to simulate setting display windowing mode to fullscreen
WindowContainerTransaction displayWct = new WindowContainerTransaction();
@@ -144,7 +144,7 @@
WINDOWING_MODE_FULLSCREEN)).thenReturn(displayWct);
// The test
- mController.updateDesktopModeEnabled(false);
+ mController.updateDesktopModeActive(false);
ArgumentCaptor<WindowContainerTransaction> arg = ArgumentCaptor.forClass(
WindowContainerTransaction.class);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsAlgorithmTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsAlgorithmTest.java
index 0059846..262e429 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsAlgorithmTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsAlgorithmTest.java
@@ -64,7 +64,7 @@
initializeMockResources();
mPipBoundsState = new PipBoundsState(mContext);
mPipBoundsAlgorithm = new PipBoundsAlgorithm(mContext, mPipBoundsState,
- new PipSnapAlgorithm());
+ new PipSnapAlgorithm(), new PipKeepClearAlgorithm() {});
mPipBoundsState.setDisplayLayout(
new DisplayLayout(mDefaultDisplayInfo, mContext.getResources(), true, true));
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
index 579638d..9088077 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
@@ -98,7 +98,7 @@
mPipBoundsState = new PipBoundsState(mContext);
mPipTransitionState = new PipTransitionState();
mPipBoundsAlgorithm = new PipBoundsAlgorithm(mContext, mPipBoundsState,
- new PipSnapAlgorithm());
+ new PipSnapAlgorithm(), new PipKeepClearAlgorithm() {});
mMainExecutor = new TestShellExecutor();
mPipTaskOrganizer = new PipTaskOrganizer(mContext,
mMockSyncTransactionQueue, mPipTransitionState, mPipBoundsState,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipKeepClearAlgorithmTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PhonePipKeepClearAlgorithmTest.java
similarity index 64%
rename from libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipKeepClearAlgorithmTest.java
rename to libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PhonePipKeepClearAlgorithmTest.java
index e0f7e35..4d7e9e4 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipKeepClearAlgorithmTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PhonePipKeepClearAlgorithmTest.java
@@ -34,61 +34,61 @@
import java.util.Set;
/**
- * Unit tests against {@link PipKeepClearAlgorithm}.
+ * Unit tests against {@link PhonePipKeepClearAlgorithm}.
*/
@RunWith(AndroidTestingRunner.class)
@SmallTest
@TestableLooper.RunWithLooper(setAsMainLooper = true)
-public class PipKeepClearAlgorithmTest extends ShellTestCase {
+public class PhonePipKeepClearAlgorithmTest extends ShellTestCase {
- private PipKeepClearAlgorithm mPipKeepClearAlgorithm;
+ private PhonePipKeepClearAlgorithm mPipKeepClearAlgorithm;
private static final Rect DISPLAY_BOUNDS = new Rect(0, 0, 1000, 1000);
@Before
public void setUp() throws Exception {
- mPipKeepClearAlgorithm = new PipKeepClearAlgorithm();
+ mPipKeepClearAlgorithm = new PhonePipKeepClearAlgorithm(mContext);
}
@Test
- public void adjust_withCollidingRestrictedKeepClearAreas_movesBounds() {
+ public void findUnoccludedPosition_withCollidingRestrictedKeepClearArea_movesBounds() {
final Rect inBounds = new Rect(0, 0, 100, 100);
final Rect keepClearRect = new Rect(50, 50, 150, 150);
- final Rect outBounds = mPipKeepClearAlgorithm.adjust(inBounds, Set.of(keepClearRect),
- Set.of(), DISPLAY_BOUNDS);
+ final Rect outBounds = mPipKeepClearAlgorithm.findUnoccludedPosition(inBounds,
+ Set.of(keepClearRect), Set.of(), DISPLAY_BOUNDS);
assertFalse(outBounds.contains(keepClearRect));
}
@Test
- public void adjust_withNonCollidingRestrictedKeepClearAreas_boundsDoNotChange() {
+ public void findUnoccludedPosition_withNonCollidingRestrictedKeepClearArea_boundsUnchanged() {
final Rect inBounds = new Rect(0, 0, 100, 100);
final Rect keepClearRect = new Rect(100, 100, 150, 150);
- final Rect outBounds = mPipKeepClearAlgorithm.adjust(inBounds, Set.of(keepClearRect),
- Set.of(), DISPLAY_BOUNDS);
+ final Rect outBounds = mPipKeepClearAlgorithm.findUnoccludedPosition(inBounds,
+ Set.of(keepClearRect), Set.of(), DISPLAY_BOUNDS);
assertEquals(inBounds, outBounds);
}
@Test
- public void adjust_withCollidingUnrestrictedKeepClearAreas_boundsDoNotChange() {
+ public void findUnoccludedPosition_withCollidingUnrestrictedKeepClearArea_moveBounds() {
// TODO(b/183746978): update this test to accommodate for the updated algorithm
final Rect inBounds = new Rect(0, 0, 100, 100);
final Rect keepClearRect = new Rect(50, 50, 150, 150);
- final Rect outBounds = mPipKeepClearAlgorithm.adjust(inBounds, Set.of(),
+ final Rect outBounds = mPipKeepClearAlgorithm.findUnoccludedPosition(inBounds, Set.of(),
Set.of(keepClearRect), DISPLAY_BOUNDS);
- assertEquals(inBounds, outBounds);
+ assertFalse(outBounds.contains(keepClearRect));
}
@Test
- public void adjust_withNonCollidingUnrestrictedKeepClearAreas_boundsDoNotChange() {
+ public void findUnoccludedPosition_withNonCollidingUnrestrictedKeepClearArea_boundsUnchanged() {
final Rect inBounds = new Rect(0, 0, 100, 100);
final Rect keepClearRect = new Rect(100, 100, 150, 150);
- final Rect outBounds = mPipKeepClearAlgorithm.adjust(inBounds, Set.of(),
+ final Rect outBounds = mPipKeepClearAlgorithm.findUnoccludedPosition(inBounds, Set.of(),
Set.of(keepClearRect), DISPLAY_BOUNDS);
assertEquals(inBounds, outBounds);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
index eb5726b..a8d3bdc 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
@@ -43,6 +43,7 @@
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.DisplayInsetsController;
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.TaskStackListenerImpl;
@@ -64,6 +65,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
+import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import java.util.Optional;
@@ -85,7 +87,7 @@
@Mock private PhonePipMenuController mMockPhonePipMenuController;
@Mock private PipAppOpsListener mMockPipAppOpsListener;
@Mock private PipBoundsAlgorithm mMockPipBoundsAlgorithm;
- @Mock private PipKeepClearAlgorithm mMockPipKeepClearAlgorithm;
+ @Mock private PhonePipKeepClearAlgorithm mMockPipKeepClearAlgorithm;
@Mock private PipSnapAlgorithm mMockPipSnapAlgorithm;
@Mock private PipMediaController mMockPipMediaController;
@Mock private PipTaskOrganizer mMockPipTaskOrganizer;
@@ -98,7 +100,8 @@
@Mock private TaskStackListenerImpl mMockTaskStackListener;
@Mock private ShellExecutor mMockExecutor;
@Mock private Optional<OneHandedController> mMockOneHandedController;
- @Mock private PipParamsChangedForwarder mPipParamsChangedForwarder;
+ @Mock private PipParamsChangedForwarder mMockPipParamsChangedForwarder;
+ @Mock private DisplayInsetsController mMockDisplayInsetsController;
@Mock private DisplayLayout mMockDisplayLayout1;
@Mock private DisplayLayout mMockDisplayLayout2;
@@ -119,8 +122,8 @@
mMockPipBoundsState, mMockPipMotionHelper, mMockPipMediaController,
mMockPhonePipMenuController, mMockPipTaskOrganizer, mMockPipTransitionState,
mMockPipTouchHandler, mMockPipTransitionController, mMockWindowManagerShellWrapper,
- mMockTaskStackListener, mPipParamsChangedForwarder,
- mMockOneHandedController, mMockExecutor);
+ mMockTaskStackListener, mMockPipParamsChangedForwarder,
+ mMockDisplayInsetsController, mMockOneHandedController, mMockExecutor);
mShellInit.init();
when(mMockPipBoundsAlgorithm.getSnapAlgorithm()).thenReturn(mMockPipSnapAlgorithm);
when(mMockPipTouchHandler.getMotionHelper()).thenReturn(mMockPipMotionHelper);
@@ -185,8 +188,8 @@
mMockPipBoundsState, mMockPipMotionHelper, mMockPipMediaController,
mMockPhonePipMenuController, mMockPipTaskOrganizer, mMockPipTransitionState,
mMockPipTouchHandler, mMockPipTransitionController, mMockWindowManagerShellWrapper,
- mMockTaskStackListener, mPipParamsChangedForwarder,
- mMockOneHandedController, mMockExecutor));
+ mMockTaskStackListener, mMockPipParamsChangedForwarder,
+ mMockDisplayInsetsController, mMockOneHandedController, mMockExecutor));
}
@Test
@@ -267,7 +270,20 @@
}
@Test
- public void onKeepClearAreasChanged_updatesPipBoundsState() {
+ public void onKeepClearAreasChanged_featureDisabled_pipBoundsStateDoesntChange() {
+ final int displayId = 1;
+ final Rect keepClearArea = new Rect(0, 0, 10, 10);
+ when(mMockPipBoundsState.getDisplayId()).thenReturn(displayId);
+
+ mPipController.mDisplaysChangedListener.onKeepClearAreasChanged(
+ displayId, Set.of(keepClearArea), Set.of());
+
+ verify(mMockPipBoundsState, never()).setKeepClearAreas(Mockito.anySet(), Mockito.anySet());
+ }
+
+ @Test
+ public void onKeepClearAreasChanged_featureEnabled_updatesPipBoundsState() {
+ mPipController.setEnablePipKeepClearAlgorithm(true);
final int displayId = 1;
final Rect keepClearArea = new Rect(0, 0, 10, 10);
when(mMockPipBoundsState.getDisplayId()).thenReturn(displayId);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipDoubleTapHelperTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipDoubleTapHelperTest.java
new file mode 100644
index 0000000..8ce3ca4
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipDoubleTapHelperTest.java
@@ -0,0 +1,172 @@
+/*
+ * 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.wm.shell.pip.phone;
+
+import static com.android.wm.shell.pip.phone.PipDoubleTapHelper.SIZE_SPEC_CUSTOM;
+import static com.android.wm.shell.pip.phone.PipDoubleTapHelper.SIZE_SPEC_DEFAULT;
+import static com.android.wm.shell.pip.phone.PipDoubleTapHelper.SIZE_SPEC_MAX;
+import static com.android.wm.shell.pip.phone.PipDoubleTapHelper.nextSizeSpec;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.testing.AndroidTestingRunner;
+
+import com.android.wm.shell.ShellTestCase;
+import com.android.wm.shell.pip.PipBoundsState;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+
+/**
+ * Unit test against {@link PipDoubleTapHelper}.
+ */
+@RunWith(AndroidTestingRunner.class)
+public class PipDoubleTapHelperTest extends ShellTestCase {
+ // represents the current pip window state and has information on current
+ // max, min, and normal sizes
+ @Mock private PipBoundsState mBoundStateMock;
+ // tied to boundsStateMock.getBounds() in setUp()
+ @Mock private Rect mBoundsMock;
+
+ // represents the most recent manually resized bounds
+ // i.e. dimensions from the most recent pinch in/out
+ @Mock private Rect mUserResizeBoundsMock;
+
+ // actual dimensions of the pip screen bounds
+ private static final int MAX_WIDTH = 100;
+ private static final int DEFAULT_WIDTH = 40;
+ private static final int MIN_WIDTH = 10;
+
+ private static final int AVERAGE_WIDTH = (MAX_WIDTH + MIN_WIDTH) / 2;
+
+ /**
+ * Initializes mocks and assigns values for different pip screen bounds.
+ */
+ @Before
+ public void setUp() {
+ // define pip bounds
+ when(mBoundStateMock.getMaxSize()).thenReturn(new Point(MAX_WIDTH, 20));
+ when(mBoundStateMock.getMinSize()).thenReturn(new Point(MIN_WIDTH, 2));
+
+ Rect rectMock = mock(Rect.class);
+ when(rectMock.width()).thenReturn(DEFAULT_WIDTH);
+ when(mBoundStateMock.getNormalBounds()).thenReturn(rectMock);
+
+ when(mBoundsMock.width()).thenReturn(DEFAULT_WIDTH);
+ when(mBoundStateMock.getBounds()).thenReturn(mBoundsMock);
+ }
+
+ /**
+ * Tests {@link PipDoubleTapHelper#nextSizeSpec(PipBoundsState, Rect)}.
+ *
+ * <p>when the user resizes the screen to a larger than the average but not the maximum width,
+ * then we toggle between {@code PipSizeSpec.CUSTOM} and {@code PipSizeSpec.DEFAULT}
+ */
+ @Test
+ public void testNextScreenSize_resizedWiderThanAverage_returnDefaultThenCustom() {
+ // make the user resize width in between MAX and average
+ when(mUserResizeBoundsMock.width()).thenReturn((MAX_WIDTH + AVERAGE_WIDTH) / 2);
+ // make current bounds same as resized bound since no double tap yet
+ when(mBoundsMock.width()).thenReturn((MAX_WIDTH + AVERAGE_WIDTH) / 2);
+
+ // then nextScreenSize() i.e. double tapping should
+ // toggle to DEFAULT state
+ Assert.assertSame(nextSizeSpec(mBoundStateMock, mUserResizeBoundsMock),
+ SIZE_SPEC_DEFAULT);
+
+ // once we toggle to DEFAULT our screen size gets updated
+ // but not the user resize bounds
+ when(mBoundsMock.width()).thenReturn(DEFAULT_WIDTH);
+
+ // then nextScreenSize() i.e. double tapping should
+ // toggle to CUSTOM state
+ Assert.assertSame(nextSizeSpec(mBoundStateMock, mUserResizeBoundsMock),
+ SIZE_SPEC_CUSTOM);
+ }
+
+ /**
+ * Tests {@link PipDoubleTapHelper#nextSizeSpec(PipBoundsState, Rect)}.
+ *
+ * <p>when the user resizes the screen to a smaller than the average but not the default width,
+ * then we toggle between {@code PipSizeSpec.CUSTOM} and {@code PipSizeSpec.MAX}
+ */
+ @Test
+ public void testNextScreenSize_resizedNarrowerThanAverage_returnMaxThenCustom() {
+ // make the user resize width in between MIN and average
+ when(mUserResizeBoundsMock.width()).thenReturn((MIN_WIDTH + AVERAGE_WIDTH) / 2);
+ // make current bounds same as resized bound since no double tap yet
+ when(mBoundsMock.width()).thenReturn((MIN_WIDTH + AVERAGE_WIDTH) / 2);
+
+ // then nextScreenSize() i.e. double tapping should
+ // toggle to MAX state
+ Assert.assertSame(nextSizeSpec(mBoundStateMock, mUserResizeBoundsMock),
+ SIZE_SPEC_MAX);
+
+ // once we toggle to MAX our screen size gets updated
+ // but not the user resize bounds
+ when(mBoundsMock.width()).thenReturn(MAX_WIDTH);
+
+ // then nextScreenSize() i.e. double tapping should
+ // toggle to CUSTOM state
+ Assert.assertSame(nextSizeSpec(mBoundStateMock, mUserResizeBoundsMock),
+ SIZE_SPEC_CUSTOM);
+ }
+
+ /**
+ * Tests {@link PipDoubleTapHelper#nextSizeSpec(PipBoundsState, Rect)}.
+ *
+ * <p>when the user resizes the screen to exactly the maximum width
+ * then we toggle to {@code PipSizeSpec.DEFAULT}
+ */
+ @Test
+ public void testNextScreenSize_resizedToMax_returnDefault() {
+ // the resized width is the same as MAX_WIDTH
+ when(mUserResizeBoundsMock.width()).thenReturn(MAX_WIDTH);
+ // the current bounds are also at MAX_WIDTH
+ when(mBoundsMock.width()).thenReturn(MAX_WIDTH);
+
+ // then nextScreenSize() i.e. double tapping should
+ // toggle to DEFAULT state
+ Assert.assertSame(nextSizeSpec(mBoundStateMock, mUserResizeBoundsMock),
+ SIZE_SPEC_DEFAULT);
+ }
+
+ /**
+ * Tests {@link PipDoubleTapHelper#nextSizeSpec(PipBoundsState, Rect)}.
+ *
+ * <p>when the user resizes the screen to exactly the default width
+ * then we toggle to {@code PipSizeSpec.MAX}
+ */
+ @Test
+ public void testNextScreenSize_resizedToDefault_returnMax() {
+ // the resized width is the same as DEFAULT_WIDTH
+ when(mUserResizeBoundsMock.width()).thenReturn(DEFAULT_WIDTH);
+ // the current bounds are also at DEFAULT_WIDTH
+ when(mBoundsMock.width()).thenReturn(DEFAULT_WIDTH);
+
+ // then nextScreenSize() i.e. double tapping should
+ // toggle to MAX state
+ Assert.assertSame(nextSizeSpec(mBoundStateMock, mUserResizeBoundsMock),
+ SIZE_SPEC_MAX);
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipResizeGestureHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipResizeGestureHandlerTest.java
index dd10aa7..dba037d 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipResizeGestureHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipResizeGestureHandlerTest.java
@@ -36,6 +36,7 @@
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.pip.PipBoundsAlgorithm;
import com.android.wm.shell.pip.PipBoundsState;
+import com.android.wm.shell.pip.PipKeepClearAlgorithm;
import com.android.wm.shell.pip.PipSnapAlgorithm;
import com.android.wm.shell.pip.PipTaskOrganizer;
import com.android.wm.shell.pip.PipTransitionController;
@@ -87,8 +88,10 @@
MockitoAnnotations.initMocks(this);
mPipBoundsState = new PipBoundsState(mContext);
final PipSnapAlgorithm pipSnapAlgorithm = new PipSnapAlgorithm();
+ final PipKeepClearAlgorithm pipKeepClearAlgorithm =
+ new PipKeepClearAlgorithm() {};
final PipBoundsAlgorithm pipBoundsAlgorithm = new PipBoundsAlgorithm(mContext,
- mPipBoundsState, pipSnapAlgorithm);
+ mPipBoundsState, pipSnapAlgorithm, pipKeepClearAlgorithm);
final PipMotionHelper motionHelper = new PipMotionHelper(mContext, mPipBoundsState,
mPipTaskOrganizer, mPhonePipMenuController, pipSnapAlgorithm,
mMockPipTransitionController, mFloatingContentCoordinator);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java
index ecefd89..474d6aa 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java
@@ -34,6 +34,7 @@
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.pip.PipBoundsAlgorithm;
import com.android.wm.shell.pip.PipBoundsState;
+import com.android.wm.shell.pip.PipKeepClearAlgorithm;
import com.android.wm.shell.pip.PipSnapAlgorithm;
import com.android.wm.shell.pip.PipTaskOrganizer;
import com.android.wm.shell.pip.PipTransitionController;
@@ -104,7 +105,8 @@
MockitoAnnotations.initMocks(this);
mPipBoundsState = new PipBoundsState(mContext);
mPipSnapAlgorithm = new PipSnapAlgorithm();
- mPipBoundsAlgorithm = new PipBoundsAlgorithm(mContext, mPipBoundsState, mPipSnapAlgorithm);
+ mPipBoundsAlgorithm = new PipBoundsAlgorithm(mContext, mPipBoundsState, mPipSnapAlgorithm,
+ new PipKeepClearAlgorithm() {});
PipMotionHelper pipMotionHelper = new PipMotionHelper(mContext, mPipBoundsState,
mPipTaskOrganizer, mPhonePipMenuController, mPipSnapAlgorithm,
mMockPipTransitionController, mFloatingContentCoordinator);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/GroupedRecentTaskInfoTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/GroupedRecentTaskInfoTest.kt
new file mode 100644
index 0000000..baa06f2
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/GroupedRecentTaskInfoTest.kt
@@ -0,0 +1,169 @@
+/*
+ * 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.wm.shell.recents
+
+import android.app.ActivityManager
+import android.graphics.Rect
+import android.os.Parcel
+import android.testing.AndroidTestingRunner
+import android.window.IWindowContainerToken
+import android.window.WindowContainerToken
+import androidx.test.filters.SmallTest
+import com.android.wm.shell.ShellTestCase
+import com.android.wm.shell.util.GroupedRecentTaskInfo
+import com.android.wm.shell.util.GroupedRecentTaskInfo.CREATOR
+import com.android.wm.shell.util.GroupedRecentTaskInfo.TYPE_FREEFORM
+import com.android.wm.shell.util.GroupedRecentTaskInfo.TYPE_SINGLE
+import com.android.wm.shell.util.GroupedRecentTaskInfo.TYPE_SPLIT
+import com.android.wm.shell.util.SplitBounds
+import com.google.common.truth.Correspondence
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.mock
+
+/**
+ * Tests for [GroupedRecentTaskInfo]
+ */
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class GroupedRecentTaskInfoTest : ShellTestCase() {
+
+ @Test
+ fun testSingleTask_hasCorrectType() {
+ assertThat(singleTaskGroupInfo().type).isEqualTo(TYPE_SINGLE)
+ }
+
+ @Test
+ fun testSingleTask_task1Set_task2Null() {
+ val group = singleTaskGroupInfo()
+ assertThat(group.taskInfo1.taskId).isEqualTo(1)
+ assertThat(group.taskInfo2).isNull()
+ }
+
+ @Test
+ fun testSingleTask_taskInfoList_hasOneTask() {
+ val list = singleTaskGroupInfo().taskInfoList
+ assertThat(list).hasSize(1)
+ assertThat(list[0].taskId).isEqualTo(1)
+ }
+
+ @Test
+ fun testSplitTasks_hasCorrectType() {
+ assertThat(splitTasksGroupInfo().type).isEqualTo(TYPE_SPLIT)
+ }
+
+ @Test
+ fun testSplitTasks_task1Set_task2Set_boundsSet() {
+ val group = splitTasksGroupInfo()
+ assertThat(group.taskInfo1.taskId).isEqualTo(1)
+ assertThat(group.taskInfo2?.taskId).isEqualTo(2)
+ assertThat(group.splitBounds).isNotNull()
+ }
+
+ @Test
+ fun testSplitTasks_taskInfoList_hasTwoTasks() {
+ val list = splitTasksGroupInfo().taskInfoList
+ assertThat(list).hasSize(2)
+ assertThat(list[0].taskId).isEqualTo(1)
+ assertThat(list[1].taskId).isEqualTo(2)
+ }
+
+ @Test
+ fun testFreeformTasks_hasCorrectType() {
+ assertThat(freeformTasksGroupInfo().type).isEqualTo(TYPE_FREEFORM)
+ }
+
+ @Test
+ fun testSplitTasks_taskInfoList_hasThreeTasks() {
+ val list = freeformTasksGroupInfo().taskInfoList
+ assertThat(list).hasSize(3)
+ assertThat(list[0].taskId).isEqualTo(1)
+ assertThat(list[1].taskId).isEqualTo(2)
+ assertThat(list[2].taskId).isEqualTo(3)
+ }
+
+ @Test
+ fun testParcelling_singleTask() {
+ val recentTaskInfo = singleTaskGroupInfo()
+ val parcel = Parcel.obtain()
+ recentTaskInfo.writeToParcel(parcel, 0)
+ parcel.setDataPosition(0)
+ // Read the object back from the parcel
+ val recentTaskInfoParcel = CREATOR.createFromParcel(parcel)
+ assertThat(recentTaskInfoParcel.type).isEqualTo(TYPE_SINGLE)
+ assertThat(recentTaskInfoParcel.taskInfo1.taskId).isEqualTo(1)
+ assertThat(recentTaskInfoParcel.taskInfo2).isNull()
+ }
+
+ @Test
+ fun testParcelling_splitTasks() {
+ val recentTaskInfo = splitTasksGroupInfo()
+ val parcel = Parcel.obtain()
+ recentTaskInfo.writeToParcel(parcel, 0)
+ parcel.setDataPosition(0)
+ // Read the object back from the parcel
+ val recentTaskInfoParcel = CREATOR.createFromParcel(parcel)
+ assertThat(recentTaskInfoParcel.type).isEqualTo(TYPE_SPLIT)
+ assertThat(recentTaskInfoParcel.taskInfo1.taskId).isEqualTo(1)
+ assertThat(recentTaskInfoParcel.taskInfo2).isNotNull()
+ assertThat(recentTaskInfoParcel.taskInfo2!!.taskId).isEqualTo(2)
+ assertThat(recentTaskInfoParcel.splitBounds).isNotNull()
+ }
+
+ @Test
+ fun testParcelling_freeformTasks() {
+ val recentTaskInfo = freeformTasksGroupInfo()
+ val parcel = Parcel.obtain()
+ recentTaskInfo.writeToParcel(parcel, 0)
+ parcel.setDataPosition(0)
+ // Read the object back from the parcel
+ val recentTaskInfoParcel = CREATOR.createFromParcel(parcel)
+ assertThat(recentTaskInfoParcel.type).isEqualTo(TYPE_FREEFORM)
+ assertThat(recentTaskInfoParcel.taskInfoList).hasSize(3)
+ // Only compare task ids
+ val taskIdComparator = Correspondence.transforming<ActivityManager.RecentTaskInfo, Int>(
+ { it?.taskId }, "has taskId of"
+ )
+ assertThat(recentTaskInfoParcel.taskInfoList).comparingElementsUsing(taskIdComparator)
+ .containsExactly(1, 2, 3)
+ }
+
+ private fun createTaskInfo(id: Int) = ActivityManager.RecentTaskInfo().apply {
+ taskId = id
+ token = WindowContainerToken(mock(IWindowContainerToken::class.java))
+ }
+
+ private fun singleTaskGroupInfo(): GroupedRecentTaskInfo {
+ val task = createTaskInfo(id = 1)
+ return GroupedRecentTaskInfo.forSingleTask(task)
+ }
+
+ private fun splitTasksGroupInfo(): GroupedRecentTaskInfo {
+ val task1 = createTaskInfo(id = 1)
+ val task2 = createTaskInfo(id = 2)
+ val splitBounds = SplitBounds(Rect(), Rect(), 1, 2)
+ return GroupedRecentTaskInfo.forSplitTasks(task1, task2, splitBounds)
+ }
+
+ private fun freeformTasksGroupInfo(): GroupedRecentTaskInfo {
+ val task1 = createTaskInfo(id = 1)
+ val task2 = createTaskInfo(id = 2)
+ val task3 = createTaskInfo(id = 3)
+ return GroupedRecentTaskInfo.forFreeformTasks(task1, task2, task3)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
index 81bb609..e9a1e25 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
@@ -20,6 +20,9 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
@@ -45,11 +48,13 @@
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.dx.mockito.inline.extended.StaticMockitoSession;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.TestShellExecutor;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.TaskStackListenerImpl;
+import com.android.wm.shell.desktopmode.DesktopMode;
import com.android.wm.shell.sysui.ShellCommandHandler;
import com.android.wm.shell.sysui.ShellInit;
import com.android.wm.shell.util.GroupedRecentTaskInfo;
@@ -179,6 +184,46 @@
}
@Test
+ public void testGetRecentTasks_groupActiveFreeformTasks() {
+ StaticMockitoSession mockitoSession = mockitoSession().mockStatic(
+ DesktopMode.class).startMocking();
+ when(DesktopMode.isActive(any())).thenReturn(true);
+
+ ActivityManager.RecentTaskInfo t1 = makeTaskInfo(1);
+ ActivityManager.RecentTaskInfo t2 = makeTaskInfo(2);
+ ActivityManager.RecentTaskInfo t3 = makeTaskInfo(3);
+ ActivityManager.RecentTaskInfo t4 = makeTaskInfo(4);
+ setRawList(t1, t2, t3, t4);
+
+ mRecentTasksController.addActiveFreeformTask(1);
+ mRecentTasksController.addActiveFreeformTask(3);
+
+ ArrayList<GroupedRecentTaskInfo> recentTasks = mRecentTasksController.getRecentTasks(
+ MAX_VALUE, RECENT_IGNORE_UNAVAILABLE, 0);
+
+ // 2 freeform tasks should be grouped into one, 3 total recents entries
+ assertEquals(3, recentTasks.size());
+ GroupedRecentTaskInfo freeformGroup = recentTasks.get(0);
+ GroupedRecentTaskInfo singleGroup1 = recentTasks.get(1);
+ GroupedRecentTaskInfo singleGroup2 = recentTasks.get(2);
+
+ // Check that groups have expected types
+ assertEquals(GroupedRecentTaskInfo.TYPE_FREEFORM, freeformGroup.getType());
+ assertEquals(GroupedRecentTaskInfo.TYPE_SINGLE, singleGroup1.getType());
+ assertEquals(GroupedRecentTaskInfo.TYPE_SINGLE, singleGroup2.getType());
+
+ // Check freeform group entries
+ assertEquals(t1, freeformGroup.getTaskInfoList().get(0));
+ assertEquals(t3, freeformGroup.getTaskInfoList().get(1));
+
+ // Check single entries
+ assertEquals(t2, singleGroup1.getTaskInfo1());
+ assertEquals(t4, singleGroup2.getTaskInfo1());
+
+ mockitoSession.finishMocking();
+ }
+
+ @Test
public void testRemovedTaskRemovesSplit() {
ActivityManager.RecentTaskInfo t1 = makeTaskInfo(1);
ActivityManager.RecentTaskInfo t2 = makeTaskInfo(2);
@@ -254,6 +299,7 @@
/**
* Asserts that the recent tasks matches the given task ids.
+ *
* @param expectedTaskIds list of task ids that map to the flattened task ids of the tasks in
* the grouped task list
*/
@@ -262,22 +308,23 @@
int[] flattenedTaskIds = new int[recentTasks.size() * 2];
for (int i = 0; i < recentTasks.size(); i++) {
GroupedRecentTaskInfo pair = recentTasks.get(i);
- int taskId1 = pair.mTaskInfo1.taskId;
+ int taskId1 = pair.getTaskInfo1().taskId;
flattenedTaskIds[2 * i] = taskId1;
- flattenedTaskIds[2 * i + 1] = pair.mTaskInfo2 != null
- ? pair.mTaskInfo2.taskId
+ flattenedTaskIds[2 * i + 1] = pair.getTaskInfo2() != null
+ ? pair.getTaskInfo2().taskId
: -1;
- if (pair.mTaskInfo2 != null) {
- assertNotNull(pair.mSplitBounds);
- int leftTopTaskId = pair.mSplitBounds.leftTopTaskId;
- int bottomRightTaskId = pair.mSplitBounds.rightBottomTaskId;
+ if (pair.getTaskInfo2() != null) {
+ assertNotNull(pair.getSplitBounds());
+ int leftTopTaskId = pair.getSplitBounds().leftTopTaskId;
+ int bottomRightTaskId = pair.getSplitBounds().rightBottomTaskId;
// Unclear if pairs are ordered by split position, most likely not.
- assertTrue(leftTopTaskId == taskId1 || leftTopTaskId == pair.mTaskInfo2.taskId);
+ assertTrue(leftTopTaskId == taskId1
+ || leftTopTaskId == pair.getTaskInfo2().taskId);
assertTrue(bottomRightTaskId == taskId1
- || bottomRightTaskId == pair.mTaskInfo2.taskId);
+ || bottomRightTaskId == pair.getTaskInfo2().taskId);
} else {
- assertNull(pair.mSplitBounds);
+ assertNull(pair.getSplitBounds());
}
}
assertTrue("Expected: " + Arrays.toString(expectedTaskIds)
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java
index a67853c..ae69b3d 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java
@@ -71,11 +71,11 @@
DisplayController displayController, DisplayImeController imeController,
DisplayInsetsController insetsController, SplitLayout splitLayout,
Transitions transitions, TransactionPool transactionPool,
- SplitscreenEventLogger logger, ShellExecutor mainExecutor,
+ ShellExecutor mainExecutor,
Optional<RecentTasksController> recentTasks) {
super(context, displayId, syncQueue, taskOrganizer, mainStage,
sideStage, displayController, imeController, insetsController, splitLayout,
- transitions, transactionPool, logger, mainExecutor, recentTasks);
+ transitions, transactionPool, mainExecutor, recentTasks);
// Prepare root task for testing.
mRootTask = new TestRunningTaskInfoBuilder().build();
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
index 1d038f4..ea0033b 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
@@ -95,7 +95,6 @@
@Mock private TransactionPool mTransactionPool;
@Mock private Transitions mTransitions;
@Mock private SurfaceSession mSurfaceSession;
- @Mock private SplitscreenEventLogger mLogger;
@Mock private IconProvider mIconProvider;
@Mock private ShellExecutor mMainExecutor;
private SplitLayout mSplitLayout;
@@ -127,7 +126,7 @@
mStageCoordinator = new SplitTestUtils.TestStageCoordinator(mContext, DEFAULT_DISPLAY,
mSyncQueue, mTaskOrganizer, mMainStage, mSideStage, mDisplayController,
mDisplayImeController, mDisplayInsetsController, mSplitLayout, mTransitions,
- mTransactionPool, mLogger, mMainExecutor, Optional.empty());
+ mTransactionPool, mMainExecutor, Optional.empty());
mSplitScreenTransitions = mStageCoordinator.getSplitTransitions();
doAnswer((Answer<IBinder>) invocation -> mock(IBinder.class))
.when(mTransitions).startTransition(anyInt(), any(), any());
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
index 4b68870..ea9390e 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
@@ -97,8 +97,6 @@
@Mock
private TransactionPool mTransactionPool;
@Mock
- private SplitscreenEventLogger mLogger;
- @Mock
private ShellExecutor mMainExecutor;
private final Rect mBounds1 = new Rect(10, 20, 30, 40);
@@ -115,7 +113,7 @@
MockitoAnnotations.initMocks(this);
mStageCoordinator = spy(new StageCoordinator(mContext, DEFAULT_DISPLAY, mSyncQueue,
mTaskOrganizer, mMainStage, mSideStage, mDisplayController, mDisplayImeController,
- mDisplayInsetsController, mSplitLayout, mTransitions, mTransactionPool, mLogger,
+ mDisplayInsetsController, mSplitLayout, mTransitions, mTransactionPool,
mMainExecutor, Optional.empty()));
doNothing().when(mStageCoordinator).updateActivityOptions(any(), anyInt());
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
index 1b74d7d..ab6ac94 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
@@ -27,6 +27,7 @@
import static org.mockito.Mockito.argThat;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.same;
@@ -59,6 +60,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
+import org.mockito.InOrder;
import org.mockito.Mock;
import java.util.ArrayList;
@@ -96,6 +98,8 @@
@Mock
private WindowContainerTransaction mMockWindowContainerTransaction;
+ private final List<SurfaceControl.Transaction> mMockSurfaceControlTransactions =
+ new ArrayList<>();
private final List<SurfaceControl.Builder> mMockSurfaceControlBuilders = new ArrayList<>();
private SurfaceControl.Transaction mMockSurfaceControlStartT;
private SurfaceControl.Transaction mMockSurfaceControlFinishT;
@@ -265,6 +269,9 @@
createMockSurfaceControlBuilder(captionContainerSurface);
mMockSurfaceControlBuilders.add(captionContainerSurfaceBuilder);
+ final SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class);
+ mMockSurfaceControlTransactions.add(t);
+
final ActivityManager.TaskDescription.Builder taskDescriptionBuilder =
new ActivityManager.TaskDescription.Builder()
.setBackgroundColor(Color.YELLOW);
@@ -287,19 +294,19 @@
windowDecor.relayout(taskInfo);
verify(mMockSurfaceControlViewHost, never()).release();
- verify(decorContainerSurface, never()).release();
- verify(taskBackgroundSurface, never()).release();
- verify(captionContainerSurface, never()).release();
+ verify(t, never()).apply();
verify(mMockWindowContainerTransaction, never())
.removeInsetsProvider(eq(taskInfo.token), any());
taskInfo.isVisible = false;
windowDecor.relayout(taskInfo);
- verify(mMockSurfaceControlViewHost).release();
- verify(decorContainerSurface).release();
- verify(taskBackgroundSurface).release();
- verify(captionContainerSurface).release();
+ final InOrder releaseOrder = inOrder(t, mMockSurfaceControlViewHost);
+ releaseOrder.verify(mMockSurfaceControlViewHost).release();
+ releaseOrder.verify(t).remove(captionContainerSurface);
+ releaseOrder.verify(t).remove(decorContainerSurface);
+ releaseOrder.verify(t).remove(taskBackgroundSurface);
+ releaseOrder.verify(t).apply();
verify(mMockWindowContainerTransaction).removeInsetsProvider(eq(taskInfo.token), any());
}
@@ -351,21 +358,30 @@
private TestWindowDecoration createWindowDecoration(
ActivityManager.RunningTaskInfo taskInfo, SurfaceControl testSurface) {
return new TestWindowDecoration(mContext, mMockDisplayController, mMockShellTaskOrganizer,
- taskInfo, testSurface, new MockSurfaceControlBuilderSupplier(),
+ taskInfo, testSurface,
+ new MockObjectSupplier<>(mMockSurfaceControlBuilders,
+ () -> createMockSurfaceControlBuilder(mock(SurfaceControl.class))),
+ new MockObjectSupplier<>(mMockSurfaceControlTransactions,
+ () -> mock(SurfaceControl.Transaction.class)),
() -> mMockWindowContainerTransaction, mMockSurfaceControlViewHostFactory);
}
- private class MockSurfaceControlBuilderSupplier implements Supplier<SurfaceControl.Builder> {
+ private class MockObjectSupplier<T> implements Supplier<T> {
+ private final List<T> mObjects;
+ private final Supplier<T> mDefaultSupplier;
private int mNumOfCalls = 0;
+ private MockObjectSupplier(List<T> objects, Supplier<T> defaultSupplier) {
+ mObjects = objects;
+ mDefaultSupplier = defaultSupplier;
+ }
+
@Override
- public SurfaceControl.Builder get() {
- final SurfaceControl.Builder builder =
- mNumOfCalls < mMockSurfaceControlBuilders.size()
- ? mMockSurfaceControlBuilders.get(mNumOfCalls)
- : createMockSurfaceControlBuilder(mock(SurfaceControl.class));
+ public T get() {
+ final T mock = mNumOfCalls < mObjects.size()
+ ? mObjects.get(mNumOfCalls) : mDefaultSupplier.get();
++mNumOfCalls;
- return builder;
+ return mock;
}
}
@@ -383,11 +399,12 @@
ShellTaskOrganizer taskOrganizer, ActivityManager.RunningTaskInfo taskInfo,
SurfaceControl taskSurface,
Supplier<SurfaceControl.Builder> surfaceControlBuilderSupplier,
+ Supplier<SurfaceControl.Transaction> surfaceControlTransactionSupplier,
Supplier<WindowContainerTransaction> windowContainerTransactionSupplier,
SurfaceControlViewHostFactory surfaceControlViewHostFactory) {
super(context, displayController, taskOrganizer, taskInfo, taskSurface,
- surfaceControlBuilderSupplier, windowContainerTransactionSupplier,
- surfaceControlViewHostFactory);
+ surfaceControlBuilderSupplier, surfaceControlTransactionSupplier,
+ windowContainerTransactionSupplier, surfaceControlViewHostFactory);
}
@Override
diff --git a/libs/dream/lowlight/Android.bp b/libs/dream/lowlight/Android.bp
new file mode 100644
index 0000000..5b5b0f0
--- /dev/null
+++ b/libs/dream/lowlight/Android.bp
@@ -0,0 +1,47 @@
+// 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 {
+ // 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"],
+}
+
+filegroup {
+ name: "low_light_dream_lib-sources",
+ srcs: [
+ "src/**/*.java",
+ ],
+ path: "src",
+}
+
+android_library {
+ name: "LowLightDreamLib",
+ srcs: [
+ ":low_light_dream_lib-sources",
+ ],
+ resource_dirs: [
+ "res",
+ ],
+ static_libs: [
+ "androidx.arch.core_core-runtime",
+ "dagger2",
+ "jsr330",
+ ],
+ manifest: "AndroidManifest.xml",
+ plugins: ["dagger2-compiler"],
+}
diff --git a/libs/dream/lowlight/AndroidManifest.xml b/libs/dream/lowlight/AndroidManifest.xml
new file mode 100644
index 0000000..a8d9526
--- /dev/null
+++ b/libs/dream/lowlight/AndroidManifest.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+-->
+
+<manifest package="com.android.dream.lowlight" />
diff --git a/libs/dream/lowlight/res/values/config.xml b/libs/dream/lowlight/res/values/config.xml
new file mode 100644
index 0000000..70fe073
--- /dev/null
+++ b/libs/dream/lowlight/res/values/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+<resources>
+ <!-- The dream component used when the device is low light environment. -->
+ <string translatable="false" name="config_lowLightDreamComponent"/>
+</resources>
diff --git a/libs/dream/lowlight/src/com/android/dream/lowlight/LowLightDreamManager.java b/libs/dream/lowlight/src/com/android/dream/lowlight/LowLightDreamManager.java
new file mode 100644
index 0000000..5ecec4d
--- /dev/null
+++ b/libs/dream/lowlight/src/com/android/dream/lowlight/LowLightDreamManager.java
@@ -0,0 +1,117 @@
+/*
+ * 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.dream.lowlight;
+
+import static com.android.dream.lowlight.dagger.LowLightDreamModule.LOW_LIGHT_DREAM_COMPONENT;
+
+import android.annotation.IntDef;
+import android.annotation.RequiresPermission;
+import android.app.DreamManager;
+import android.content.ComponentName;
+import android.util.Log;
+
+import androidx.annotation.Nullable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+/**
+ * Maintains the ambient light mode of the environment the device is in, and sets a low light dream
+ * component, if present, as the system dream when the ambient light mode is low light.
+ *
+ * @hide
+ */
+public final class LowLightDreamManager {
+ private static final String TAG = "LowLightDreamManager";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+ /**
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = { "AMBIENT_LIGHT_MODE_" }, value = {
+ AMBIENT_LIGHT_MODE_UNKNOWN,
+ AMBIENT_LIGHT_MODE_REGULAR,
+ AMBIENT_LIGHT_MODE_LOW_LIGHT
+ })
+ public @interface AmbientLightMode {}
+
+ /**
+ * Constant for ambient light mode being unknown.
+ * @hide
+ */
+ public static final int AMBIENT_LIGHT_MODE_UNKNOWN = 0;
+
+ /**
+ * Constant for ambient light mode being regular / bright.
+ * @hide
+ */
+ public static final int AMBIENT_LIGHT_MODE_REGULAR = 1;
+
+ /**
+ * Constant for ambient light mode being low light / dim.
+ * @hide
+ */
+ public static final int AMBIENT_LIGHT_MODE_LOW_LIGHT = 2;
+
+ private final DreamManager mDreamManager;
+
+ @Nullable
+ private final ComponentName mLowLightDreamComponent;
+
+ private int mAmbientLightMode = AMBIENT_LIGHT_MODE_UNKNOWN;
+
+ @Inject
+ public LowLightDreamManager(
+ DreamManager dreamManager,
+ @Named(LOW_LIGHT_DREAM_COMPONENT) @Nullable ComponentName lowLightDreamComponent) {
+ mDreamManager = dreamManager;
+ mLowLightDreamComponent = lowLightDreamComponent;
+ }
+
+ /**
+ * Sets the current ambient light mode.
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.WRITE_DREAM_STATE)
+ public void setAmbientLightMode(@AmbientLightMode int ambientLightMode) {
+ if (mLowLightDreamComponent == null) {
+ if (DEBUG) {
+ Log.d(TAG, "ignore ambient light mode change because low light dream component "
+ + "is empty");
+ }
+ return;
+ }
+
+ if (mAmbientLightMode == ambientLightMode) {
+ return;
+ }
+
+ if (DEBUG) {
+ Log.d(TAG, "ambient light mode changed from " + mAmbientLightMode + " to "
+ + ambientLightMode);
+ }
+
+ mAmbientLightMode = ambientLightMode;
+
+ mDreamManager.setSystemDreamComponent(mAmbientLightMode == AMBIENT_LIGHT_MODE_LOW_LIGHT
+ ? mLowLightDreamComponent : null);
+ }
+}
diff --git a/libs/dream/lowlight/src/com/android/dream/lowlight/dagger/LowLightDreamModule.java b/libs/dream/lowlight/src/com/android/dream/lowlight/dagger/LowLightDreamModule.java
new file mode 100644
index 0000000..c183a04
--- /dev/null
+++ b/libs/dream/lowlight/src/com/android/dream/lowlight/dagger/LowLightDreamModule.java
@@ -0,0 +1,61 @@
+/*
+ * 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.dream.lowlight.dagger;
+
+import android.app.DreamManager;
+import android.content.ComponentName;
+import android.content.Context;
+
+import androidx.annotation.Nullable;
+
+import com.android.dream.lowlight.R;
+
+import javax.inject.Named;
+
+import dagger.Module;
+import dagger.Provides;
+
+/**
+ * Dagger module for low light dream.
+ *
+ * @hide
+ */
+@Module
+public interface LowLightDreamModule {
+ String LOW_LIGHT_DREAM_COMPONENT = "low_light_dream_component";
+
+ /**
+ * Provides dream manager.
+ */
+ @Provides
+ static DreamManager providesDreamManager(Context context) {
+ return context.getSystemService(DreamManager.class);
+ }
+
+ /**
+ * Provides the component name of the low light dream, or null if not configured.
+ */
+ @Provides
+ @Named(LOW_LIGHT_DREAM_COMPONENT)
+ @Nullable
+ static ComponentName providesLowLightDreamComponent(Context context) {
+ final String lowLightDreamComponent = context.getResources().getString(
+ R.string.config_lowLightDreamComponent);
+ return lowLightDreamComponent.isEmpty() ? null
+ : ComponentName.unflattenFromString(lowLightDreamComponent);
+ }
+}
diff --git a/libs/dream/lowlight/tests/Android.bp b/libs/dream/lowlight/tests/Android.bp
new file mode 100644
index 0000000..bd6f05e
--- /dev/null
+++ b/libs/dream/lowlight/tests/Android.bp
@@ -0,0 +1,45 @@
+// 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 {
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_test {
+ name: "LowLightDreamTests",
+ srcs: [
+ "**/*.java",
+ ],
+ static_libs: [
+ "LowLightDreamLib",
+ "androidx.test.runner",
+ "androidx.test.rules",
+ "androidx.test.ext.junit",
+ "frameworks-base-testutils",
+ "junit",
+ "mockito-target-extended-minus-junit4",
+ "platform-test-annotations",
+ "testables",
+ "truth-prebuilt",
+ ],
+ libs: [
+ "android.test.mock",
+ "android.test.base",
+ "android.test.runner",
+ ],
+ jni_libs: [
+ "libdexmakerjvmtiagent",
+ "libstaticjvmtiagent",
+ ],
+}
diff --git a/libs/dream/lowlight/tests/AndroidManifest.xml b/libs/dream/lowlight/tests/AndroidManifest.xml
new file mode 100644
index 0000000..abb71fb
--- /dev/null
+++ b/libs/dream/lowlight/tests/AndroidManifest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ package="com.android.dream.lowlight.tests">
+
+ <application android:debuggable="true" android:largeHeap="true">
+ <uses-library android:name="android.test.mock" />
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:label="Tests for LowLightDreamLib"
+ android:targetPackage="com.android.dream.lowlight.tests">
+ </instrumentation>
+
+</manifest>
diff --git a/libs/dream/lowlight/tests/AndroidTest.xml b/libs/dream/lowlight/tests/AndroidTest.xml
new file mode 100644
index 0000000..1080033
--- /dev/null
+++ b/libs/dream/lowlight/tests/AndroidTest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<configuration description="Runs Tests for LowLightDreamLib">
+ <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="LowLightDreamTests.apk" />
+ </target_preparer>
+
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="framework-base-presubmit" />
+ <option name="test-tag" value="LowLightDreamLibTests" />
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="com.android.dream.lowlight.tests" />
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+ <option name="hidden-api-checks" value="false"/>
+ </test>
+</configuration>
diff --git a/libs/dream/lowlight/tests/src/com.android.dream.lowlight/LowLightDreamManagerTest.java b/libs/dream/lowlight/tests/src/com.android.dream.lowlight/LowLightDreamManagerTest.java
new file mode 100644
index 0000000..91a170f
--- /dev/null
+++ b/libs/dream/lowlight/tests/src/com.android.dream.lowlight/LowLightDreamManagerTest.java
@@ -0,0 +1,98 @@
+/*
+ * 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.dream.lowlight;
+
+import static com.android.dream.lowlight.LowLightDreamManager.AMBIENT_LIGHT_MODE_LOW_LIGHT;
+import static com.android.dream.lowlight.LowLightDreamManager.AMBIENT_LIGHT_MODE_REGULAR;
+import static com.android.dream.lowlight.LowLightDreamManager.AMBIENT_LIGHT_MODE_UNKNOWN;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import android.app.DreamManager;
+import android.content.ComponentName;
+import android.testing.AndroidTestingRunner;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class LowLightDreamManagerTest {
+ @Mock
+ private DreamManager mDreamManager;
+
+ @Mock
+ private ComponentName mDreamComponent;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ @Test
+ public void setAmbientLightMode_lowLight_setSystemDream() {
+ final LowLightDreamManager lowLightDreamManager = new LowLightDreamManager(mDreamManager,
+ mDreamComponent);
+
+ lowLightDreamManager.setAmbientLightMode(AMBIENT_LIGHT_MODE_LOW_LIGHT);
+
+ verify(mDreamManager).setSystemDreamComponent(mDreamComponent);
+ }
+
+ @Test
+ public void setAmbientLightMode_regularLight_clearSystemDream() {
+ final LowLightDreamManager lowLightDreamManager = new LowLightDreamManager(mDreamManager,
+ mDreamComponent);
+
+ lowLightDreamManager.setAmbientLightMode(AMBIENT_LIGHT_MODE_REGULAR);
+
+ verify(mDreamManager).setSystemDreamComponent(null);
+ }
+
+ @Test
+ public void setAmbientLightMode_defaultUnknownMode_clearSystemDream() {
+ final LowLightDreamManager lowLightDreamManager = new LowLightDreamManager(mDreamManager,
+ mDreamComponent);
+
+ // Set to low light first.
+ lowLightDreamManager.setAmbientLightMode(AMBIENT_LIGHT_MODE_LOW_LIGHT);
+ clearInvocations(mDreamManager);
+
+ // Return to default unknown mode.
+ lowLightDreamManager.setAmbientLightMode(AMBIENT_LIGHT_MODE_UNKNOWN);
+
+ verify(mDreamManager).setSystemDreamComponent(null);
+ }
+
+ @Test
+ public void setAmbientLightMode_dreamComponentNotSet_doNothing() {
+ final LowLightDreamManager lowLightDreamManager = new LowLightDreamManager(mDreamManager,
+ null /*dream component*/);
+
+ lowLightDreamManager.setAmbientLightMode(AMBIENT_LIGHT_MODE_LOW_LIGHT);
+
+ verify(mDreamManager, never()).setSystemDreamComponent(any());
+ }
+}
diff --git a/libs/hwui/FrameInfoVisualizer.cpp b/libs/hwui/FrameInfoVisualizer.cpp
index 3a8e559..687e4dd 100644
--- a/libs/hwui/FrameInfoVisualizer.cpp
+++ b/libs/hwui/FrameInfoVisualizer.cpp
@@ -179,7 +179,7 @@
void FrameInfoVisualizer::nextBarSegment(FrameInfoIndex start, FrameInfoIndex end) {
int fast_i = (mNumFastRects - 1) * 4;
int janky_i = (mNumJankyRects - 1) * 4;
- ;
+
for (size_t fi = 0; fi < mFrameSource.size(); fi++) {
if (mFrameSource[fi][FrameInfoIndex::Flags] & FrameInfoFlags::SkippedFrame) {
continue;
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 976117b..75d3ff7 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -512,9 +512,19 @@
ATRACE_FORMAT("Drawing " RECT_STRING, SK_RECT_ARGS(dirty));
- const auto drawResult = mRenderPipeline->draw(frame, windowDirty, dirty, mLightGeometry,
- &mLayerUpdateQueue, mContentDrawBounds, mOpaque,
- mLightInfo, mRenderNodes, &(profiler()));
+ IRenderPipeline::DrawResult drawResult;
+ {
+ // FrameInfoVisualizer accesses the frame events, which cannot be mutated mid-draw
+ // or it can lead to memory corruption.
+ // This lock is overly broad, but it's the quickest fix since this mutex is otherwise
+ // not visible to IRenderPipeline much less FrameInfoVisualizer. And since this is
+ // the thread we're primarily concerned about being responsive, this being too broad
+ // shouldn't pose a performance issue.
+ std::scoped_lock lock(mFrameMetricsReporterMutex);
+ drawResult = mRenderPipeline->draw(frame, windowDirty, dirty, mLightGeometry,
+ &mLayerUpdateQueue, mContentDrawBounds, mOpaque,
+ mLightInfo, mRenderNodes, &(profiler()));
+ }
uint64_t frameCompleteNr = getFrameNumber();
@@ -754,11 +764,11 @@
FrameInfo* frameInfo = instance->getFrameInfoFromLast4(frameNumber, surfaceControlId);
if (frameInfo != nullptr) {
+ std::scoped_lock lock(instance->mFrameMetricsReporterMutex);
frameInfo->set(FrameInfoIndex::FrameCompleted) = std::max(gpuCompleteTime,
frameInfo->get(FrameInfoIndex::SwapBuffersCompleted));
frameInfo->set(FrameInfoIndex::GpuCompleted) = std::max(
gpuCompleteTime, frameInfo->get(FrameInfoIndex::CommandSubmissionCompleted));
- std::scoped_lock lock(instance->mFrameMetricsReporterMutex);
instance->mJankTracker.finishFrame(*frameInfo, instance->mFrameMetricsReporter, frameNumber,
surfaceControlId);
}
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 650f360..7ccbe51 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -2385,6 +2385,14 @@
return types.size() == 1 && types.contains(type);
}
+ /**
+ * @hide
+ * Return true if the audio device type is a Bluetooth LE Audio device.
+ */
+ public static boolean isLeAudioDeviceType(int type) {
+ return DEVICE_OUT_ALL_BLE_SET.contains(type);
+ }
+
/** @hide */
public static final int DEFAULT_MUTE_STREAMS_AFFECTED =
(1 << STREAM_MUSIC) |
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index e18642c..0c8cacd 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -79,20 +79,24 @@
/**
* This is a class for reading and writing Exif tags in various image file formats.
* <p>
+ * <b>Note:</b> This class has known issues on some versions of Android. It is recommended to use
+ * the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
+ * <a href="{@docRoot}reference/androidx/exifinterface/media/ExifInterface.html">ExifInterface
+ * Library</a> since it offers a superset of the functionality of this class and is more easily
+ * updateable. In addition to the functionality of this class, it supports parsing extra metadata
+ * such as exposure and data compression information as well as setting extra metadata such as GPS
+ * and datetime information.
+ * <p>
* Supported for reading: JPEG, PNG, WebP, HEIF, DNG, CR2, NEF, NRW, ARW, RW2, ORF, PEF, SRW, RAF,
* AVIF.
* <p>
- * Supported for writing: JPEG, PNG, WebP, DNG.
+ * Supported for writing: JPEG, PNG, WebP.
* <p>
* Note: JPEG and HEIF files may contain XMP data either inside the Exif data chunk or outside of
* it. This class will search both locations for XMP data, but if XMP data exist both inside and
* outside Exif, will favor the XMP data inside Exif over the one outside.
* <p>
- * Note: It is recommended to use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
- * <a href="{@docRoot}reference/androidx/exifinterface/media/ExifInterface.html">ExifInterface
- * Library</a> since it is a superset of this class. In addition to the functionalities of this
- * class, it supports parsing extra metadata such as exposure and data compression information
- * as well as setting extra metadata such as GPS and datetime information.
+
*/
public class ExifInterface {
private static final String TAG = "ExifInterface";
@@ -1294,7 +1298,6 @@
new ExifTag(TAG_Y_CB_CR_SUB_SAMPLING, 530, IFD_FORMAT_USHORT),
new ExifTag(TAG_Y_CB_CR_POSITIONING, 531, IFD_FORMAT_USHORT),
new ExifTag(TAG_REFERENCE_BLACK_WHITE, 532, IFD_FORMAT_URATIONAL),
- new ExifTag(TAG_XMP, 700, IFD_FORMAT_BYTE),
new ExifTag(TAG_COPYRIGHT, 33432, IFD_FORMAT_STRING),
new ExifTag(TAG_EXIF_IFD_POINTER, 34665, IFD_FORMAT_ULONG),
new ExifTag(TAG_GPS_INFO_IFD_POINTER, 34853, IFD_FORMAT_ULONG),
@@ -2076,7 +2079,7 @@
* {@link #setAttribute(String,String)} to set all attributes to write and
* make a single call rather than multiple calls for each attribute.
* <p>
- * This method is supported for JPEG, PNG, WebP, and DNG files.
+ * This method is supported for JPEG, PNG, and WebP files.
* <p class="note">
* Note: after calling this method, any attempts to obtain range information
* from {@link #getAttributeRange(String)} or {@link #getThumbnailRange()}
@@ -2088,11 +2091,15 @@
* <p>
* For PNG format, the Exif data will be stored as an "eXIf" chunk as per
* "Extensions to the PNG 1.2 Specification, Version 1.5.0".
+ * <p>
+ * <b>Warning:</b> Calling this method on a DNG-based instance of {@code ExifInterface} may
+ * result in the original image file being overwritten with invalid data on some versions of
+ * Android 13 (API 33).
*/
public void saveAttributes() throws IOException {
if (!isSupportedFormatForSavingAttributes()) {
throw new IOException("ExifInterface only supports saving attributes for JPEG, PNG, "
- + "WebP, and DNG formats.");
+ + "and WebP formats.");
}
if (mIsInputStream || (mSeekableFileDescriptor == null && mFilename == null)) {
throw new IOException(
@@ -2150,10 +2157,6 @@
savePngAttributes(bufferedIn, bufferedOut);
} else if (mMimeType == IMAGE_TYPE_WEBP) {
saveWebpAttributes(bufferedIn, bufferedOut);
- } else if (mMimeType == IMAGE_TYPE_DNG || mMimeType == IMAGE_TYPE_UNKNOWN) {
- ByteOrderedDataOutputStream dataOutputStream =
- new ByteOrderedDataOutputStream(bufferedOut, ByteOrder.BIG_ENDIAN);
- writeExifSegment(dataOutputStream);
}
}
} catch (Exception e) {
@@ -5262,8 +5265,7 @@
private boolean isSupportedFormatForSavingAttributes() {
if (mIsSupportedFile && (mMimeType == IMAGE_TYPE_JPEG || mMimeType == IMAGE_TYPE_PNG
- || mMimeType == IMAGE_TYPE_WEBP || mMimeType == IMAGE_TYPE_DNG
- || mMimeType == IMAGE_TYPE_UNKNOWN)) {
+ || mMimeType == IMAGE_TYPE_WEBP)) {
return true;
}
return false;
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index c08f5a2..220232d 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -3835,11 +3835,10 @@
private void invalidateByteBufferLocked(
@Nullable ByteBuffer[] buffers, int index, boolean input) {
if (buffers == null) {
- if (index < 0) {
- throw new IllegalStateException("index is negative (" + index + ")");
+ if (index >= 0) {
+ BitSet indices = input ? mValidInputIndices : mValidOutputIndices;
+ indices.clear(index);
}
- BitSet indices = input ? mValidInputIndices : mValidOutputIndices;
- indices.clear(index);
} else if (index >= 0 && index < buffers.length) {
ByteBuffer buffer = buffers[index];
if (buffer != null) {
@@ -3851,10 +3850,9 @@
private void validateInputByteBufferLocked(
@Nullable ByteBuffer[] buffers, int index) {
if (buffers == null) {
- if (index < 0) {
- throw new IllegalStateException("index is negative (" + index + ")");
+ if (index >= 0) {
+ mValidInputIndices.set(index);
}
- mValidInputIndices.set(index);
} else if (index >= 0 && index < buffers.length) {
ByteBuffer buffer = buffers[index];
if (buffer != null) {
@@ -3868,11 +3866,10 @@
@Nullable ByteBuffer[] buffers, int index, boolean input) {
synchronized(mBufferLock) {
if (buffers == null) {
- if (index < 0) {
- throw new IllegalStateException("index is negative (" + index + ")");
+ if (index >= 0) {
+ BitSet indices = input ? mValidInputIndices : mValidOutputIndices;
+ indices.set(index);
}
- BitSet indices = input ? mValidInputIndices : mValidOutputIndices;
- indices.set(index);
} else if (index >= 0 && index < buffers.length) {
ByteBuffer buffer = buffers[index];
if (buffer != null) {
@@ -3885,10 +3882,9 @@
private void validateOutputByteBufferLocked(
@Nullable ByteBuffer[] buffers, int index, @NonNull BufferInfo info) {
if (buffers == null) {
- if (index < 0) {
- throw new IllegalStateException("index is negative (" + index + ")");
+ if (index >= 0) {
+ mValidOutputIndices.set(index);
}
- mValidOutputIndices.set(index);
} else if (index >= 0 && index < buffers.length) {
ByteBuffer buffer = buffers[index];
if (buffer != null) {
diff --git a/media/java/android/media/Ringtone.java b/media/java/android/media/Ringtone.java
index 86a94a9..82c3139 100644
--- a/media/java/android/media/Ringtone.java
+++ b/media/java/android/media/Ringtone.java
@@ -29,11 +29,12 @@
import android.os.Binder;
import android.os.Build;
import android.os.RemoteException;
+import android.os.Trace;
import android.provider.MediaStore;
import android.provider.MediaStore.MediaColumns;
import android.provider.Settings;
import android.util.Log;
-
+import com.android.internal.annotations.VisibleForTesting;
import java.io.IOException;
import java.util.ArrayList;
@@ -136,13 +137,73 @@
*/
public void setAudioAttributes(AudioAttributes attributes)
throws IllegalArgumentException {
+ setAudioAttributesField(attributes);
+ // The audio attributes have to be set before the media player is prepared.
+ // Re-initialize it.
+ setUri(mUri, mVolumeShaperConfig);
+ createLocalMediaPlayer();
+ }
+
+ /**
+ * Same as {@link #setAudioAttributes(AudioAttributes)} except this one does not create
+ * the media player.
+ * @hide
+ */
+ public void setAudioAttributesField(@Nullable AudioAttributes attributes) {
if (attributes == null) {
throw new IllegalArgumentException("Invalid null AudioAttributes for Ringtone");
}
mAudioAttributes = attributes;
- // The audio attributes have to be set before the media player is prepared.
- // Re-initialize it.
- setUri(mUri, mVolumeShaperConfig);
+ }
+
+ /**
+ * Creates a local media player for the ringtone using currently set attributes.
+ * @hide
+ */
+ public void createLocalMediaPlayer() {
+ Trace.beginSection("createLocalMediaPlayer");
+ if (mUri == null) {
+ Log.e(TAG, "Could not create media player as no URI was provided.");
+ return;
+ }
+ destroyLocalPlayer();
+ // try opening uri locally before delegating to remote player
+ mLocalPlayer = new MediaPlayer();
+ try {
+ mLocalPlayer.setDataSource(mContext, mUri);
+ mLocalPlayer.setAudioAttributes(mAudioAttributes);
+ synchronized (mPlaybackSettingsLock) {
+ applyPlaybackProperties_sync();
+ }
+ if (mVolumeShaperConfig != null) {
+ mVolumeShaper = mLocalPlayer.createVolumeShaper(mVolumeShaperConfig);
+ }
+ mLocalPlayer.prepare();
+
+ } catch (SecurityException | IOException e) {
+ destroyLocalPlayer();
+ if (!mAllowRemote) {
+ Log.w(TAG, "Remote playback not allowed: " + e);
+ }
+ }
+
+ if (LOGD) {
+ if (mLocalPlayer != null) {
+ Log.d(TAG, "Successfully created local player");
+ } else {
+ Log.d(TAG, "Problem opening; delegating to remote player");
+ }
+ }
+ Trace.endSection();
+ }
+
+ /**
+ * Returns whether a local player has been created for this ringtone.
+ * @hide
+ */
+ @VisibleForTesting
+ public boolean hasLocalPlayer() {
+ return mLocalPlayer != null;
}
/**
@@ -336,8 +397,7 @@
}
/**
- * Set {@link Uri} to be used for ringtone playback. Attempts to open
- * locally, otherwise will delegate playback to remote
+ * Set {@link Uri} to be used for ringtone playback.
* {@link IRingtonePlayer}.
*
* @hide
@@ -348,6 +408,13 @@
}
/**
+ * @hide
+ */
+ public void setVolumeShaperConfig(@Nullable VolumeShaper.Configuration volumeShaperConfig) {
+ mVolumeShaperConfig = volumeShaperConfig;
+ }
+
+ /**
* Set {@link Uri} to be used for ringtone playback. Attempts to open
* locally, otherwise will delegate playback to remote
* {@link IRingtonePlayer}. Add {@link VolumeShaper} if required.
@@ -356,41 +423,10 @@
*/
public void setUri(Uri uri, @Nullable VolumeShaper.Configuration volumeShaperConfig) {
mVolumeShaperConfig = volumeShaperConfig;
- destroyLocalPlayer();
mUri = uri;
if (mUri == null) {
- return;
- }
-
- // TODO: detect READ_EXTERNAL and specific content provider case, instead of relying on throwing
-
- // try opening uri locally before delegating to remote player
- mLocalPlayer = new MediaPlayer();
- try {
- mLocalPlayer.setDataSource(mContext, mUri);
- mLocalPlayer.setAudioAttributes(mAudioAttributes);
- synchronized (mPlaybackSettingsLock) {
- applyPlaybackProperties_sync();
- }
- if (mVolumeShaperConfig != null) {
- mVolumeShaper = mLocalPlayer.createVolumeShaper(mVolumeShaperConfig);
- }
- mLocalPlayer.prepare();
-
- } catch (SecurityException | IOException e) {
destroyLocalPlayer();
- if (!mAllowRemote) {
- Log.w(TAG, "Remote playback not allowed: " + e);
- }
- }
-
- if (LOGD) {
- if (mLocalPlayer != null) {
- Log.d(TAG, "Successfully created local player");
- } else {
- Log.d(TAG, "Problem opening; delegating to remote player");
- }
}
}
diff --git a/media/java/android/media/RingtoneManager.java b/media/java/android/media/RingtoneManager.java
index 2772769..27db41c 100644
--- a/media/java/android/media/RingtoneManager.java
+++ b/media/java/android/media/RingtoneManager.java
@@ -480,8 +480,9 @@
if (mStopPreviousRingtone && mPreviousRingtone != null) {
mPreviousRingtone.stop();
}
-
- mPreviousRingtone = getRingtone(mContext, getRingtoneUri(position), inferStreamType());
+
+ mPreviousRingtone =
+ getRingtone(mContext, getRingtoneUri(position), inferStreamType(), true);
return mPreviousRingtone;
}
@@ -677,7 +678,7 @@
*/
public static Ringtone getRingtone(final Context context, Uri ringtoneUri) {
// Don't set the stream type
- return getRingtone(context, ringtoneUri, -1);
+ return getRingtone(context, ringtoneUri, -1, true);
}
/**
@@ -698,7 +699,34 @@
final Context context, Uri ringtoneUri,
@Nullable VolumeShaper.Configuration volumeShaperConfig) {
// Don't set the stream type
- return getRingtone(context, ringtoneUri, -1 /* streamType */, volumeShaperConfig);
+ return getRingtone(context, ringtoneUri, -1 /* streamType */, volumeShaperConfig, true);
+ }
+
+ /**
+ * @hide
+ */
+ public static Ringtone getRingtone(final Context context, Uri ringtoneUri,
+ @Nullable VolumeShaper.Configuration volumeShaperConfig,
+ boolean createLocalMediaPlayer) {
+ // Don't set the stream type
+ return getRingtone(context, ringtoneUri, -1 /* streamType */, volumeShaperConfig,
+ createLocalMediaPlayer);
+ }
+
+ /**
+ * @hide
+ */
+ public static Ringtone getRingtone(final Context context, Uri ringtoneUri,
+ @Nullable VolumeShaper.Configuration volumeShaperConfig,
+ AudioAttributes audioAttributes) {
+ // Don't set the stream type
+ Ringtone ringtone =
+ getRingtone(context, ringtoneUri, -1 /* streamType */, volumeShaperConfig, false);
+ if (ringtone != null) {
+ ringtone.setAudioAttributesField(audioAttributes);
+ ringtone.createLocalMediaPlayer();
+ }
+ return ringtone;
}
//FIXME bypass the notion of stream types within the class
@@ -707,14 +735,19 @@
* type. Normally, if you change the stream type on the returned
* {@link Ringtone}, it will re-create the {@link MediaPlayer}. This is just
* an optimized route to avoid that.
- *
+ *
* @param streamType The stream type for the ringtone, or -1 if it should
* not be set (and the default used instead).
+ * @param createLocalMediaPlayer when true, the ringtone returned will be fully
+ * created otherwise, it will require the caller to create the media player manually
+ * {@link Ringtone#createLocalMediaPlayer()} in order to play the Ringtone.
* @see #getRingtone(Context, Uri)
*/
@UnsupportedAppUsage
- private static Ringtone getRingtone(final Context context, Uri ringtoneUri, int streamType) {
- return getRingtone(context, ringtoneUri, streamType, null /* volumeShaperConfig */);
+ private static Ringtone getRingtone(final Context context, Uri ringtoneUri, int streamType,
+ boolean createLocalMediaPlayer) {
+ return getRingtone(context, ringtoneUri, streamType, null /* volumeShaperConfig */,
+ createLocalMediaPlayer);
}
//FIXME bypass the notion of stream types within the class
@@ -730,16 +763,21 @@
* @see #getRingtone(Context, Uri)
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- private static Ringtone getRingtone(
- final Context context, Uri ringtoneUri, int streamType,
- @Nullable VolumeShaper.Configuration volumeShaperConfig) {
+ private static Ringtone getRingtone(final Context context, Uri ringtoneUri, int streamType,
+ @Nullable VolumeShaper.Configuration volumeShaperConfig,
+ boolean createLocalMediaPlayer) {
try {
final Ringtone r = new Ringtone(context, true);
if (streamType >= 0) {
//FIXME deprecated call
r.setStreamType(streamType);
}
+
+ r.setVolumeShaperConfig(volumeShaperConfig);
r.setUri(ringtoneUri, volumeShaperConfig);
+ if (createLocalMediaPlayer) {
+ r.createLocalMediaPlayer();
+ }
return r;
} catch (Exception ex) {
Log.e(TAG, "Failed to open ringtone " + ringtoneUri + ": " + ex);
diff --git a/packages/BackupRestoreConfirmation/res/values-or/strings.xml b/packages/BackupRestoreConfirmation/res/values-or/strings.xml
index 1c54569..cb61092 100644
--- a/packages/BackupRestoreConfirmation/res/values-or/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-or/strings.xml
@@ -20,7 +20,7 @@
<string name="restore_confirm_title" msgid="5469365809567486602">"ସମ୍ପୂର୍ଣ୍ଣ ରିଷ୍ଟୋର୍"</string>
<string name="backup_confirm_text" msgid="1878021282758896593">"ଏକ ସଂଯୁକ୍ତ ଡେସ୍କଟପ୍ କମ୍ପ୍ୟୁଟର୍କୁ ସମସ୍ତ ଡାଟାର ସମ୍ପୂର୍ଣ୍ଣ ବ୍ୟାକଅପ୍ କରିବାକୁ ଅନୁରୋଧ କରାଯାଇଛି। ଆପଣ ଏହିପରି କରିବାକୁ ଚାହିଁବେ?\n\nଯଦି ଆପଣ ନିଜେ ବ୍ୟାକଅପ୍ର ଅନୁରୋଧ କରିନାହାନ୍ତି, ତେବେ ଏହି କାମକୁ ଆଗକୁ ବଢ଼ିବାକୁ ଦିଅନ୍ତୁ ନାହିଁ।"</string>
<string name="allow_backup_button_label" msgid="4217228747769644068">"ମୋ ଡାଟାର ବ୍ୟାକଅପ୍ ନିଆଯାଉ"</string>
- <string name="deny_backup_button_label" msgid="6009119115581097708">"ବ୍ୟାକଅପ୍ ନିଆନଯାଉ"</string>
+ <string name="deny_backup_button_label" msgid="6009119115581097708">"ବେକଅପ ନିଅନ୍ତୁ ନାହିଁ"</string>
<string name="restore_confirm_text" msgid="7499866728030461776">"ଏକ ସଂଯୁକ୍ତ ଡେସ୍କଟପ୍ କମ୍ପ୍ୟୁଟର୍ରୁ ସମସ୍ତ ଡାଟାର ସମ୍ପୂର୍ଣ୍ଣ ରିଷ୍ଟୋର୍ ଅନୁରୋଧ କରାଯାଇଛି। ଆପଣ ଏହାକୁ ଅନୁମତି ଦେବାକୁ ଚାହିଁବେ କି?\n\nଯଦି ଆପଣ ନିଜେ ରିଷ୍ଟୋର୍ ଅନୁରୋଧ କରିନାହାନ୍ତି, ତେବେ ଏହା କାର୍ଯ୍ୟକୁ ଆଗକୁ ବଢ଼ିବାକୁ ଦିଅନ୍ତୁ ନାହିଁ। ଏହା ବର୍ତ୍ତମାନ ଡିଭାଇସ୍ରେ ଥିବା ଯେକୌଣସି ଡାଟାକୁ ବଦଳାଇଦେବ!"</string>
<string name="allow_restore_button_label" msgid="3081286752277127827">"ମୋ ଡାଟାକୁ ରିଷ୍ଟୋର୍ କରାଯାଉ"</string>
<string name="deny_restore_button_label" msgid="1724367334453104378">"ରିଷ୍ଟୋର୍ କରନ୍ତୁ ନାହିଁ।"</string>
diff --git a/packages/BackupRestoreConfirmation/res/values-pt-rPT/strings.xml b/packages/BackupRestoreConfirmation/res/values-pt-rPT/strings.xml
index a1e6167..1f6be83 100644
--- a/packages/BackupRestoreConfirmation/res/values-pt-rPT/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-pt-rPT/strings.xml
@@ -20,7 +20,7 @@
<string name="restore_confirm_title" msgid="5469365809567486602">"Restauro completo"</string>
<string name="backup_confirm_text" msgid="1878021282758896593">"Foi solicitada uma cópia de segurança completa de todos os dados para um computador. Permitir esta operação?\n\nCaso não tenha solicitado a cópia de segurança, não permita que a operação prossiga."</string>
<string name="allow_backup_button_label" msgid="4217228747769644068">"Fazer cópia de seg. dos dados"</string>
- <string name="deny_backup_button_label" msgid="6009119115581097708">"Não efetuar cópia de seg."</string>
+ <string name="deny_backup_button_label" msgid="6009119115581097708">"Não fazer cópia de seg."</string>
<string name="restore_confirm_text" msgid="7499866728030461776">"Foi solicitado um restauro completo de todos os dados a partir de um computador. Permitir esta operação?\n\nCaso não tenha solicitado o restauro, não permita que a operação prossiga. Isto substituirá os dados existentes no equipamento!"</string>
<string name="allow_restore_button_label" msgid="3081286752277127827">"Restaurar os meus dados"</string>
<string name="deny_restore_button_label" msgid="1724367334453104378">"Não restaurar"</string>
diff --git a/packages/CompanionDeviceManager/res/values-hi/strings.xml b/packages/CompanionDeviceManager/res/values-hi/strings.xml
index ef21b6d..c5ef913 100644
--- a/packages/CompanionDeviceManager/res/values-hi/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hi/strings.xml
@@ -34,7 +34,7 @@
<string name="permission_notification_summary" msgid="884075314530071011">"इससे सभी सूचनाएं देखी जा सकती हैं. इसमें संपर्क, मैसेज, और फ़ोटो जैसी जानकारी शामिल होती है"</string>
<string name="permission_storage" msgid="6831099350839392343">"फ़ोटो और मीडिया"</string>
<string name="permission_storage_summary" msgid="3918240895519506417"></string>
- <string name="helper_title_computer" msgid="4671071173916176037">"Google Play सेवाएं"</string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Google Play services"</string>
<string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> आपके <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> की ओर से, फ़ोन में मौजूद फ़ोटो, मीडिया, और सूचनाओं को ऐक्सेस करने की अनुमति मांग रहा है"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"डिवाइस"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
diff --git a/packages/CompanionDeviceManager/res/values-ko/strings.xml b/packages/CompanionDeviceManager/res/values-ko/strings.xml
index 4af740e..525896b 100644
--- a/packages/CompanionDeviceManager/res/values-ko/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ko/strings.xml
@@ -23,7 +23,7 @@
<string name="summary_watch" msgid="3002344206574997652">"이 앱은 <xliff:g id="DEVICE_NAME">%1$s</xliff:g> 프로필을 관리하는 데 필요합니다. <xliff:g id="APP_NAME">%2$s</xliff:g>에서 알림과 상호작용하고 내 전화, SMS, 연락처, Calendar, 통화 기록, 근처 기기에 대한 권한을 갖게 됩니다."</string>
<string name="permission_apps" msgid="6142133265286656158">"앱"</string>
<string name="permission_apps_summary" msgid="798718816711515431">"휴대전화의 앱을 스트리밍합니다."</string>
- <string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> 앱이 휴대전화에서 이 정보에 액세스하도록 허용합니다."</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>이 휴대전화의 이 정보에 액세스하도록 허용합니다."</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"교차 기기 서비스"</string>
<string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g>에서 <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> 대신 기기 간에 앱을 스트리밍할 수 있는 권한을 요청하고 있습니다."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
diff --git a/packages/CompanionDeviceManager/res/values-night/themes.xml b/packages/CompanionDeviceManager/res/values-night/themes.xml
index 6eb16e7..55e91b6 100644
--- a/packages/CompanionDeviceManager/res/values-night/themes.xml
+++ b/packages/CompanionDeviceManager/res/values-night/themes.xml
@@ -18,8 +18,8 @@
<style name="ChooserActivity"
parent="@android:style/Theme.DeviceDefault.Dialog.NoActionBar">
- <item name="*android:windowFixedHeightMajor">100%</item>
- <item name="*android:windowFixedHeightMinor">100%</item>
+ <item name="android:windowContentOverlay">@null</item>
+ <item name="android:windowNoTitle">true</item>
<item name="android:windowBackground">@android:color/transparent</item>
</style>
diff --git a/packages/CompanionDeviceManager/res/values-pl/strings.xml b/packages/CompanionDeviceManager/res/values-pl/strings.xml
index 1013566..88c0976 100644
--- a/packages/CompanionDeviceManager/res/values-pl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pl/strings.xml
@@ -23,7 +23,7 @@
<string name="summary_watch" msgid="3002344206574997652">"Ta aplikacja jest niezbędna do zarządzania profilem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. Aplikacja <xliff:g id="APP_NAME">%2$s</xliff:g> będzie mogła korzystać z powiadomień oraz uprawnień dotyczących telefonu, SMS-ów, kontaktów, kalendarza, rejestrów połączeń i urządzeń w pobliżu."</string>
<string name="permission_apps" msgid="6142133265286656158">"Aplikacje"</string>
<string name="permission_apps_summary" msgid="798718816711515431">"Odtwarzaj strumieniowo aplikacje z telefonu"</string>
- <string name="title_app_streaming" msgid="2270331024626446950">"Zezwól aplikacji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> na dostęp do tych informacji na Twoim telefonie"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Zezwól urządzeniu <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> na dostęp do tych informacji na Twoim telefonie"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Usługi na innym urządzeniu"</string>
<string name="helper_summary_app_streaming" msgid="5977509499890099">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> prosi w imieniu urządzenia <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> o uprawnienia dotyczące strumieniowego odtwarzania treści z aplikacji na innym urządzeniu"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
diff --git a/packages/InputDevices/res/values-hi/strings.xml b/packages/InputDevices/res/values-hi/strings.xml
index 55fc5bf..c3291a0 100644
--- a/packages/InputDevices/res/values-hi/strings.xml
+++ b/packages/InputDevices/res/values-hi/strings.xml
@@ -35,7 +35,7 @@
<string name="keyboard_layout_portuguese" msgid="2888198587329660305">"पुर्तगाली"</string>
<string name="keyboard_layout_slovak" msgid="2469379934672837296">"स्लोवाक"</string>
<string name="keyboard_layout_slovenian" msgid="1735933028924982368">"स्लोवेनियाई"</string>
- <string name="keyboard_layout_turkish" msgid="7736163250907964898">"तुर्की"</string>
+ <string name="keyboard_layout_turkish" msgid="7736163250907964898">"तुर्किये"</string>
<string name="keyboard_layout_turkish_f" msgid="9130320856010776018">"Turkish F"</string>
<string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"यूक्रेनियाई"</string>
<string name="keyboard_layout_arabic" msgid="5671970465174968712">"अरबी"</string>
diff --git a/packages/PrintSpooler/res/values-am/strings.xml b/packages/PrintSpooler/res/values-am/strings.xml
index 832b855..c1cec38 100644
--- a/packages/PrintSpooler/res/values-am/strings.xml
+++ b/packages/PrintSpooler/res/values-am/strings.xml
@@ -41,7 +41,7 @@
<string name="current_page_template" msgid="5145005201131935302">"<xliff:g id="CURRENT_PAGE">%1$d</xliff:g>/<xliff:g id="PAGE_COUNT">%2$d</xliff:g>"</string>
<string name="page_description_template" msgid="6831239682256197161">"ገጽ <xliff:g id="CURRENT_PAGE">%1$d</xliff:g> ከ<xliff:g id="PAGE_COUNT">%2$d</xliff:g>"</string>
<string name="summary_template" msgid="8899734908625669193">"ማጠቃለያ፣ ቅጂዎች <xliff:g id="COPIES">%1$s</xliff:g>፣ የወረቀት መጠን <xliff:g id="PAPER_SIZE">%2$s</xliff:g>"</string>
- <string name="expand_handle" msgid="7282974448109280522">"እጀታን ወደ ውጪ ላክ"</string>
+ <string name="expand_handle" msgid="7282974448109280522">"እጀታን ወደ ውጭ ላክ"</string>
<string name="collapse_handle" msgid="6886637989442507451">"እጀታን ሰብስብ"</string>
<string name="print_button" msgid="645164566271246268">"አትም"</string>
<string name="savetopdf_button" msgid="2976186791686924743">"ወደ ፔዲኤፍ አስቀምጥ"</string>
diff --git a/packages/PrintSpooler/res/values-es-rUS/strings.xml b/packages/PrintSpooler/res/values-es-rUS/strings.xml
index 441ae73..90c1937 100644
--- a/packages/PrintSpooler/res/values-es-rUS/strings.xml
+++ b/packages/PrintSpooler/res/values-es-rUS/strings.xml
@@ -56,6 +56,7 @@
<string name="print_select_printer" msgid="7388760939873368698">"Seleccionar impresora"</string>
<string name="print_forget_printer" msgid="5035287497291910766">"No recordar impresora"</string>
<plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+ <item quantity="many"><xliff:g id="COUNT_1">%1$s</xliff:g> printers found</item>
<item quantity="other">Se encontraron <xliff:g id="COUNT_1">%1$s</xliff:g> impresoras.</item>
<item quantity="one">Se encontró <xliff:g id="COUNT_0">%1$s</xliff:g> impresora.</item>
</plurals>
@@ -76,6 +77,7 @@
<string name="disabled_services_title" msgid="7313253167968363211">"Servicios inhabilitados"</string>
<string name="all_services_title" msgid="5578662754874906455">"Todos los servicios"</string>
<plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="many">Install to discover <xliff:g id="COUNT_1">%1$s</xliff:g> printers</item>
<item quantity="other">Instala para ver <xliff:g id="COUNT_1">%1$s</xliff:g> impresoras</item>
<item quantity="one">Instala para ver <xliff:g id="COUNT_0">%1$s</xliff:g> impresora</item>
</plurals>
diff --git a/packages/PrintSpooler/res/values-es/strings.xml b/packages/PrintSpooler/res/values-es/strings.xml
index c1ff282..18e56db 100644
--- a/packages/PrintSpooler/res/values-es/strings.xml
+++ b/packages/PrintSpooler/res/values-es/strings.xml
@@ -56,6 +56,7 @@
<string name="print_select_printer" msgid="7388760939873368698">"Seleccionar impresora"</string>
<string name="print_forget_printer" msgid="5035287497291910766">"Olvidar impresora"</string>
<plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+ <item quantity="many"><xliff:g id="COUNT_1">%1$s</xliff:g> printers found</item>
<item quantity="other">Se han encontrado <xliff:g id="COUNT_1">%1$s</xliff:g> impresoras</item>
<item quantity="one">Se ha encontrado <xliff:g id="COUNT_0">%1$s</xliff:g> impresora</item>
</plurals>
@@ -76,6 +77,7 @@
<string name="disabled_services_title" msgid="7313253167968363211">"Servicios inhabilitados"</string>
<string name="all_services_title" msgid="5578662754874906455">"Todos los servicios"</string>
<plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="many">Install to discover <xliff:g id="COUNT_1">%1$s</xliff:g> printers</item>
<item quantity="other">Instalar para descubrir <xliff:g id="COUNT_1">%1$s</xliff:g> impresoras</item>
<item quantity="one">Instalar para descubrir <xliff:g id="COUNT_0">%1$s</xliff:g> impresora</item>
</plurals>
diff --git a/packages/PrintSpooler/res/values-fr-rCA/strings.xml b/packages/PrintSpooler/res/values-fr-rCA/strings.xml
index 3b7775a..082c148 100644
--- a/packages/PrintSpooler/res/values-fr-rCA/strings.xml
+++ b/packages/PrintSpooler/res/values-fr-rCA/strings.xml
@@ -57,6 +57,7 @@
<string name="print_forget_printer" msgid="5035287497291910766">"Supprimer l\'imprimante"</string>
<plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
<item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> imprimante trouvée</item>
+ <item quantity="many"><xliff:g id="COUNT_1">%1$s</xliff:g> printers found</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> imprimante trouvées</item>
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
@@ -77,6 +78,7 @@
<string name="all_services_title" msgid="5578662754874906455">"Tous les services"</string>
<plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
<item quantity="one">Installer pour détecter <xliff:g id="COUNT_1">%1$s</xliff:g> imprimante</item>
+ <item quantity="many">Install to discover <xliff:g id="COUNT_1">%1$s</xliff:g> printers</item>
<item quantity="other">Installer pour détecter <xliff:g id="COUNT_1">%1$s</xliff:g> imprimantes</item>
</plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Impression de <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> en cours…"</string>
diff --git a/packages/PrintSpooler/res/values-fr/strings.xml b/packages/PrintSpooler/res/values-fr/strings.xml
index f6e901d..560c5dc 100644
--- a/packages/PrintSpooler/res/values-fr/strings.xml
+++ b/packages/PrintSpooler/res/values-fr/strings.xml
@@ -57,6 +57,7 @@
<string name="print_forget_printer" msgid="5035287497291910766">"Supprimer l\'imprimante"</string>
<plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
<item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> imprimante trouvée</item>
+ <item quantity="many"><xliff:g id="COUNT_1">%1$s</xliff:g> printers found</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> imprimantes trouvées</item>
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
@@ -77,6 +78,7 @@
<string name="all_services_title" msgid="5578662754874906455">"Tous les services"</string>
<plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
<item quantity="one">Installer pour détecter <xliff:g id="COUNT_1">%1$s</xliff:g> imprimante</item>
+ <item quantity="many">Install to discover <xliff:g id="COUNT_1">%1$s</xliff:g> printers</item>
<item quantity="other">Installer pour détecter <xliff:g id="COUNT_1">%1$s</xliff:g> imprimantes</item>
</plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Impression de \"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>\" en cours…"</string>
diff --git a/packages/PrintSpooler/res/values-it/strings.xml b/packages/PrintSpooler/res/values-it/strings.xml
index 96751ea..569bbc2 100644
--- a/packages/PrintSpooler/res/values-it/strings.xml
+++ b/packages/PrintSpooler/res/values-it/strings.xml
@@ -56,6 +56,7 @@
<string name="print_select_printer" msgid="7388760939873368698">"Seleziona stampante"</string>
<string name="print_forget_printer" msgid="5035287497291910766">"Elimina stampante"</string>
<plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+ <item quantity="many"><xliff:g id="COUNT_1">%1$s</xliff:g> printers found</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> stampanti trovate</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> stampante trovata</item>
</plurals>
@@ -76,6 +77,7 @@
<string name="disabled_services_title" msgid="7313253167968363211">"Servizi disattivati"</string>
<string name="all_services_title" msgid="5578662754874906455">"Tutti i servizi"</string>
<plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="many">Install to discover <xliff:g id="COUNT_1">%1$s</xliff:g> printers</item>
<item quantity="other">Installa per rilevare <xliff:g id="COUNT_1">%1$s</xliff:g> stampanti</item>
<item quantity="one">Installa per rilevare <xliff:g id="COUNT_0">%1$s</xliff:g> stampante</item>
</plurals>
diff --git a/packages/PrintSpooler/res/values-pt-rBR/strings.xml b/packages/PrintSpooler/res/values-pt-rBR/strings.xml
index 6ce4636..3b460a1 100644
--- a/packages/PrintSpooler/res/values-pt-rBR/strings.xml
+++ b/packages/PrintSpooler/res/values-pt-rBR/strings.xml
@@ -57,6 +57,7 @@
<string name="print_forget_printer" msgid="5035287497291910766">"Esquecer impressora"</string>
<plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
<item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> impressoras encontradas</item>
+ <item quantity="many"><xliff:g id="COUNT_1">%1$s</xliff:g> printers found</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> impressoras encontradas</item>
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
@@ -77,6 +78,7 @@
<string name="all_services_title" msgid="5578662754874906455">"Todos os serviços"</string>
<plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
<item quantity="one">Instale para encontrar <xliff:g id="COUNT_1">%1$s</xliff:g> impressoras</item>
+ <item quantity="many">Install to discover <xliff:g id="COUNT_1">%1$s</xliff:g> printers</item>
<item quantity="other">Instale para encontrar <xliff:g id="COUNT_1">%1$s</xliff:g> impressoras</item>
</plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Imprimindo <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-pt-rPT/strings.xml b/packages/PrintSpooler/res/values-pt-rPT/strings.xml
index 4517efe..8c1087e 100644
--- a/packages/PrintSpooler/res/values-pt-rPT/strings.xml
+++ b/packages/PrintSpooler/res/values-pt-rPT/strings.xml
@@ -56,6 +56,7 @@
<string name="print_select_printer" msgid="7388760939873368698">"Selecionar impressora"</string>
<string name="print_forget_printer" msgid="5035287497291910766">"Esquecer impressora"</string>
<plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+ <item quantity="many"><xliff:g id="COUNT_1">%1$s</xliff:g> printers found</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> impressoras encontradas</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> impressora encontrada</item>
</plurals>
@@ -76,6 +77,7 @@
<string name="disabled_services_title" msgid="7313253167968363211">"Serviços desativados"</string>
<string name="all_services_title" msgid="5578662754874906455">"Todos os serviços"</string>
<plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="many">Install to discover <xliff:g id="COUNT_1">%1$s</xliff:g> printers</item>
<item quantity="other">Instale para detetar <xliff:g id="COUNT_1">%1$s</xliff:g> impressoras</item>
<item quantity="one">Instale para detetar <xliff:g id="COUNT_0">%1$s</xliff:g> impressora</item>
</plurals>
diff --git a/packages/PrintSpooler/res/values-pt/strings.xml b/packages/PrintSpooler/res/values-pt/strings.xml
index 6ce4636..3b460a1 100644
--- a/packages/PrintSpooler/res/values-pt/strings.xml
+++ b/packages/PrintSpooler/res/values-pt/strings.xml
@@ -57,6 +57,7 @@
<string name="print_forget_printer" msgid="5035287497291910766">"Esquecer impressora"</string>
<plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
<item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> impressoras encontradas</item>
+ <item quantity="many"><xliff:g id="COUNT_1">%1$s</xliff:g> printers found</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> impressoras encontradas</item>
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
@@ -77,6 +78,7 @@
<string name="all_services_title" msgid="5578662754874906455">"Todos os serviços"</string>
<plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
<item quantity="one">Instale para encontrar <xliff:g id="COUNT_1">%1$s</xliff:g> impressoras</item>
+ <item quantity="many">Install to discover <xliff:g id="COUNT_1">%1$s</xliff:g> printers</item>
<item quantity="other">Instale para encontrar <xliff:g id="COUNT_1">%1$s</xliff:g> impressoras</item>
</plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Imprimindo <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/IllustrationPreference/res/values/colors.xml b/packages/SettingsLib/IllustrationPreference/res/values/colors.xml
index ead5174..0de7be0 100644
--- a/packages/SettingsLib/IllustrationPreference/res/values/colors.xml
+++ b/packages/SettingsLib/IllustrationPreference/res/values/colors.xml
@@ -43,6 +43,8 @@
<color name="settingslib_color_grey400">#bdc1c6</color>
<color name="settingslib_color_grey300">#dadce0</color>
<color name="settingslib_color_grey200">#e8eaed</color>
+ <color name="settingslib_color_grey100">#f1f3f4</color>
+ <color name="settingslib_color_grey50">#f8f9fa</color>
<color name="settingslib_color_orange600">#e8710a</color>
<color name="settingslib_color_orange400">#fa903e</color>
<color name="settingslib_color_orange300">#fcad70</color>
diff --git a/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/LottieColorUtils.java b/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/LottieColorUtils.java
new file mode 100644
index 0000000..93b6acc
--- /dev/null
+++ b/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/LottieColorUtils.java
@@ -0,0 +1,88 @@
+/*
+ * 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.settingslib.widget;
+
+import android.content.Context;
+import android.content.res.Configuration;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
+
+import com.airbnb.lottie.LottieAnimationView;
+import com.airbnb.lottie.LottieProperty;
+import com.airbnb.lottie.model.KeyPath;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Util class which dynamically changes the color of tags in a lottie json file between Dark Theme
+ * (DT) and Light Theme (LT). This class assumes the json file is for Dark Theme.
+ */
+public class LottieColorUtils {
+ private static final Map<String, Integer> DARK_TO_LIGHT_THEME_COLOR_MAP;
+
+ static {
+ HashMap<String, Integer> map = new HashMap<>();
+ map.put(
+ ".grey600",
+ R.color.settingslib_color_grey300);
+ map.put(
+ ".grey800",
+ R.color.settingslib_color_grey200);
+ map.put(
+ ".grey900",
+ R.color.settingslib_color_grey50);
+ map.put(
+ ".red400",
+ R.color.settingslib_color_red600);
+ map.put(
+ ".black",
+ android.R.color.white);
+ map.put(
+ ".blue400",
+ R.color.settingslib_color_blue600);
+ map.put(
+ ".green400",
+ R.color.settingslib_color_green600);
+ DARK_TO_LIGHT_THEME_COLOR_MAP = Collections.unmodifiableMap(map);
+ }
+
+ private LottieColorUtils() {
+ }
+
+ private static boolean isDarkMode(Context context) {
+ return (context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK)
+ == Configuration.UI_MODE_NIGHT_YES;
+ }
+
+ /** Applies dynamic colors based on DT vs. LT. The LottieAnimationView should be Dark Theme. */
+ public static void applyDynamicColors(Context context,
+ LottieAnimationView lottieAnimationView) {
+ // Assume the default for the lottie is dark mode
+ if (isDarkMode(context)) {
+ return;
+ }
+ for (String key : DARK_TO_LIGHT_THEME_COLOR_MAP.keySet()) {
+ final int color = context.getColor(DARK_TO_LIGHT_THEME_COLOR_MAP.get(key));
+ lottieAnimationView.addValueCallback(
+ new KeyPath("**", key, "**"),
+ LottieProperty.COLOR_FILTER,
+ frameInfo -> new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_ATOP));
+ }
+ }
+}
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index 84c5a69..e050ae0 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -597,7 +597,7 @@
<string name="guest_reset_guest" msgid="6110013010356013758">"கெஸ்ட் அமர்வை மீட்டமை"</string>
<string name="guest_reset_guest_dialog_title" msgid="8047270010895437534">"கெஸ்ட்டை மீட்டமைக்கவா?"</string>
<string name="guest_remove_guest_dialog_title" msgid="4548511006624088072">"கெஸ்ட் பயனரை அகற்றவா?"</string>
- <string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"மீட்டமை"</string>
+ <string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"ரீசெட்"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"அகற்று"</string>
<string name="guest_resetting" msgid="7822120170191509566">"கெஸ்ட்டை மீட்டமைக்கிறது…"</string>
<string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"கெஸ்ட் அமர்வை ரீசெட் செய்யவா?"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index 3ca94db..a5f3df9 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -398,6 +398,7 @@
* @param id the group id from the CSIP.
*/
public void setGroupId(int id) {
+ Log.d(TAG, this.getDevice().getAnonymizedAddress() + " set GroupId " + id);
mGroupId = id;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
index 26a2080..5662ce6 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
@@ -357,8 +357,12 @@
* {@code false}.
*/
public synchronized boolean shouldPairByCsip(BluetoothDevice device, int groupId) {
- if (mOngoingSetMemberPair != null || device.getBondState() != BluetoothDevice.BOND_NONE
+ boolean isOngoingSetMemberPair = mOngoingSetMemberPair != null;
+ int bondState = device.getBondState();
+ if (isOngoingSetMemberPair || bondState != BluetoothDevice.BOND_NONE
|| !mCsipDeviceManager.isExistedGroupId(groupId)) {
+ Log.d(TAG, "isOngoingSetMemberPair: " + isOngoingSetMemberPair
+ + " , device.getBondState: " + bondState);
return false;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java
index 9b38238..d5de3f0 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java
@@ -102,9 +102,12 @@
}
private CachedBluetoothDevice getCachedDevice(int groupId) {
+ log("getCachedDevice: groupId: " + groupId);
for (int i = mCachedDevices.size() - 1; i >= 0; i--) {
CachedBluetoothDevice cachedDevice = mCachedDevices.get(i);
if (cachedDevice.getGroupId() == groupId) {
+ log("getCachedDevice: found cachedDevice with the groupId: "
+ + cachedDevice.getDevice().getAnonymizedAddress());
return cachedDevice;
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java
index 818f5ca..cf4e1ee 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java
@@ -46,16 +46,43 @@
if (isValidHiSyncId(hiSyncId)) {
// Once hiSyncId is valid, assign hiSyncId
newDevice.setHiSyncId(hiSyncId);
+ final int side = getDeviceSide(newDevice.getDevice());
+ final int mode = getDeviceMode(newDevice.getDevice());
+ newDevice.setDeviceSide(side);
+ newDevice.setDeviceMode(mode);
}
}
private long getHiSyncId(BluetoothDevice device) {
- LocalBluetoothProfileManager profileManager = mBtManager.getProfileManager();
- HearingAidProfile profileProxy = profileManager.getHearingAidProfile();
- if (profileProxy != null) {
- return profileProxy.getHiSyncId(device);
+ final LocalBluetoothProfileManager profileManager = mBtManager.getProfileManager();
+ final HearingAidProfile profileProxy = profileManager.getHearingAidProfile();
+ if (profileProxy == null) {
+ return BluetoothHearingAid.HI_SYNC_ID_INVALID;
}
- return BluetoothHearingAid.HI_SYNC_ID_INVALID;
+
+ return profileProxy.getHiSyncId(device);
+ }
+
+ private int getDeviceSide(BluetoothDevice device) {
+ final LocalBluetoothProfileManager profileManager = mBtManager.getProfileManager();
+ final HearingAidProfile profileProxy = profileManager.getHearingAidProfile();
+ if (profileProxy == null) {
+ Log.w(TAG, "HearingAidProfile is not supported and not ready to fetch device side");
+ return HearingAidProfile.DeviceSide.SIDE_INVALID;
+ }
+
+ return profileProxy.getDeviceSide(device);
+ }
+
+ private int getDeviceMode(BluetoothDevice device) {
+ final LocalBluetoothProfileManager profileManager = mBtManager.getProfileManager();
+ final HearingAidProfile profileProxy = profileManager.getHearingAidProfile();
+ if (profileProxy == null) {
+ Log.w(TAG, "HearingAidProfile is not supported and not ready to fetch device mode");
+ return HearingAidProfile.DeviceMode.MODE_INVALID;
+ }
+
+ return profileProxy.getDeviceMode(device);
}
boolean setSubDeviceIfNeeded(CachedBluetoothDevice newDevice) {
@@ -98,6 +125,10 @@
if (isValidHiSyncId(newHiSyncId)) {
cachedDevice.setHiSyncId(newHiSyncId);
newSyncIdSet.add(newHiSyncId);
+ final int side = getDeviceSide(cachedDevice.getDevice());
+ final int mode = getDeviceMode(cachedDevice.getDevice());
+ cachedDevice.setDeviceSide(side);
+ cachedDevice.setDeviceMode(mode);
}
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java
index 01d581e..123c01b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java
@@ -26,11 +26,17 @@
import android.bluetooth.BluetoothLeAudioContentMetadata;
import android.bluetooth.BluetoothLeBroadcast;
import android.bluetooth.BluetoothLeBroadcastMetadata;
+import android.bluetooth.BluetoothLeBroadcastSubgroup;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothProfile.ServiceListener;
+import android.content.ContentResolver;
import android.content.Context;
-import android.content.SharedPreferences;
+import android.database.ContentObserver;
+import android.net.Uri;
import android.os.Build;
+import android.os.Handler;
+import android.os.Looper;
+import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
@@ -40,6 +46,7 @@
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
@@ -54,19 +61,20 @@
*/
public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
private static final String TAG = "LocalBluetoothLeBroadcast";
- private static final int UNKNOWN_VALUE_PLACEHOLDER = -1;
private static final boolean DEBUG = BluetoothUtils.D;
static final String NAME = "LE_AUDIO_BROADCAST";
+ private static final String UNDERLINE = "_";
+ private static final int DEFAULT_CODE_MAX = 9999;
+ private static final int DEFAULT_CODE_MIN = 1000;
// Order of this profile in device profiles list
private static final int ORDINAL = 1;
- private static final String PREF_NAME = "LocalBluetoothLeBroadcast";
- private static final String PREF_PROGRAM_INFO = "PrefProgramInfo";
- private static final String PREF_BROADCAST_CODE = "PrefBroadcastCode";
- private static final String PREF_APP_SOURCE_NAME = "PrefAppSourceName";
- private static final String UNDERLINE = "_";
- private static final int DEFAULT_CODE_MIN = 1000;
- private static final int DEFAULT_CODE_MAX = 9999;
+ private static final int UNKNOWN_VALUE_PLACEHOLDER = -1;
+ private static final Uri[] SETTINGS_URIS = new Uri[]{
+ Settings.Secure.getUriFor(Settings.Secure.BLUETOOTH_LE_BROADCAST_PROGRAM_INFO),
+ Settings.Secure.getUriFor(Settings.Secure.BLUETOOTH_LE_BROADCAST_CODE),
+ Settings.Secure.getUriFor(Settings.Secure.BLUETOOTH_LE_BROADCAST_APP_SOURCE_NAME),
+ };
private BluetoothLeBroadcast mService;
private BluetoothLeAudioContentMetadata mBluetoothLeAudioContentMetadata;
@@ -78,8 +86,9 @@
private boolean mIsProfileReady;
private String mProgramInfo;
private byte[] mBroadcastCode;
- private SharedPreferences mSharedPref;
private Executor mExecutor;
+ private ContentResolver mContentResolver;
+ private ContentObserver mSettingsObserver;
private final ServiceListener mServiceListener = new ServiceListener() {
@Override
@@ -91,6 +100,11 @@
mService = (BluetoothLeBroadcast) proxy;
mIsProfileReady = true;
registerServiceCallBack(mExecutor, mBroadcastCallback);
+ List<BluetoothLeBroadcastMetadata> metadata = getAllBroadcastMetadata();
+ if (!metadata.isEmpty()) {
+ updateBroadcastInfoFromBroadcastMetadata(metadata.get(0));
+ }
+ registerContentObserver();
}
}
@@ -102,6 +116,7 @@
if(mIsProfileReady) {
mIsProfileReady = false;
unregisterServiceCallBack(mBroadcastCallback);
+ unregisterContentObserver();
}
}
};
@@ -116,7 +131,7 @@
+ broadcastId);
}
setLatestBroadcastId(broadcastId);
- setAppSourceName(mNewAppSourceName);
+ setAppSourceName(mNewAppSourceName, /*updateContentResolver=*/ true);
}
@Override
@@ -160,7 +175,7 @@
+ broadcastId);
}
setLatestBroadcastId(broadcastId);
- setAppSourceName(mNewAppSourceName);
+ setAppSourceName(mNewAppSourceName, /*updateContentResolver=*/ true);
}
@Override
@@ -181,30 +196,27 @@
}
};
+ private class BroadcastSettingsObserver extends ContentObserver {
+ BroadcastSettingsObserver(Handler h) {
+ super(h);
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ Log.d(TAG, "BroadcastSettingsObserver: onChange");
+ updateBroadcastInfoFromContentProvider();
+ }
+ }
+
LocalBluetoothLeBroadcast(Context context) {
mExecutor = Executors.newSingleThreadExecutor();
BluetoothAdapter.getDefaultAdapter().
getProfileProxy(context, mServiceListener, BluetoothProfile.LE_AUDIO_BROADCAST);
mBuilder = new BluetoothLeAudioContentMetadata.Builder();
- mSharedPref = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
- if (mSharedPref != null) {
- String programInfo = mSharedPref.getString(PREF_PROGRAM_INFO, "");
- if (programInfo.isEmpty()) {
- programInfo = getDefaultValueOfProgramInfo();
- }
- setProgramInfo(programInfo);
-
- String prefBroadcastCode = mSharedPref.getString(PREF_BROADCAST_CODE, "");
- byte[] broadcastCode;
- if (prefBroadcastCode.isEmpty()) {
- broadcastCode = getDefaultValueOfBroadcastCode();
- } else {
- broadcastCode = prefBroadcastCode.getBytes(StandardCharsets.UTF_8);
- }
- setBroadcastCode(broadcastCode);
-
- mAppSourceName = mSharedPref.getString(PREF_APP_SOURCE_NAME, "");
- }
+ mContentResolver = context.getContentResolver();
+ Handler handler = new Handler(Looper.getMainLooper());
+ mSettingsObserver = new BroadcastSettingsObserver(handler);
+ updateBroadcastInfoFromContentProvider();
}
/**
@@ -217,11 +229,12 @@
Log.d(TAG, "The BluetoothLeBroadcast is null when starting the broadcast.");
return;
}
+ String programInfo = getProgramInfo();
if (DEBUG) {
Log.d(TAG,
- "startBroadcast: language = " + language + " ,programInfo = " + mProgramInfo);
+ "startBroadcast: language = " + language + " ,programInfo = " + programInfo);
}
- buildContentMetadata(language, mProgramInfo);
+ buildContentMetadata(language, programInfo);
mService.startBroadcast(mBluetoothLeAudioContentMetadata, mBroadcastCode);
}
@@ -230,21 +243,28 @@
}
public void setProgramInfo(String programInfo) {
- if (programInfo == null || programInfo.isEmpty()) {
+ setProgramInfo(programInfo, /*updateContentResolver=*/ true);
+ }
+
+ private void setProgramInfo(String programInfo, boolean updateContentResolver) {
+ if (TextUtils.isEmpty(programInfo)) {
Log.d(TAG, "setProgramInfo: programInfo is null or empty");
return;
}
+ if (mProgramInfo != null && TextUtils.equals(mProgramInfo, programInfo)) {
+ Log.d(TAG, "setProgramInfo: programInfo is not changed");
+ return;
+ }
Log.d(TAG, "setProgramInfo: " + programInfo);
mProgramInfo = programInfo;
-
- if (mSharedPref == null) {
- Log.d(TAG, "setProgramInfo: sharedPref is null");
- return;
+ if (updateContentResolver) {
+ if (mContentResolver == null) {
+ Log.d(TAG, "mContentResolver is null");
+ return;
+ }
+ Settings.Secure.putString(mContentResolver,
+ Settings.Secure.BLUETOOTH_LE_BROADCAST_PROGRAM_INFO, programInfo);
}
- SharedPreferences.Editor editor = mSharedPref.edit();
- editor.putString(PREF_PROGRAM_INFO, mProgramInfo);
- editor.apply();
-
}
public byte[] getBroadcastCode() {
@@ -252,22 +272,31 @@
}
public void setBroadcastCode(byte[] broadcastCode) {
- if (broadcastCode == null || broadcastCode.length == 0) {
- Log.d(TAG, "setBroadcastCode: broadcastCode is null or empty");
+ setBroadcastCode(broadcastCode, /*updateContentResolver=*/ true);
+ }
+
+ private void setBroadcastCode(byte[] broadcastCode, boolean updateContentResolver) {
+ if (broadcastCode == null) {
+ Log.d(TAG, "setBroadcastCode: broadcastCode is null");
+ return;
+ }
+ if (mBroadcastCode != null && Arrays.equals(broadcastCode, mBroadcastCode)) {
+ Log.d(TAG, "setBroadcastCode: broadcastCode is not changed");
return;
}
mBroadcastCode = broadcastCode;
-
- if (mSharedPref == null) {
- Log.d(TAG, "setBroadcastCode: sharedPref is null");
- return;
+ if (updateContentResolver) {
+ if (mContentResolver == null) {
+ Log.d(TAG, "mContentResolver is null");
+ return;
+ }
+ Settings.Secure.putString(mContentResolver, Settings.Secure.BLUETOOTH_LE_BROADCAST_CODE,
+ new String(broadcastCode, StandardCharsets.UTF_8));
}
- SharedPreferences.Editor editor = mSharedPref.edit();
- editor.putString(PREF_BROADCAST_CODE, new String(broadcastCode, StandardCharsets.UTF_8));
- editor.apply();
}
private void setLatestBroadcastId(int broadcastId) {
+ Log.d(TAG, "setLatestBroadcastId: mBroadcastId is " + broadcastId);
mBroadcastId = broadcastId;
}
@@ -275,19 +304,24 @@
return mBroadcastId;
}
- private void setAppSourceName(String appSourceName) {
+ private void setAppSourceName(String appSourceName, boolean updateContentResolver) {
if (TextUtils.isEmpty(appSourceName)) {
appSourceName = "";
}
- mAppSourceName = appSourceName;
- mNewAppSourceName = "";
- if (mSharedPref == null) {
- Log.d(TAG, "setBroadcastCode: sharedPref is null");
+ if (mAppSourceName != null && TextUtils.equals(mAppSourceName, appSourceName)) {
+ Log.d(TAG, "setAppSourceName: appSourceName is not changed");
return;
}
- SharedPreferences.Editor editor = mSharedPref.edit();
- editor.putString(PREF_APP_SOURCE_NAME, appSourceName);
- editor.apply();
+ mAppSourceName = appSourceName;
+ mNewAppSourceName = "";
+ if (updateContentResolver) {
+ if (mContentResolver == null) {
+ Log.d(TAG, "mContentResolver is null");
+ return;
+ }
+ Settings.Secure.putString(mContentResolver,
+ Settings.Secure.BLUETOOTH_LE_BROADCAST_APP_SOURCE_NAME, mAppSourceName);
+ }
}
public String getAppSourceName() {
@@ -299,6 +333,7 @@
if (bluetoothLeBroadcastMetadata != null
&& bluetoothLeBroadcastMetadata.getBroadcastId() == mBroadcastId) {
mBluetoothLeBroadcastMetadata = bluetoothLeBroadcastMetadata;
+ updateBroadcastInfoFromBroadcastMetadata(bluetoothLeBroadcastMetadata);
}
}
@@ -318,6 +353,48 @@
return mBluetoothLeBroadcastMetadata;
}
+ private void updateBroadcastInfoFromContentProvider() {
+ if (mContentResolver == null) {
+ Log.d(TAG, "updateBroadcastInfoFromContentProvider: mContentResolver is null");
+ return;
+ }
+ String programInfo = Settings.Secure.getString(mContentResolver,
+ Settings.Secure.BLUETOOTH_LE_BROADCAST_PROGRAM_INFO);
+ if (programInfo == null) {
+ programInfo = getDefaultValueOfProgramInfo();
+ }
+ setProgramInfo(programInfo, /*updateContentResolver=*/ false);
+
+ String prefBroadcastCode = Settings.Secure.getString(mContentResolver,
+ Settings.Secure.BLUETOOTH_LE_BROADCAST_CODE);
+ byte[] broadcastCode = (prefBroadcastCode == null) ? getDefaultValueOfBroadcastCode()
+ : prefBroadcastCode.getBytes(StandardCharsets.UTF_8);
+ setBroadcastCode(broadcastCode, /*updateContentResolver=*/ false);
+
+ String appSourceName = Settings.Secure.getString(mContentResolver,
+ Settings.Secure.BLUETOOTH_LE_BROADCAST_APP_SOURCE_NAME);
+ setAppSourceName(appSourceName, /*updateContentResolver=*/ false);
+ }
+
+ private void updateBroadcastInfoFromBroadcastMetadata(
+ BluetoothLeBroadcastMetadata bluetoothLeBroadcastMetadata) {
+ if (bluetoothLeBroadcastMetadata == null) {
+ Log.d(TAG, "The bluetoothLeBroadcastMetadata is null");
+ return;
+ }
+ setBroadcastCode(bluetoothLeBroadcastMetadata.getBroadcastCode());
+ setLatestBroadcastId(bluetoothLeBroadcastMetadata.getBroadcastId());
+
+ List<BluetoothLeBroadcastSubgroup> subgroup = bluetoothLeBroadcastMetadata.getSubgroups();
+ if (subgroup == null || subgroup.size() < 1) {
+ Log.d(TAG, "The subgroup is not valid value");
+ return;
+ }
+ BluetoothLeAudioContentMetadata contentMetadata = subgroup.get(0).getContentMetadata();
+ setProgramInfo(contentMetadata.getProgramInfo());
+ setAppSourceName(getAppSourceName(), /*updateContentResolver=*/ true);
+ }
+
/**
* Stop the latest LE Broadcast. If the system stopped the LE Broadcast, then the system
* calls the corresponding callback {@link BluetoothLeBroadcast.Callback}.
@@ -350,12 +427,13 @@
Log.d(TAG, "The BluetoothLeBroadcast is null when updating the broadcast.");
return;
}
+ String programInfo = getProgramInfo();
if (DEBUG) {
Log.d(TAG,
- "updateBroadcast: language = " + language + " ,programInfo = " + mProgramInfo);
+ "updateBroadcast: language = " + language + " ,programInfo = " + programInfo);
}
mNewAppSourceName = appSourceName;
- mBluetoothLeAudioContentMetadata = mBuilder.setProgramInfo(mProgramInfo).build();
+ mBluetoothLeAudioContentMetadata = mBuilder.setProgramInfo(programInfo).build();
mService.updateBroadcast(mBroadcastId, mBluetoothLeAudioContentMetadata);
}
@@ -517,8 +595,7 @@
if (DEBUG) {
Log.d(TAG, "resetCacheInfo:");
}
- mNewAppSourceName = "";
- mAppSourceName = "";
+ setAppSourceName("", /*updateContentResolver=*/ true);
mBluetoothLeBroadcastMetadata = null;
mBroadcastId = UNKNOWN_VALUE_PLACEHOLDER;
}
@@ -528,4 +605,22 @@
//first 12 chars from xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
return randomUUID.substring(0, 8) + randomUUID.substring(9, 13);
}
+
+ private void registerContentObserver() {
+ if (mContentResolver == null) {
+ Log.d(TAG, "mContentResolver is null");
+ return;
+ }
+ for (Uri uri : SETTINGS_URIS) {
+ mContentResolver.registerContentObserver(uri, false, mSettingsObserver);
+ }
+ }
+
+ private void unregisterContentObserver() {
+ if (mContentResolver == null) {
+ Log.d(TAG, "mContentResolver is null");
+ return;
+ }
+ mContentResolver.unregisterContentObserver(mSettingsObserver);
+ }
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/OWNERS b/packages/SettingsLib/src/com/android/settingslib/bluetooth/OWNERS
index 387bae1..5e66972 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/OWNERS
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/OWNERS
@@ -3,5 +3,7 @@
hughchen@google.com
timhypeng@google.com
robertluo@google.com
+changbetty@google.com
+songferngwang@google.com
# Emergency approvers in case the above are not available
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
index a72f311..58c15eb 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
@@ -422,7 +422,7 @@
|| sessionInfo.getSelectedRoutes().size() <= 1;
}
- private void refreshDevices() {
+ private synchronized void refreshDevices() {
mMediaDevices.clear();
mCurrentConnectedDevice = null;
if (TextUtils.isEmpty(mPackageName)) {
@@ -452,7 +452,7 @@
return infos;
}
- private void buildAvailableRoutes() {
+ private synchronized void buildAvailableRoutes() {
for (MediaRoute2Info route : getAvailableRoutes(mPackageName)) {
if (DEBUG) {
Log.d(TAG, "buildAvailableRoutes() route : " + route.getName() + ", volume : "
@@ -462,7 +462,7 @@
}
}
- private List<MediaRoute2Info> getAvailableRoutes(String packageName) {
+ private synchronized List<MediaRoute2Info> getAvailableRoutes(String packageName) {
final List<MediaRoute2Info> infos = new ArrayList<>();
RoutingSessionInfo routingSessionInfo = getRoutingSessionInfo(packageName);
if (routingSessionInfo != null) {
@@ -596,7 +596,7 @@
@Override
public void onSessionUpdated(RoutingSessionInfo sessionInfo) {
- dispatchDataChanged();
+ refreshDevices();
}
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/mobile/MobileStatusTracker.java b/packages/SettingsLib/src/com/android/settingslib/mobile/MobileStatusTracker.java
index b416738..39b4b8e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/mobile/MobileStatusTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/mobile/MobileStatusTracker.java
@@ -78,6 +78,9 @@
* Config the MobileStatusTracker to start or stop monitoring platform signals.
*/
public void setListening(boolean listening) {
+ if (mListening == listening) {
+ return;
+ }
mListening = listening;
if (listening) {
mPhone.registerTelephonyCallback(mReceiverHandler::post, mTelephonyCallback);
diff --git a/packages/SettingsLib/src/com/android/settingslib/users/AvatarPhotoController.java b/packages/SettingsLib/src/com/android/settingslib/users/AvatarPhotoController.java
index 63a9f0c..4ce88ee 100644
--- a/packages/SettingsLib/src/com/android/settingslib/users/AvatarPhotoController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/users/AvatarPhotoController.java
@@ -21,8 +21,8 @@
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
@@ -48,6 +48,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.util.List;
import java.util.concurrent.ExecutionException;
class AvatarPhotoController {
@@ -326,13 +327,13 @@
@Override
public boolean startSystemActivityForResult(Intent intent, int code) {
- ActivityInfo info = intent.resolveActivityInfo(mActivity.getPackageManager(),
- PackageManager.MATCH_SYSTEM_ONLY);
- if (info == null) {
+ List<ResolveInfo> resolveInfos = mActivity.getPackageManager()
+ .queryIntentActivities(intent, PackageManager.MATCH_SYSTEM_ONLY);
+ if (resolveInfos.isEmpty()) {
Log.w(TAG, "No system package activity could be found for code " + code);
return false;
}
- intent.setPackage(info.packageName);
+ intent.setPackage(resolveInfos.get(0).activityInfo.packageName);
mActivity.startActivityForResult(intent, code);
return true;
}
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 d80a591..611b0a4 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
@@ -102,16 +102,25 @@
}
/**
- * Test initHearingAidDeviceIfNeeded, a valid HiSyncId will be assigned
+ * Test initHearingAidDeviceIfNeeded, set HearingAid's information, including HiSyncId,
+ * deviceSide, deviceMode.
*/
@Test
- public void initHearingAidDeviceIfNeeded_validHiSyncId_verifyHiSyncId() {
+ public void initHearingAidDeviceIfNeeded_validHiSyncId_setHearingAidInfos() {
when(mHearingAidProfile.getHiSyncId(mDevice1)).thenReturn(HISYNCID1);
+ when(mHearingAidProfile.getDeviceMode(mDevice1)).thenReturn(
+ HearingAidProfile.DeviceMode.MODE_BINAURAL);
+ when(mHearingAidProfile.getDeviceSide(mDevice1)).thenReturn(
+ HearingAidProfile.DeviceSide.SIDE_RIGHT);
assertThat(mCachedDevice1.getHiSyncId()).isNotEqualTo(HISYNCID1);
mHearingAidDeviceManager.initHearingAidDeviceIfNeeded(mCachedDevice1);
assertThat(mCachedDevice1.getHiSyncId()).isEqualTo(HISYNCID1);
+ assertThat(mCachedDevice1.getDeviceMode()).isEqualTo(
+ HearingAidProfile.DeviceMode.MODE_BINAURAL);
+ assertThat(mCachedDevice1.getDeviceSide()).isEqualTo(
+ HearingAidProfile.DeviceSide.SIDE_RIGHT);
}
/**
@@ -251,6 +260,29 @@
}
/**
+ * Test updateHearingAidsDevices, set HearingAid's information, including HiSyncId, deviceSide,
+ * deviceMode.
+ */
+ @Test
+ public void updateHearingAidsDevices_validHiSyncId_setHearingAidInfos() {
+ when(mHearingAidProfile.getHiSyncId(mDevice1)).thenReturn(HISYNCID1);
+ when(mHearingAidProfile.getDeviceMode(mDevice1)).thenReturn(
+ HearingAidProfile.DeviceMode.MODE_BINAURAL);
+ when(mHearingAidProfile.getDeviceSide(mDevice1)).thenReturn(
+ HearingAidProfile.DeviceSide.SIDE_RIGHT);
+ mCachedDeviceManager.mCachedDevices.add(mCachedDevice1);
+
+ mHearingAidDeviceManager.updateHearingAidsDevices();
+
+ assertThat(mCachedDevice1.getHiSyncId()).isEqualTo(HISYNCID1);
+ assertThat(mCachedDevice1.getDeviceMode()).isEqualTo(
+ HearingAidProfile.DeviceMode.MODE_BINAURAL);
+ assertThat(mCachedDevice1.getDeviceSide()).isEqualTo(
+ HearingAidProfile.DeviceSide.SIDE_RIGHT);
+ verify(mHearingAidDeviceManager).onHiSyncIdChanged(HISYNCID1);
+ }
+
+ /**
* Test onProfileConnectionStateChangedIfProcessed.
* When first hearing aid device is connected, to process it same as other generic devices.
* No need to process it.
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
index ee7b7d6..d04d85a 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
@@ -666,12 +666,22 @@
}
@Test
- public void onSessionUpdated_shouldDispatchDataChanged() {
+ public void onSessionUpdated_shouldDispatchDeviceListAdded() {
+ final MediaRoute2Info info = mock(MediaRoute2Info.class);
+ when(info.getId()).thenReturn(TEST_ID);
+ when(info.getClientPackageName()).thenReturn(TEST_PACKAGE_NAME);
+ when(info.isSystemRoute()).thenReturn(true);
+
+ final List<MediaRoute2Info> routes = new ArrayList<>();
+ routes.add(info);
+ mShadowRouter2Manager.setAllRoutes(routes);
+
+ mInfoMediaManager.mPackageName = "";
mInfoMediaManager.registerCallback(mCallback);
mInfoMediaManager.mMediaRouterCallback.onSessionUpdated(mock(RoutingSessionInfo.class));
- verify(mCallback).onDeviceAttributesChanged();
+ verify(mCallback).onDeviceListAdded(any());
}
@Test
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index 36fbf8f..453a713 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -212,6 +212,9 @@
Settings.Secure.LOCKSCREEN_USE_DOUBLE_LINE_CLOCK,
Settings.Secure.STATUS_BAR_SHOW_VIBRATE_ICON,
Settings.Secure.ASSIST_TOUCH_GESTURE_ENABLED,
- Settings.Secure.ASSIST_LONG_PRESS_HOME_ENABLED
+ Settings.Secure.ASSIST_LONG_PRESS_HOME_ENABLED,
+ Settings.Secure.BLUETOOTH_LE_BROADCAST_PROGRAM_INFO,
+ Settings.Secure.BLUETOOTH_LE_BROADCAST_CODE,
+ Settings.Secure.BLUETOOTH_LE_BROADCAST_APP_SOURCE_NAME
};
}
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index 6a70230..a39735f 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -344,5 +344,8 @@
return true;
});
VALIDATORS.put(Secure.ODI_CAPTIONS_VOLUME_UI_ENABLED, BOOLEAN_VALIDATOR);
+ VALIDATORS.put(Secure.BLUETOOTH_LE_BROADCAST_PROGRAM_INFO, ANY_STRING_VALIDATOR);
+ VALIDATORS.put(Secure.BLUETOOTH_LE_BROADCAST_CODE, ANY_STRING_VALIDATOR);
+ VALIDATORS.put(Secure.BLUETOOTH_LE_BROADCAST_APP_SOURCE_NAME, ANY_STRING_VALIDATOR);
}
}
diff --git a/packages/Shell/res/values-nb/strings.xml b/packages/Shell/res/values-nb/strings.xml
index 625b15a..ce39385 100644
--- a/packages/Shell/res/values-nb/strings.xml
+++ b/packages/Shell/res/values-nb/strings.xml
@@ -18,8 +18,8 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Kommandoliste"</string>
<string name="bugreport_notification_channel" msgid="2574150205913861141">"Feilrapporter"</string>
- <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Feilrapporten <xliff:g id="ID">#%d</xliff:g> blir generert"</string>
- <string name="bugreport_finished_title" msgid="4429132808670114081">"Feilrapporten <xliff:g id="ID">#%d</xliff:g> er fullført"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Feilrapport <xliff:g id="ID">#%d</xliff:g> blir generert"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Feilrapport <xliff:g id="ID">#%d</xliff:g> er fullført"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Legger til detaljer i feilrapporten"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Vent litt"</string>
<string name="bugreport_finished_text" product="watch" msgid="1223616207145252689">"Feilrapporten vises snart på telefonen"</string>
@@ -38,7 +38,7 @@
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Skjermdump"</string>
<string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Skjermdumpen er tatt."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Skjermdumpen kunne ikke tas."</string>
- <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Detaljer om feilrapporten <xliff:g id="ID">#%d</xliff:g>"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Detaljer om feilrapport <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Filnavn"</string>
<string name="bugreport_info_title" msgid="2306030793918239804">"Navn på feil"</string>
<string name="bugreport_info_description" msgid="5072835127481627722">"Oppsummering av feil"</string>
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index ff4c748..f50dc74 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -212,6 +212,7 @@
"kotlinx-coroutines-android",
"kotlinx-coroutines-core",
"kotlinx_coroutines_test",
+ "kotlin-reflect",
"iconloader_base",
"SystemUI-tags",
"SystemUI-proto",
@@ -240,11 +241,9 @@
plugins: ["dagger2-compiler"],
}
-// Opt-in config for optimizing the SystemUI target using R8.
-// Enabled via `export SYSTEMUI_OPTIMIZE_JAVA=true`, or explicitly in Make via
-// the `SOONG_CONFIG_ANDROID_SYSTEMUI_OPTIMIZE_JAVA` variable.
-// TODO(b/203472868): Enable optimizations by default after stabilizing and
-// building out retrace infrastructure.
+// Opt-out config for optimizing the SystemUI target using R8.
+// Disabled via `export SYSTEMUI_OPTIMIZE_JAVA=false`, or explicitly in Make via
+// `SYSTEMUI_OPTIMIZE_JAVA := false`.
soong_config_module_type {
name: "systemui_optimized_java_defaults",
module_type: "java_defaults",
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 7649de6..2737ecf 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -414,7 +414,7 @@
</intent-filter>
</receiver>
- <service android:name=".ImageWallpaper"
+ <service android:name=".wallpapers.ImageWallpaper"
android:singleUser="true"
android:permission="android.permission.BIND_WALLPAPER"
android:exported="true" />
diff --git a/packages/SystemUI/OWNERS b/packages/SystemUI/OWNERS
index 546f0d2..a65f9be 100644
--- a/packages/SystemUI/OWNERS
+++ b/packages/SystemUI/OWNERS
@@ -7,6 +7,7 @@
aaliomer@google.com
adamcohen@google.com
alexflo@google.com
+arteiro@google.com
asc@google.com
awickham@google.com
beverlyt@google.com
diff --git a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SlowUserQueryDetector.kt b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SlowUserQueryDetector.kt
new file mode 100644
index 0000000..b006615
--- /dev/null
+++ b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SlowUserQueryDetector.kt
@@ -0,0 +1,103 @@
+/*
+ * 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.internal.systemui.lint
+
+import com.android.tools.lint.detector.api.Category
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Implementation
+import com.android.tools.lint.detector.api.Issue
+import com.android.tools.lint.detector.api.JavaContext
+import com.android.tools.lint.detector.api.Scope
+import com.android.tools.lint.detector.api.Severity
+import com.android.tools.lint.detector.api.SourceCodeScanner
+import com.intellij.psi.PsiMethod
+import org.jetbrains.uast.UCallExpression
+
+/**
+ * Checks for slow calls to ActivityManager.getCurrentUser() or UserManager.getUserInfo() and
+ * suggests using UserTracker instead. For more info, see: http://go/multi-user-in-systemui-slides.
+ */
+@Suppress("UnstableApiUsage")
+class SlowUserQueryDetector : Detector(), SourceCodeScanner {
+
+ override fun getApplicableMethodNames(): List<String> {
+ return listOf("getCurrentUser", "getUserInfo")
+ }
+
+ override fun visitMethodCall(context: JavaContext, node: UCallExpression, method: PsiMethod) {
+ val evaluator = context.evaluator
+ if (
+ evaluator.isStatic(method) &&
+ method.name == "getCurrentUser" &&
+ method.containingClass?.qualifiedName == "android.app.ActivityManager"
+ ) {
+ context.report(
+ ISSUE_SLOW_USER_ID_QUERY,
+ method,
+ context.getNameLocation(node),
+ "ActivityManager.getCurrentUser() is slow. " +
+ "Use UserTracker.getUserId() instead."
+ )
+ }
+ if (
+ !evaluator.isStatic(method) &&
+ method.name == "getUserInfo" &&
+ method.containingClass?.qualifiedName == "android.os.UserManager"
+ ) {
+ context.report(
+ ISSUE_SLOW_USER_INFO_QUERY,
+ method,
+ context.getNameLocation(node),
+ "UserManager.getUserInfo() is slow. " + "Use UserTracker.getUserInfo() instead."
+ )
+ }
+ }
+
+ companion object {
+ @JvmField
+ val ISSUE_SLOW_USER_ID_QUERY: Issue =
+ Issue.create(
+ id = "SlowUserIdQuery",
+ briefDescription = "User ID queried using ActivityManager instead of UserTracker.",
+ explanation =
+ "ActivityManager.getCurrentUser() makes a binder call and is slow. " +
+ "Instead, inject a UserTracker and call UserTracker.getUserId(). For " +
+ "more info, see: http://go/multi-user-in-systemui-slides",
+ category = Category.PERFORMANCE,
+ priority = 8,
+ severity = Severity.WARNING,
+ implementation =
+ Implementation(SlowUserQueryDetector::class.java, Scope.JAVA_FILE_SCOPE)
+ )
+
+ @JvmField
+ val ISSUE_SLOW_USER_INFO_QUERY: Issue =
+ Issue.create(
+ id = "SlowUserInfoQuery",
+ briefDescription = "User info queried using UserManager instead of UserTracker.",
+ explanation =
+ "UserManager.getUserInfo() makes a binder call and is slow. " +
+ "Instead, inject a UserTracker and call UserTracker.getUserInfo(). For " +
+ "more info, see: http://go/multi-user-in-systemui-slides",
+ category = Category.PERFORMANCE,
+ priority = 8,
+ severity = Severity.WARNING,
+ implementation =
+ Implementation(SlowUserQueryDetector::class.java, Scope.JAVA_FILE_SCOPE)
+ )
+ }
+}
diff --git a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt
index c7c73d3..4879883 100644
--- a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt
+++ b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt
@@ -30,6 +30,8 @@
get() = listOf(
BindServiceViaContextDetector.ISSUE,
BroadcastSentViaContextDetector.ISSUE,
+ SlowUserQueryDetector.ISSUE_SLOW_USER_ID_QUERY,
+ SlowUserQueryDetector.ISSUE_SLOW_USER_INFO_QUERY,
GetMainLooperViaContextDetector.ISSUE,
RegisterReceiverViaContextDetector.ISSUE,
SoftwareBitmapDetector.ISSUE,
diff --git a/packages/SystemUI/checks/tests/com/android/systemui/lint/SlowUserQueryDetectorTest.kt b/packages/SystemUI/checks/tests/com/android/systemui/lint/SlowUserQueryDetectorTest.kt
new file mode 100644
index 0000000..2738f04
--- /dev/null
+++ b/packages/SystemUI/checks/tests/com/android/systemui/lint/SlowUserQueryDetectorTest.kt
@@ -0,0 +1,194 @@
+package com.android.internal.systemui.lint
+
+import com.android.tools.lint.checks.infrastructure.LintDetectorTest
+import com.android.tools.lint.checks.infrastructure.TestFile
+import com.android.tools.lint.checks.infrastructure.TestFiles
+import com.android.tools.lint.checks.infrastructure.TestLintTask
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Issue
+import org.junit.Test
+
+class SlowUserQueryDetectorTest : LintDetectorTest() {
+
+ override fun getDetector(): Detector = SlowUserQueryDetector()
+ override fun lint(): TestLintTask = super.lint().allowMissingSdk(true)
+
+ override fun getIssues(): List<Issue> =
+ listOf(
+ SlowUserQueryDetector.ISSUE_SLOW_USER_ID_QUERY,
+ SlowUserQueryDetector.ISSUE_SLOW_USER_INFO_QUERY
+ )
+
+ @Test
+ fun testGetCurrentUser() {
+ lint()
+ .files(
+ TestFiles.java(
+ """
+ package test.pkg;
+ import android.app.ActivityManager;
+
+ public class TestClass1 {
+ public void slewlyGetCurrentUser() {
+ ActivityManager.getCurrentUser();
+ }
+ }
+ """
+ )
+ .indented(),
+ *stubs
+ )
+ .issues(
+ SlowUserQueryDetector.ISSUE_SLOW_USER_ID_QUERY,
+ SlowUserQueryDetector.ISSUE_SLOW_USER_INFO_QUERY
+ )
+ .run()
+ .expectWarningCount(1)
+ .expectContains(
+ "ActivityManager.getCurrentUser() is slow. " +
+ "Use UserTracker.getUserId() instead."
+ )
+ }
+
+ @Test
+ fun testGetUserInfo() {
+ lint()
+ .files(
+ TestFiles.java(
+ """
+ package test.pkg;
+ import android.os.UserManager;
+
+ public class TestClass2 {
+ public void slewlyGetUserInfo(UserManager userManager) {
+ userManager.getUserInfo();
+ }
+ }
+ """
+ )
+ .indented(),
+ *stubs
+ )
+ .issues(
+ SlowUserQueryDetector.ISSUE_SLOW_USER_ID_QUERY,
+ SlowUserQueryDetector.ISSUE_SLOW_USER_INFO_QUERY
+ )
+ .run()
+ .expectWarningCount(1)
+ .expectContains(
+ "UserManager.getUserInfo() is slow. " + "Use UserTracker.getUserInfo() instead."
+ )
+ }
+
+ @Test
+ fun testUserTrackerGetUserId() {
+ lint()
+ .files(
+ TestFiles.java(
+ """
+ package test.pkg;
+ import com.android.systemui.settings.UserTracker;
+
+ public class TestClass3 {
+ public void quicklyGetUserId(UserTracker userTracker) {
+ userTracker.getUserId();
+ }
+ }
+ """
+ )
+ .indented(),
+ *stubs
+ )
+ .issues(
+ SlowUserQueryDetector.ISSUE_SLOW_USER_ID_QUERY,
+ SlowUserQueryDetector.ISSUE_SLOW_USER_INFO_QUERY
+ )
+ .run()
+ .expectClean()
+ }
+
+ @Test
+ fun testUserTrackerGetUserInfo() {
+ lint()
+ .files(
+ TestFiles.java(
+ """
+ package test.pkg;
+ import com.android.systemui.settings.UserTracker;
+
+ public class TestClass4 {
+ public void quicklyGetUserId(UserTracker userTracker) {
+ userTracker.getUserInfo();
+ }
+ }
+ """
+ )
+ .indented(),
+ *stubs
+ )
+ .issues(
+ SlowUserQueryDetector.ISSUE_SLOW_USER_ID_QUERY,
+ SlowUserQueryDetector.ISSUE_SLOW_USER_INFO_QUERY
+ )
+ .run()
+ .expectClean()
+ }
+
+ private val activityManagerStub: TestFile =
+ java(
+ """
+ package android.app;
+
+ public class ActivityManager {
+ public static int getCurrentUser() {};
+ }
+ """
+ )
+
+ private val userManagerStub: TestFile =
+ java(
+ """
+ package android.os;
+ import android.content.pm.UserInfo;
+ import android.annotation.UserIdInt;
+
+ public class UserManager {
+ public UserInfo getUserInfo(@UserIdInt int userId) {};
+ }
+ """
+ )
+
+ private val userIdIntStub: TestFile =
+ java(
+ """
+ package android.annotation;
+
+ public @interface UserIdInt {}
+ """
+ )
+
+ private val userInfoStub: TestFile =
+ java(
+ """
+ package android.content.pm;
+
+ public class UserInfo {}
+ """
+ )
+
+ private val userTrackerStub: TestFile =
+ java(
+ """
+ package com.android.systemui.settings;
+ import android.content.pm.UserInfo;
+
+ public interface UserTracker {
+ public int getUserId();
+ public UserInfo getUserInfo();
+ }
+ """
+ )
+
+ private val stubs =
+ arrayOf(activityManagerStub, userManagerStub, userIdIntStub, userInfoStub, userTrackerStub)
+}
diff --git a/packages/SystemUI/compose/core/src/com/android/systemui/compose/SystemUiButtons.kt b/packages/SystemUI/compose/core/src/com/android/systemui/compose/SystemUiButtons.kt
new file mode 100644
index 0000000..496f4b3
--- /dev/null
+++ b/packages/SystemUI/compose/core/src/com/android/systemui/compose/SystemUiButtons.kt
@@ -0,0 +1,110 @@
+/*
+ * 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.compose
+
+import androidx.compose.foundation.BorderStroke
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.RowScope
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material3.ButtonColors
+import androidx.compose.material3.ButtonDefaults
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.unit.dp
+import com.android.systemui.compose.theme.LocalAndroidColorScheme
+
+@Composable
+fun SysUiButton(
+ onClick: () -> Unit,
+ modifier: Modifier = Modifier,
+ enabled: Boolean = true,
+ content: @Composable RowScope.() -> Unit,
+) {
+ androidx.compose.material3.Button(
+ modifier = modifier.padding(vertical = 6.dp).height(36.dp),
+ colors = filledButtonColors(),
+ contentPadding = ButtonPaddings,
+ onClick = onClick,
+ enabled = enabled,
+ ) {
+ content()
+ }
+}
+
+@Composable
+fun SysUiOutlinedButton(
+ onClick: () -> Unit,
+ modifier: Modifier = Modifier,
+ enabled: Boolean = true,
+ content: @Composable RowScope.() -> Unit,
+) {
+ androidx.compose.material3.OutlinedButton(
+ modifier = modifier.padding(vertical = 6.dp).height(36.dp),
+ enabled = enabled,
+ colors = outlineButtonColors(),
+ border = outlineButtonBorder(),
+ contentPadding = ButtonPaddings,
+ onClick = onClick,
+ ) {
+ content()
+ }
+}
+
+@Composable
+fun SysUiTextButton(
+ onClick: () -> Unit,
+ modifier: Modifier = Modifier,
+ enabled: Boolean = true,
+ content: @Composable RowScope.() -> Unit,
+) {
+ androidx.compose.material3.TextButton(
+ onClick = onClick,
+ modifier = modifier,
+ enabled = enabled,
+ content = content,
+ )
+}
+
+private val ButtonPaddings = PaddingValues(horizontal = 16.dp, vertical = 8.dp)
+
+@Composable
+private fun filledButtonColors(): ButtonColors {
+ val colors = LocalAndroidColorScheme.current
+ return ButtonDefaults.buttonColors(
+ containerColor = colors.colorAccentPrimary,
+ contentColor = colors.textColorOnAccent,
+ )
+}
+
+@Composable
+private fun outlineButtonColors(): ButtonColors {
+ val colors = LocalAndroidColorScheme.current
+ return ButtonDefaults.outlinedButtonColors(
+ contentColor = colors.textColorPrimary,
+ )
+}
+
+@Composable
+private fun outlineButtonBorder(): BorderStroke {
+ val colors = LocalAndroidColorScheme.current
+ return BorderStroke(
+ width = 1.dp,
+ color = colors.colorAccentPrimaryVariant,
+ )
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeConstants.java b/packages/SystemUI/compose/features/src/com/android/systemui/common/ui/compose/TextExt.kt
similarity index 60%
copy from libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeConstants.java
copy to packages/SystemUI/compose/features/src/com/android/systemui/common/ui/compose/TextExt.kt
index e62a63a..e1f73e3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeConstants.java
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/common/ui/compose/TextExt.kt
@@ -12,20 +12,20 @@
* WITHOUT 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.desktopmode;
+package com.android.systemui.common.ui.compose
-import android.os.SystemProperties;
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.res.stringResource
+import com.android.systemui.common.shared.model.Text
-/**
- * Constants for desktop mode feature
- */
-public class DesktopModeConstants {
-
- /**
- * Flag to indicate whether desktop mode is available on the device
- */
- public static final boolean IS_FEATURE_ENABLED = SystemProperties.getBoolean(
- "persist.wm.debug.desktop_mode", false);
+/** Returns the loaded [String] or `null` if there isn't one. */
+@Composable
+fun Text.load(): String? {
+ return when (this) {
+ is Text.Loaded -> text
+ is Text.Resource -> stringResource(res)
+ }
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/user/ui/compose/UserSwitcherScreen.kt b/packages/SystemUI/compose/features/src/com/android/systemui/user/ui/compose/UserSwitcherScreen.kt
new file mode 100644
index 0000000..3175dcf
--- /dev/null
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/user/ui/compose/UserSwitcherScreen.kt
@@ -0,0 +1,423 @@
+/*
+ * 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.user.ui.compose
+
+import android.graphics.Bitmap
+import android.graphics.Canvas
+import android.graphics.drawable.Drawable
+import androidx.appcompat.content.res.AppCompatResources
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.background
+import androidx.compose.foundation.border
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.heightIn
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.sizeIn
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.shape.CircleShape
+import androidx.compose.material3.DropdownMenu
+import androidx.compose.material3.DropdownMenuItem
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.collectAsState
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.alpha
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.asImageBitmap
+import androidx.compose.ui.graphics.painter.ColorPainter
+import androidx.compose.ui.graphics.toArgb
+import androidx.compose.ui.platform.LocalConfiguration
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.platform.LocalDensity
+import androidx.compose.ui.res.colorResource
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.style.TextOverflow
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.dp
+import com.android.systemui.common.ui.compose.load
+import com.android.systemui.compose.SysUiOutlinedButton
+import com.android.systemui.compose.SysUiTextButton
+import com.android.systemui.compose.features.R
+import com.android.systemui.compose.theme.LocalAndroidColorScheme
+import com.android.systemui.user.ui.viewmodel.UserActionViewModel
+import com.android.systemui.user.ui.viewmodel.UserSwitcherViewModel
+import com.android.systemui.user.ui.viewmodel.UserViewModel
+import java.lang.Integer.min
+import kotlin.math.ceil
+
+@Composable
+fun UserSwitcherScreen(
+ viewModel: UserSwitcherViewModel,
+ onFinished: () -> Unit,
+ modifier: Modifier = Modifier,
+) {
+ val isFinishRequested: Boolean by viewModel.isFinishRequested.collectAsState(false)
+ val users: List<UserViewModel> by viewModel.users.collectAsState(emptyList())
+ val maxUserColumns: Int by viewModel.maximumUserColumns.collectAsState(1)
+ val menuActions: List<UserActionViewModel> by viewModel.menu.collectAsState(emptyList())
+ val isOpenMenuButtonVisible: Boolean by viewModel.isOpenMenuButtonVisible.collectAsState(false)
+ val isMenuVisible: Boolean by viewModel.isMenuVisible.collectAsState(false)
+
+ UserSwitcherScreenStateless(
+ isFinishRequested = isFinishRequested,
+ users = users,
+ maxUserColumns = maxUserColumns,
+ menuActions = menuActions,
+ isOpenMenuButtonVisible = isOpenMenuButtonVisible,
+ isMenuVisible = isMenuVisible,
+ onMenuClosed = viewModel::onMenuClosed,
+ onOpenMenuButtonClicked = viewModel::onOpenMenuButtonClicked,
+ onCancelButtonClicked = viewModel::onCancelButtonClicked,
+ onFinished = {
+ onFinished()
+ viewModel.onFinished()
+ },
+ modifier = modifier,
+ )
+}
+
+@Composable
+private fun UserSwitcherScreenStateless(
+ isFinishRequested: Boolean,
+ users: List<UserViewModel>,
+ maxUserColumns: Int,
+ menuActions: List<UserActionViewModel>,
+ isOpenMenuButtonVisible: Boolean,
+ isMenuVisible: Boolean,
+ onMenuClosed: () -> Unit,
+ onOpenMenuButtonClicked: () -> Unit,
+ onCancelButtonClicked: () -> Unit,
+ onFinished: () -> Unit,
+ modifier: Modifier = Modifier,
+) {
+ LaunchedEffect(isFinishRequested) {
+ if (isFinishRequested) {
+ onFinished()
+ }
+ }
+
+ Box(
+ modifier =
+ modifier
+ .fillMaxSize()
+ .padding(
+ horizontal = 60.dp,
+ vertical = 40.dp,
+ ),
+ ) {
+ UserGrid(
+ users = users,
+ maxUserColumns = maxUserColumns,
+ modifier = Modifier.align(Alignment.Center),
+ )
+
+ Buttons(
+ menuActions = menuActions,
+ isOpenMenuButtonVisible = isOpenMenuButtonVisible,
+ isMenuVisible = isMenuVisible,
+ onMenuClosed = onMenuClosed,
+ onOpenMenuButtonClicked = onOpenMenuButtonClicked,
+ onCancelButtonClicked = onCancelButtonClicked,
+ modifier = Modifier.align(Alignment.BottomEnd),
+ )
+ }
+}
+
+@Composable
+private fun UserGrid(
+ users: List<UserViewModel>,
+ maxUserColumns: Int,
+ modifier: Modifier = Modifier,
+) {
+ Column(
+ horizontalAlignment = Alignment.CenterHorizontally,
+ verticalArrangement = Arrangement.spacedBy(44.dp),
+ modifier = modifier,
+ ) {
+ val rowCount = ceil(users.size / maxUserColumns.toFloat()).toInt()
+ (0 until rowCount).forEach { rowIndex ->
+ Row(
+ horizontalArrangement = Arrangement.spacedBy(64.dp),
+ modifier = modifier,
+ ) {
+ val fromIndex = rowIndex * maxUserColumns
+ val toIndex = min(users.size, (rowIndex + 1) * maxUserColumns)
+ users.subList(fromIndex, toIndex).forEach { user ->
+ UserItem(
+ viewModel = user,
+ )
+ }
+ }
+ }
+ }
+}
+
+@Composable
+private fun UserItem(
+ viewModel: UserViewModel,
+) {
+ val onClicked = viewModel.onClicked
+ Column(
+ horizontalAlignment = Alignment.CenterHorizontally,
+ modifier =
+ if (onClicked != null) {
+ Modifier.clickable { onClicked() }
+ } else {
+ Modifier
+ }
+ .alpha(viewModel.alpha),
+ ) {
+ Box {
+ UserItemBackground(modifier = Modifier.align(Alignment.Center).size(222.dp))
+
+ UserItemIcon(
+ image = viewModel.image,
+ isSelectionMarkerVisible = viewModel.isSelectionMarkerVisible,
+ modifier = Modifier.align(Alignment.Center).size(222.dp)
+ )
+ }
+
+ // User name
+ val text = viewModel.name.load()
+ if (text != null) {
+ // We use the box to center-align the text vertically as that is not possible with Text
+ // alone.
+ Box(
+ modifier = Modifier.size(width = 222.dp, height = 48.dp),
+ ) {
+ Text(
+ text = text,
+ style = MaterialTheme.typography.titleLarge,
+ color = colorResource(com.android.internal.R.color.system_neutral1_50),
+ maxLines = 1,
+ overflow = TextOverflow.Ellipsis,
+ modifier = Modifier.align(Alignment.Center),
+ )
+ }
+ }
+ }
+}
+
+@Composable
+private fun UserItemBackground(
+ modifier: Modifier = Modifier,
+) {
+ Image(
+ painter = ColorPainter(LocalAndroidColorScheme.current.colorBackground),
+ contentDescription = null,
+ modifier = modifier.clip(CircleShape),
+ )
+}
+
+@Composable
+private fun UserItemIcon(
+ image: Drawable,
+ isSelectionMarkerVisible: Boolean,
+ modifier: Modifier = Modifier,
+) {
+ Image(
+ bitmap = image.toBitmap().asImageBitmap(),
+ contentDescription = null,
+ modifier =
+ if (isSelectionMarkerVisible) {
+ // Draws a ring
+ modifier.border(
+ width = 8.dp,
+ color = LocalAndroidColorScheme.current.colorAccentPrimary,
+ shape = CircleShape,
+ )
+ } else {
+ modifier
+ }
+ .padding(16.dp)
+ .clip(CircleShape)
+ )
+}
+
+@Composable
+private fun Buttons(
+ menuActions: List<UserActionViewModel>,
+ isOpenMenuButtonVisible: Boolean,
+ isMenuVisible: Boolean,
+ onMenuClosed: () -> Unit,
+ onOpenMenuButtonClicked: () -> Unit,
+ onCancelButtonClicked: () -> Unit,
+ modifier: Modifier = Modifier,
+) {
+ Row(
+ modifier = modifier,
+ ) {
+ // Cancel button.
+ SysUiTextButton(
+ onClick = onCancelButtonClicked,
+ ) {
+ Text(stringResource(R.string.cancel))
+ }
+
+ // "Open menu" button.
+ if (isOpenMenuButtonVisible) {
+ Spacer(modifier = Modifier.width(8.dp))
+ // To properly use a DropdownMenu in Compose, we need to wrap the button that opens it
+ // and the menu itself in a Box.
+ Box {
+ SysUiOutlinedButton(
+ onClick = onOpenMenuButtonClicked,
+ ) {
+ Text(stringResource(R.string.add))
+ }
+ Menu(
+ viewModel = menuActions,
+ isMenuVisible = isMenuVisible,
+ onMenuClosed = onMenuClosed,
+ )
+ }
+ }
+ }
+}
+
+@Composable
+private fun Menu(
+ viewModel: List<UserActionViewModel>,
+ isMenuVisible: Boolean,
+ onMenuClosed: () -> Unit,
+ modifier: Modifier = Modifier,
+) {
+ val maxItemWidth = LocalConfiguration.current.screenWidthDp.dp / 4
+ DropdownMenu(
+ expanded = isMenuVisible,
+ onDismissRequest = onMenuClosed,
+ modifier =
+ modifier.background(
+ color = MaterialTheme.colorScheme.inverseOnSurface,
+ ),
+ ) {
+ viewModel.forEachIndexed { index, action ->
+ MenuItem(
+ viewModel = action,
+ onClicked = { action.onClicked() },
+ topPadding =
+ if (index == 0) {
+ 16.dp
+ } else {
+ 0.dp
+ },
+ bottomPadding =
+ if (index == viewModel.size - 1) {
+ 16.dp
+ } else {
+ 0.dp
+ },
+ modifier = Modifier.sizeIn(maxWidth = maxItemWidth),
+ )
+ }
+ }
+}
+
+@Composable
+private fun MenuItem(
+ viewModel: UserActionViewModel,
+ onClicked: () -> Unit,
+ topPadding: Dp,
+ bottomPadding: Dp,
+ modifier: Modifier = Modifier,
+) {
+ val context = LocalContext.current
+ val density = LocalDensity.current
+
+ val icon =
+ remember(viewModel.iconResourceId) {
+ val drawable =
+ checkNotNull(AppCompatResources.getDrawable(context, viewModel.iconResourceId))
+ drawable
+ .toBitmap(
+ size = with(density) { 20.dp.toPx() }.toInt(),
+ tintColor = Color.White,
+ )
+ .asImageBitmap()
+ }
+
+ DropdownMenuItem(
+ text = {
+ Text(
+ text = stringResource(viewModel.textResourceId),
+ style = MaterialTheme.typography.bodyMedium,
+ )
+ },
+ onClick = onClicked,
+ leadingIcon = {
+ Spacer(modifier = Modifier.width(10.dp))
+ Image(
+ bitmap = icon,
+ contentDescription = null,
+ )
+ },
+ modifier =
+ modifier
+ .heightIn(
+ min = 56.dp,
+ )
+ .padding(
+ start = 18.dp,
+ end = 65.dp,
+ top = topPadding,
+ bottom = bottomPadding,
+ ),
+ )
+}
+
+/**
+ * Converts the [Drawable] to a [Bitmap].
+ *
+ * Note that this is a relatively memory-heavy operation as it allocates a whole bitmap and draws
+ * the `Drawable` onto it. Use sparingly and with care.
+ */
+private fun Drawable.toBitmap(
+ size: Int? = null,
+ tintColor: Color? = null,
+): Bitmap {
+ val bitmap =
+ if (intrinsicWidth <= 0 || intrinsicHeight <= 0) {
+ Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888)
+ } else {
+ Bitmap.createBitmap(
+ size ?: intrinsicWidth,
+ size ?: intrinsicHeight,
+ Bitmap.Config.ARGB_8888
+ )
+ }
+ val canvas = Canvas(bitmap)
+ setBounds(0, 0, canvas.width, canvas.height)
+ if (tintColor != null) {
+ setTint(tintColor.toArgb())
+ }
+ draw(canvas)
+ return bitmap
+}
diff --git a/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/ButtonsScreen.kt b/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/ButtonsScreen.kt
new file mode 100644
index 0000000..881a1def
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/ButtonsScreen.kt
@@ -0,0 +1,77 @@
+/*
+ * 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(ExperimentalMaterial3Api::class)
+
+package com.android.systemui.compose.gallery
+
+import androidx.compose.foundation.layout.Column
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import com.android.systemui.compose.SysUiButton
+import com.android.systemui.compose.SysUiOutlinedButton
+import com.android.systemui.compose.SysUiTextButton
+
+@Composable
+fun ButtonsScreen(
+ modifier: Modifier = Modifier,
+) {
+ Column(
+ modifier = modifier,
+ ) {
+ SysUiButton(
+ onClick = {},
+ ) {
+ Text("SysUiButton")
+ }
+
+ SysUiButton(
+ onClick = {},
+ enabled = false,
+ ) {
+ Text("SysUiButton - disabled")
+ }
+
+ SysUiOutlinedButton(
+ onClick = {},
+ ) {
+ Text("SysUiOutlinedButton")
+ }
+
+ SysUiOutlinedButton(
+ onClick = {},
+ enabled = false,
+ ) {
+ Text("SysUiOutlinedButton - disabled")
+ }
+
+ SysUiTextButton(
+ onClick = {},
+ ) {
+ Text("SysUiTextButton")
+ }
+
+ SysUiTextButton(
+ onClick = {},
+ enabled = false,
+ ) {
+ Text("SysUiTextButton - disabled")
+ }
+ }
+}
diff --git a/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/GalleryApp.kt b/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/GalleryApp.kt
index bb98fb3..2e6456b 100644
--- a/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/GalleryApp.kt
+++ b/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/GalleryApp.kt
@@ -31,6 +31,7 @@
val Typography = ChildScreen("typography") { TypographyScreen() }
val MaterialColors = ChildScreen("material_colors") { MaterialColorsScreen() }
val AndroidColors = ChildScreen("android_colors") { AndroidColorsScreen() }
+ val Buttons = ChildScreen("buttons") { ButtonsScreen() }
val ExampleFeature = ChildScreen("example_feature") { ExampleFeatureScreen() }
val PeopleEmpty =
@@ -63,6 +64,7 @@
"Material colors" to MaterialColors,
"Android colors" to AndroidColors,
"Example feature" to ExampleFeature,
+ "Buttons" to Buttons,
"People" to People,
)
)
diff --git a/packages/SystemUI/compose/gallery/src/com/android/systemui/qs/footer/Fakes.kt b/packages/SystemUI/compose/gallery/src/com/android/systemui/qs/footer/Fakes.kt
index 11477f9..6588e22 100644
--- a/packages/SystemUI/compose/gallery/src/com/android/systemui/qs/footer/Fakes.kt
+++ b/packages/SystemUI/compose/gallery/src/com/android/systemui/qs/footer/Fakes.kt
@@ -83,7 +83,11 @@
flowOf(
securityText?.let { text ->
SecurityButtonConfig(
- icon = Icon.Resource(R.drawable.ic_info_outline),
+ icon =
+ Icon.Resource(
+ R.drawable.ic_info_outline,
+ contentDescription = null,
+ ),
text = text,
isClickable = securityClickable,
)
diff --git a/packages/SystemUI/compose/gallery/src/com/android/systemui/user/Fakes.kt b/packages/SystemUI/compose/gallery/src/com/android/systemui/user/Fakes.kt
new file mode 100644
index 0000000..02d76f4
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/src/com/android/systemui/user/Fakes.kt
@@ -0,0 +1,99 @@
+/*
+ * 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.user
+
+import android.content.Context
+import androidx.appcompat.content.res.AppCompatResources
+import com.android.systemui.common.shared.model.Text
+import com.android.systemui.compose.gallery.R
+import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
+import com.android.systemui.power.data.repository.FakePowerRepository
+import com.android.systemui.power.domain.interactor.PowerInteractor
+import com.android.systemui.user.data.repository.FakeUserRepository
+import com.android.systemui.user.domain.interactor.UserInteractor
+import com.android.systemui.user.shared.model.UserActionModel
+import com.android.systemui.user.shared.model.UserModel
+import com.android.systemui.user.ui.viewmodel.UserSwitcherViewModel
+import com.android.systemui.util.mockito.mock
+
+object Fakes {
+ private val USER_TINT_COLORS =
+ arrayOf(
+ 0x000000,
+ 0x0000ff,
+ 0x00ff00,
+ 0x00ffff,
+ 0xff0000,
+ 0xff00ff,
+ 0xffff00,
+ 0xffffff,
+ )
+
+ fun fakeUserSwitcherViewModel(
+ context: Context,
+ userCount: Int,
+ ): UserSwitcherViewModel {
+ return UserSwitcherViewModel.Factory(
+ userInteractor =
+ UserInteractor(
+ repository =
+ FakeUserRepository().apply {
+ setUsers(
+ (0 until userCount).map { index ->
+ UserModel(
+ id = index,
+ name = Text.Loaded("user_$index"),
+ image =
+ checkNotNull(
+ AppCompatResources.getDrawable(
+ context,
+ R.drawable.ic_avatar_guest_user
+ )
+ ),
+ isSelected = index == 0,
+ isSelectable = true,
+ )
+ }
+ )
+ setActions(
+ UserActionModel.values().mapNotNull {
+ if (it == UserActionModel.NAVIGATE_TO_USER_MANAGEMENT) {
+ null
+ } else {
+ it
+ }
+ }
+ )
+ },
+ controller = mock(),
+ activityStarter = mock(),
+ keyguardInteractor =
+ KeyguardInteractor(
+ repository =
+ FakeKeyguardRepository().apply { setKeyguardShowing(false) },
+ ),
+ ),
+ powerInteractor =
+ PowerInteractor(
+ repository = FakePowerRepository(),
+ )
+ )
+ .create(UserSwitcherViewModel::class.java)
+ }
+}
diff --git a/packages/SystemUI/ktfmt_includes.txt b/packages/SystemUI/ktfmt_includes.txt
index 51cc195..689938a 100644
--- a/packages/SystemUI/ktfmt_includes.txt
+++ b/packages/SystemUI/ktfmt_includes.txt
@@ -240,8 +240,6 @@
-packages/SystemUI/src/com/android/systemui/media/nearby/NearbyMediaDevicesManager.kt
-packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt
-packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttFlags.kt
--packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/ChipInfoCommon.kt
--packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt
-packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttLogger.kt
-packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/ChipStateReceiver.kt
-packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
@@ -529,6 +527,8 @@
-packages/SystemUI/src/com/android/systemui/statusbar/tv/VpnStatusObserver.kt
-packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowModule.kt
-packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowStateController.kt
+-packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewInfo.kt
+-packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt
-packages/SystemUI/src/com/android/systemui/toast/ToastDefaultAnimation.kt
-packages/SystemUI/src/com/android/systemui/toast/ToastLogger.kt
-packages/SystemUI/src/com/android/systemui/tv/TVSystemUICoreStartableModule.kt
@@ -677,7 +677,6 @@
-packages/SystemUI/tests/src/com/android/systemui/media/muteawait/MediaMuteAwaitConnectionManagerTest.kt
-packages/SystemUI/tests/src/com/android/systemui/media/nearby/NearbyMediaDevicesManagerTest.kt
-packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt
--packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt
-packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttLoggerTest.kt
-packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt
-packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt
@@ -834,6 +833,7 @@
-packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/VariableDateViewControllerTest.kt
-packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/WalletControllerImplTest.kt
-packages/SystemUI/tests/src/com/android/systemui/statusbar/window/StatusBarWindowStateControllerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt
-packages/SystemUI/tests/src/com/android/systemui/unfold/FoldStateLoggingProviderTest.kt
-packages/SystemUI/tests/src/com/android/systemui/unfold/UnfoldLatencyTrackerTest.kt
-packages/SystemUI/tests/src/com/android/systemui/unfold/UnfoldTransitionWallpaperControllerTest.kt
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
index 57193e7..436145e 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
@@ -16,6 +16,8 @@
import android.view.View;
+import androidx.annotation.FloatRange;
+
import com.android.systemui.plugins.FragmentBase;
import com.android.systemui.plugins.annotations.DependsOn;
import com.android.systemui.plugins.annotations.ProvidesInterface;
@@ -107,10 +109,24 @@
void setInSplitShade(boolean shouldTranslate);
/**
- * Set the amount of pixels we have currently dragged down if we're transitioning to the full
- * shade. 0.0f means we're not transitioning yet.
+ * Sets the progress of the transition to full shade on the lockscreen.
+ *
+ * @param isTransitioningToFullShade
+ * whether the transition to full shade is in progress. This might be {@code true}, even
+ * though {@code qsTransitionFraction} is still 0.
+ * The reason for that is that on some device configurations, the QS transition has a
+ * start delay compared to the overall transition.
+ *
+ * @param qsTransitionFraction
+ * the fraction of the QS transition progress, from 0 to 1.
+ *
+ * @param qsSquishinessFraction
+ * the fraction of the QS "squish" transition progress, from 0 to 1.
*/
- default void setTransitionToFullShadeAmount(float pxAmount, float progress) {}
+ default void setTransitionToFullShadeProgress(
+ boolean isTransitioningToFullShade,
+ @FloatRange(from = 0.0, to = 1.0) float qsTransitionFraction,
+ @FloatRange(from = 0.0, to = 1.0) float qsSquishinessFraction) {}
/**
* A rounded corner clipping that makes QS feel as if it were behind everything.
@@ -140,6 +156,12 @@
default void setOverScrollAmount(int overScrollAmount) {}
/**
+ * Sets whether the notification panel is using the full width of the screen. Typically true on
+ * small screens and false on large screens.
+ */
+ void setIsNotificationPanelFullWidth(boolean isFullWidth);
+
+ /**
* Callback for when QSPanel container is scrolled
*/
@ProvidesInterface(version = ScrollListener.VERSION)
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSContainerController.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSContainerController.kt
index 8bf982d..9c7fbe8 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSContainerController.kt
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSContainerController.kt
@@ -3,7 +3,9 @@
interface QSContainerController {
fun setCustomizerAnimating(animating: Boolean)
- fun setCustomizerShowing(showing: Boolean)
+ fun setCustomizerShowing(showing: Boolean) = setCustomizerShowing(showing, 0L)
+
+ fun setCustomizerShowing(showing: Boolean, animationDuration: Long)
fun setDetailShowing(showing: Boolean)
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/res-keyguard/drawable/qs_light_dark_theme_icon_off.xml b/packages/SystemUI/res-keyguard/drawable/qs_light_dark_theme_icon_off.xml
new file mode 100644
index 0000000..5c0a7c8
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/drawable/qs_light_dark_theme_icon_off.xml
@@ -0,0 +1,109 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ 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
+ -->
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <target android:name="_R_G_L_0_G_D_1_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="20"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M7.38 -2.03 C6.38,-4.66 3.47,-7.32 0.01,-7.32 C0.03,-6.22 -0.03,5.66 -0.03,7.28 C1.59,7.31 5.22,6.17 7.37,2.06 C7.37,1.21 7.37,0.69 7.37,0 C7.37,-0.91 7.38,-1.16 7.38,-2.03c "
+ android:valueTo="M7.25 -2.44 C5.46,-5.86 1.53,-8.3 -1.72,-7.1 C-1.73,-6.22 -1.73,5.88 -1.7,7.16 C0.25,8.45 4.43,6.91 7.28,2.47 C7.29,1.42 7.27,1.3 7.3,0 C7.32,-1.17 7.27,-1.49 7.25,-2.44c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="40"
+ android:propertyName="pathData"
+ android:startOffset="20"
+ android:valueFrom="M7.25 -2.44 C5.46,-5.86 1.53,-8.3 -1.72,-7.1 C-1.73,-6.22 -1.73,5.88 -1.7,7.16 C0.25,8.45 4.43,6.91 7.28,2.47 C7.29,1.42 7.27,1.3 7.3,0 C7.32,-1.17 7.27,-1.49 7.25,-2.44c "
+ android:valueTo="M7.06 -3.94 C3.5,-8.81 -3.31,-9.44 -7,-3.66 C-7.12,-3.47 -7.05,3 -6.94,3.22 C-3.63,9.31 2.94,9.19 7,3.59 C7.06,1.94 7,3.19 7.12,0 C7.19,-2 7.12,-2.75 7.06,-3.94c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="40"
+ android:propertyName="pathData"
+ android:startOffset="60"
+ android:valueFrom="M7.06 -3.94 C3.5,-8.81 -3.31,-9.44 -7,-3.66 C-7.12,-3.47 -7.05,3 -6.94,3.22 C-3.63,9.31 2.94,9.19 7,3.59 C7.06,1.94 7,3.19 7.12,0 C7.19,-2 7.12,-2.75 7.06,-3.94c "
+ android:valueTo="M3.11 -6.83 C-0.23,-9.49 -6.06,-6.24 -7.23,-2.29 C-7.28,-2.09 -7.23,1.85 -7.18,2.06 C-5.84,7.25 -0.33,9.23 3.14,6.75 C3.17,5.1 3.17,3.58 3.22,0 C3.25,-3.04 3.14,-5.1 3.11,-6.83c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="100"
+ android:propertyName="pathData"
+ android:startOffset="100"
+ android:valueFrom="M3.11 -6.83 C-0.23,-9.49 -6.06,-6.24 -7.23,-2.29 C-7.28,-2.09 -7.23,1.85 -7.18,2.06 C-5.84,7.25 -0.33,9.23 3.14,6.75 C3.17,5.1 3.17,3.58 3.22,0 C3.25,-3.04 3.14,-5.1 3.11,-6.83c "
+ android:valueTo="M0 -7.49 C-2.58,-7.49 -7.45,-4.78 -7.45,-1.62 C-7.45,-1.42 -7.37,0.88 -7.37,1.09 C-7.37,6.31 -2.19,7.55 0,7.55 C0,5.91 -0.01,3.91 -0.01,0 C-0.01,-3.91 0,-5.31 0,-7.49c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="217"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+ <aapt:attr name="android:drawable">
+ <vector
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportHeight="24"
+ android:viewportWidth="24">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_0_G"
+ android:translateX="12"
+ android:translateY="12">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M0 -7.08 C-2.69,-7.08 -7.03,-5.19 -7.03,0.03 C-7.03,5.25 -2.19,7.08 0,7.08 C3.03,7.08 7.08,3.91 7.08,0 C7.08,-3.91 3.69,-7.08 0,-7.08c M-8.33 0 C-8.33,-4.6 -4.6,-8.33 0,-8.33 C4.6,-8.33 8.33,-4.6 8.33,0 C8.33,4.6 4.6,8.33 0,8.33 C-4.6,8.33 -8.33,4.6 -8.33,0c " />
+ <path
+ android:name="_R_G_L_0_G_D_1_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M7.38 -2.03 C6.38,-4.66 3.47,-7.32 0.01,-7.32 C0.03,-6.22 -0.03,5.66 -0.03,7.28 C1.59,7.31 5.22,6.17 7.37,2.06 C7.37,1.21 7.37,0.69 7.37,0 C7.37,-0.91 7.38,-1.16 7.38,-2.03c " />
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+</animated-vector>
diff --git a/packages/SystemUI/res-keyguard/drawable/qs_light_dark_theme_icon_on.xml b/packages/SystemUI/res-keyguard/drawable/qs_light_dark_theme_icon_on.xml
new file mode 100644
index 0000000..a96b748
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/drawable/qs_light_dark_theme_icon_on.xml
@@ -0,0 +1,109 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ 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
+ -->
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <target android:name="_R_G_L_0_G_D_1_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="100"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M0 -7.49 C-2.58,-7.49 -7.45,-4.78 -7.45,-1.62 C-7.45,-1.42 -7.37,0.88 -7.37,1.09 C-7.37,6.31 -2.19,7.55 0,7.55 C0,5.91 -0.01,3.91 -0.01,0 C-0.01,-3.91 0,-5.31 0,-7.49c "
+ android:valueTo="M3.11 -6.83 C-0.23,-9.49 -6.06,-6.24 -7.23,-2.29 C-7.28,-2.09 -7.23,1.85 -7.18,2.06 C-5.84,7.25 -0.33,9.23 3.14,6.75 C3.17,5.1 3.17,3.58 3.22,0 C3.25,-3.04 3.14,-5.1 3.11,-6.83c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="67"
+ android:propertyName="pathData"
+ android:startOffset="100"
+ android:valueFrom="M3.11 -6.83 C-0.23,-9.49 -6.06,-6.24 -7.23,-2.29 C-7.28,-2.09 -7.23,1.85 -7.18,2.06 C-5.84,7.25 -0.33,9.23 3.14,6.75 C3.17,5.1 3.17,3.58 3.22,0 C3.25,-3.04 3.14,-5.1 3.11,-6.83c "
+ android:valueTo="M7.06 -3.94 C3.5,-8.81 -3.31,-9.44 -7,-3.66 C-7.12,-3.47 -7.05,3 -6.94,3.22 C-3.63,9.31 2.94,9.19 7,3.59 C7.06,1.94 7,3.19 7.12,0 C7.19,-2 7.12,-2.75 7.06,-3.94c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="67"
+ android:propertyName="pathData"
+ android:startOffset="167"
+ android:valueFrom="M7.06 -3.94 C3.5,-8.81 -3.31,-9.44 -7,-3.66 C-7.12,-3.47 -7.05,3 -6.94,3.22 C-3.63,9.31 2.94,9.19 7,3.59 C7.06,1.94 7,3.19 7.12,0 C7.19,-2 7.12,-2.75 7.06,-3.94c "
+ android:valueTo="M7.25 -2.44 C5.46,-5.86 1.53,-8.3 -1.72,-7.1 C-1.73,-6.22 -1.73,5.88 -1.7,7.16 C0.25,8.45 4.43,6.91 7.28,2.47 C7.29,1.42 7.27,1.3 7.3,0 C7.32,-1.17 7.27,-1.49 7.25,-2.44c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="100"
+ android:propertyName="pathData"
+ android:startOffset="233"
+ android:valueFrom="M7.25 -2.44 C5.46,-5.86 1.53,-8.3 -1.72,-7.1 C-1.73,-6.22 -1.73,5.88 -1.7,7.16 C0.25,8.45 4.43,6.91 7.28,2.47 C7.29,1.42 7.27,1.3 7.3,0 C7.32,-1.17 7.27,-1.49 7.25,-2.44c "
+ android:valueTo="M7.38 -2.03 C6.38,-4.66 3.47,-7.32 0.01,-7.32 C0.03,-6.22 -0.03,5.66 -0.03,7.28 C1.59,7.31 5.22,6.17 7.37,2.06 C7.37,1.21 7.37,0.69 7.37,0 C7.37,-0.91 7.38,-1.16 7.38,-2.03c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="350"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+ <aapt:attr name="android:drawable">
+ <vector
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportHeight="24"
+ android:viewportWidth="24">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_0_G"
+ android:translateX="12"
+ android:translateY="12">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#edf2eb"
+ android:fillType="nonZero"
+ android:pathData=" M0 -7.08 C-2.69,-7.08 -7.03,-5.19 -7.03,0.03 C-7.03,5.25 -2.19,7.08 0,7.08 C3.03,7.08 7.08,3.91 7.08,0 C7.08,-3.91 3.69,-7.08 0,-7.08c M-8.33 0 C-8.33,-4.6 -4.6,-8.33 0,-8.33 C4.6,-8.33 8.33,-4.6 8.33,0 C8.33,4.6 4.6,8.33 0,8.33 C-4.6,8.33 -8.33,4.6 -8.33,0c " />
+ <path
+ android:name="_R_G_L_0_G_D_1_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#edf2eb"
+ android:fillType="nonZero"
+ android:pathData=" M0 -7.49 C-2.58,-7.49 -7.45,-4.78 -7.45,-1.62 C-7.45,-1.42 -7.37,0.88 -7.37,1.09 C-7.37,6.31 -2.19,7.55 0,7.55 C0,5.91 -0.01,3.91 -0.01,0 C-0.01,-3.91 0,-5.31 0,-7.49c " />
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+</animated-vector>
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_message_area.xml b/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_message_area.xml
new file mode 100644
index 0000000..57b3acd
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_message_area.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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
+ -->
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+ <com.android.keyguard.BouncerKeyguardMessageArea
+ android:id="@+id/bouncer_message_area"
+ style="@style/Keyguard.TextView"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/keyguard_lock_padding"
+ android:ellipsize="marquee"
+ android:focusable="true"
+ android:gravity="center"
+ android:singleLine="true" />
+</merge>
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_password_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_password_view.xml
index e77e084..5486adb 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_password_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_password_view.xml
@@ -28,6 +28,7 @@
android:layout_gravity="center_horizontal|bottom"
android:gravity="bottom"
>
+ <include layout="@layout/keyguard_bouncer_message_area"/>
<Space
android:layout_width="match_parent"
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_pattern_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_pattern_view.xml
index 231ead8..2b7bdc2 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_pattern_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_pattern_view.xml
@@ -31,6 +31,7 @@
android:layout_gravity="center_horizontal|bottom"
android:clipChildren="false"
android:clipToPadding="false">
+ <include layout="@layout/keyguard_bouncer_message_area"/>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/pattern_container"
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml
index 712f657..64ece47 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml
@@ -17,23 +17,25 @@
*/
-->
-<com.android.keyguard.KeyguardPINView
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:androidprv="http://schemas.android.com/apk/res-auto"
- xmlns:tools="http://schemas.android.com/tools"
- android:id="@+id/keyguard_pin_view"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- androidprv:layout_maxWidth="@dimen/keyguard_security_width"
- android:layout_gravity="center_horizontal|bottom"
- android:orientation="vertical"
- >
+<com.android.keyguard.KeyguardPINView xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/keyguard_pin_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="center_horizontal|bottom"
+ android:clipChildren="false"
+ android:clipToPadding="false"
+ android:orientation="vertical"
+ androidprv:layout_maxWidth="@dimen/keyguard_security_width">
+<include layout="@layout/keyguard_bouncer_message_area"/>
- <androidx.constraintlayout.widget.ConstraintLayout
+<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/pin_container"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginBottom="8dp"
+ android:clipChildren="false"
+ android:clipToPadding="false"
android:layout_weight="1"
android:layoutDirection="ltr"
android:orientation="vertical">
@@ -79,6 +81,8 @@
android:layout_width="0dp"
android:layout_height="0dp"
android:orientation="horizontal"
+ android:clipChildren="false"
+ android:clipToPadding="false"
androidprv:constraint_referenced_ids="key1,key2,key3,key4,key5,key6,key7,key8,key9,delete_button,key0,key_enter"
@@ -186,8 +190,6 @@
</androidx.constraintlayout.widget.ConstraintLayout>
-
-
<include layout="@layout/keyguard_eca"
android:id="@+id/keyguard_selector_fade_container"
android:layout_width="match_parent"
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_sim_pin_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_sim_pin_view.xml
index dae2e56..f2fe520 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_sim_pin_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_sim_pin_view.xml
@@ -26,20 +26,17 @@
android:layout_height="match_parent"
androidprv:layout_maxWidth="@dimen/keyguard_security_width"
android:layout_gravity="center_horizontal|bottom">
-
- <Space
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1"
- />
-
+ <include layout="@layout/keyguard_bouncer_message_area" />
+ <Space
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1" />
<ImageView
android:id="@+id/keyguard_sim"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:tint="@color/background_protected"
android:src="@drawable/ic_lockscreen_sim"/>
-
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -52,14 +49,12 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/eca_overlap" />
-
<RelativeLayout
android:id="@+id/row0"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="4dp"
>
-
<com.android.keyguard.PasswordTextView
android:id="@+id/simPinEntry"
style="@style/Widget.TextView.Password"
@@ -195,7 +190,6 @@
/>
</LinearLayout>
</LinearLayout>
-
<include layout="@layout/keyguard_eca"
android:id="@+id/keyguard_selector_fade_container"
android:layout_width="match_parent"
@@ -205,5 +199,4 @@
android:layout_marginTop="@dimen/keyguard_eca_top_margin"
android:layout_marginBottom="2dp"
android:gravity="center_horizontal"/>
-
</com.android.keyguard.KeyguardSimPinView>
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_sim_puk_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_sim_puk_view.xml
index 74f7820..a21ec29 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_sim_puk_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_sim_puk_view.xml
@@ -27,12 +27,12 @@
android:layout_height="match_parent"
androidprv:layout_maxWidth="@dimen/keyguard_security_width"
android:layout_gravity="center_horizontal|bottom">
+ <include layout="@layout/keyguard_bouncer_message_area"/>
- <Space
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1"
- />
+ <Space
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1" />
<ImageView
android:id="@+id/keyguard_sim"
diff --git a/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml b/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml
index fc9c402..9dc054a 100644
--- a/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml
@@ -53,7 +53,7 @@
<string name="kg_wrong_pattern" msgid="5907301342430102842">"Patrón incorrecto"</string>
<string name="kg_wrong_password" msgid="4143127991071670512">"Contraseña incorrecta"</string>
<string name="kg_wrong_pin" msgid="4160978845968732624">"PIN incorrecto"</string>
- <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Vuelve a intentarlo en # segundo.}other{Vuelve a intentarlo en # segundos.}}"</string>
+ <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Vuelve a intentarlo en # segundo.}many{Vuelve a intentarlo en # segundos.}other{Vuelve a intentarlo en # segundos.}}"</string>
<string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Ingresa el PIN de la tarjeta SIM."</string>
<string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Ingresa el PIN de la tarjeta SIM de \"<xliff:g id="CARRIER">%1$s</xliff:g>\"."</string>
<string name="kg_sim_lock_esim_instructions" msgid="5577169988158738030">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> Inhabilita la tarjeta eSIM para usar el dispositivo sin servicio móvil."</string>
@@ -68,9 +68,9 @@
<string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Escribiste tu contraseña <xliff:g id="NUMBER_0">%1$d</xliff:g> veces de manera incorrecta. \n\nVuelve a intentarlo en <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
<string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Dibujaste tu patrón de desbloqueo <xliff:g id="NUMBER_0">%1$d</xliff:g> veces de manera incorrecta. \n\nVuelve a intentarlo en <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
<string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"El código PIN de la tarjeta SIM es incorrecto. Debes comunicarte con tu proveedor para desbloquear el dispositivo."</string>
- <string name="kg_password_wrong_pin_code" msgid="5629415765976820357">"{count,plural, =1{El código PIN de la tarjeta SIM es incorrecto. Tienes # intento restante antes de que debas comunicarte con tu operador para desbloquear el dispositivo.}other{El código PIN de la tarjeta SIM es incorrecto. Tienes # intentos restantes. }}"</string>
+ <string name="kg_password_wrong_pin_code" msgid="5629415765976820357">"{count,plural, =1{El código PIN de la tarjeta SIM es incorrecto. Tienes # intento restante antes de que debas comunicarte con tu operador para desbloquear el dispositivo.}many{El código PIN de la tarjeta SIM es incorrecto. Tienes # intentos restantes. }other{El código PIN de la tarjeta SIM es incorrecto. Tienes # intentos restantes. }}"</string>
<string name="kg_password_wrong_puk_code_dead" msgid="3698285357028468617">"La tarjeta SIM no se puede usar. Comunícate con tu proveedor."</string>
- <string name="kg_password_wrong_puk_code" msgid="6820515467645087827">"{count,plural, =1{El código PUK de la tarjeta SIM es incorrecto. Tienes # intento restante antes de que la tarjeta SIM quede inutilizable permanentemente.}other{El código PUK de la tarjeta SIM es incorrecto. Tienes # intentos restantes antes de que la tarjeta SIM quede inutilizable permanentemente.}}"</string>
+ <string name="kg_password_wrong_puk_code" msgid="6820515467645087827">"{count,plural, =1{El código PUK de la tarjeta SIM es incorrecto. Tienes # intento restante antes de que la tarjeta SIM quede inutilizable permanentemente.}many{El código PUK de la tarjeta SIM es incorrecto. Tienes # intentos restantes antes de que la tarjeta SIM quede inutilizable permanentemente.}other{El código PUK de la tarjeta SIM es incorrecto. Tienes # intentos restantes antes de que la tarjeta SIM quede inutilizable permanentemente.}}"</string>
<string name="kg_password_pin_failed" msgid="5136259126330604009">"Se produjo un error al desbloquear la tarjeta SIM con el PIN."</string>
<string name="kg_password_puk_failed" msgid="6778867411556937118">"Se produjo un error al desbloquear la tarjeta SIM con el PUK."</string>
<string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Cambiar método de entrada"</string>
@@ -85,8 +85,8 @@
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"El dispositivo se bloqueó de forma manual"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"No se reconoció"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="939511161763558512">"Activa acceso a cámara en Config. y usa Desb. facial"</string>
- <string name="kg_password_default_pin_message" msgid="1434544655827987873">"{count,plural, =1{Ingresa el PIN de la tarjeta SIM. Tienes # intento restante antes de que debas comunicarte con tu operador para desbloquear el dispositivo.}other{Ingresa el PIN de la tarjeta SIM. Tienes # intentos restantes.}}"</string>
- <string name="kg_password_default_puk_message" msgid="1025139786449741950">"{count,plural, =1{Se inhabilitó la tarjeta SIM. Para continuar, ingresa el código PUK. Tienes # intento restante antes de que la SIM quede inutilizable permanentemente. Comunícate con tu operador para conocer más detalles.}other{Se inhabilitó la tarjeta SIM. Para continuar, ingresa el código PUK. Tienes # intentos restantes antes de que la SIM quede inutilizable permanentemente. Comunícate con tu operador para conocer más detalles.}}"</string>
+ <string name="kg_password_default_pin_message" msgid="1434544655827987873">"{count,plural, =1{Ingresa el PIN de la tarjeta SIM. Tienes # intento restante antes de que debas comunicarte con tu operador para desbloquear el dispositivo.}many{Ingresa el PIN de la tarjeta SIM. Tienes # intentos restantes.}other{Ingresa el PIN de la tarjeta SIM. Tienes # intentos restantes.}}"</string>
+ <string name="kg_password_default_puk_message" msgid="1025139786449741950">"{count,plural, =1{Se inhabilitó la tarjeta SIM. Para continuar, ingresa el código PUK. Tienes # intento restante antes de que la SIM quede inutilizable permanentemente. Comunícate con tu operador para conocer más detalles.}many{Se inhabilitó la tarjeta SIM. Para continuar, ingresa el código PUK. Tienes # intentos restantes antes de que la SIM quede inutilizable permanentemente. Comunícate con tu operador para conocer más detalles.}other{Se inhabilitó la tarjeta SIM. Para continuar, ingresa el código PUK. Tienes # intentos restantes antes de que la SIM quede inutilizable permanentemente. Comunícate con tu operador para conocer más detalles.}}"</string>
<string name="clock_title_default" msgid="6342735240617459864">"Predeterminado"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Burbuja"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analógico"</string>
diff --git a/packages/SystemUI/res-keyguard/values-es/strings.xml b/packages/SystemUI/res-keyguard/values-es/strings.xml
index 4053161..f9f0452 100644
--- a/packages/SystemUI/res-keyguard/values-es/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-es/strings.xml
@@ -53,7 +53,7 @@
<string name="kg_wrong_pattern" msgid="5907301342430102842">"Patrón incorrecto"</string>
<string name="kg_wrong_password" msgid="4143127991071670512">"Contraseña incorrecta"</string>
<string name="kg_wrong_pin" msgid="4160978845968732624">"PIN incorrecto"</string>
- <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Vuelve a intentarlo en # segundo.}other{Vuelve a intentarlo en # segundos.}}"</string>
+ <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Vuelve a intentarlo en # segundo.}many{Vuelve a intentarlo en # segundos.}other{Vuelve a intentarlo en # segundos.}}"</string>
<string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Introduce el PIN de la tarjeta SIM."</string>
<string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Introduce el PIN de la tarjeta SIM de <xliff:g id="CARRIER">%1$s</xliff:g>."</string>
<string name="kg_sim_lock_esim_instructions" msgid="5577169988158738030">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> Inhabilita la tarjeta eSIM para usar el dispositivo sin servicio móvil."</string>
@@ -68,9 +68,9 @@
<string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Has fallado <xliff:g id="NUMBER_0">%1$d</xliff:g> veces al introducir la contraseña. \n\nVuelve a intentarlo dentro de <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
<string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Has fallado <xliff:g id="NUMBER_0">%1$d</xliff:g> veces al dibujar el patrón de desbloqueo. \n\nVuelve a intentarlo dentro de <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
<string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"El código PIN de la tarjeta SIM es incorrecto. Debes ponerte en contacto con tu operador para desbloquear el dispositivo."</string>
- <string name="kg_password_wrong_pin_code" msgid="5629415765976820357">"{count,plural, =1{Código PIN de la SIM incorrecto. Te queda # intento antes de tener que ponerte en contacto con tu operador para desbloquear el dispositivo.}other{Código PIN de la SIM incorrecto. Te quedan # intentos. }}"</string>
+ <string name="kg_password_wrong_pin_code" msgid="5629415765976820357">"{count,plural, =1{Código PIN de la SIM incorrecto. Te queda # intento antes de tener que ponerte en contacto con tu operador para desbloquear el dispositivo.}many{Código PIN de la SIM incorrecto. Te quedan # intentos. }other{Código PIN de la SIM incorrecto. Te quedan # intentos. }}"</string>
<string name="kg_password_wrong_puk_code_dead" msgid="3698285357028468617">"La tarjeta SIM no se puede utilizar. Ponte en contacto con tu operador."</string>
- <string name="kg_password_wrong_puk_code" msgid="6820515467645087827">"{count,plural, =1{Código PUK de la SIM incorrecto. Te queda # intento antes de que la SIM quede inservible permanentemente.}other{Código PUK de la SIM incorrecto. Te quedan # intentos antes de que la SIM quede inservible permanentemente.}}"</string>
+ <string name="kg_password_wrong_puk_code" msgid="6820515467645087827">"{count,plural, =1{Código PUK de la SIM incorrecto. Te queda # intento antes de que la SIM quede inservible permanentemente.}many{Código PUK de la SIM incorrecto. Te quedan # intentos antes de que la SIM quede inservible permanentemente.}other{Código PUK de la SIM incorrecto. Te quedan # intentos antes de que la SIM quede inservible permanentemente.}}"</string>
<string name="kg_password_pin_failed" msgid="5136259126330604009">"No se ha podido desbloquear la tarjeta SIM con el código PIN."</string>
<string name="kg_password_puk_failed" msgid="6778867411556937118">"No se ha podido desbloquear la tarjeta SIM con el código PUK."</string>
<string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Cambiar método de introducción"</string>
@@ -85,8 +85,8 @@
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"El dispositivo se ha bloqueado manualmente"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"No se reconoce"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="939511161763558512">"Desbloqueo facial: activa el acceso a la cámara"</string>
- <string name="kg_password_default_pin_message" msgid="1434544655827987873">"{count,plural, =1{Introduce el PIN de la SIM. Te queda # intento antes de tener que ponerte en contacto con tu operador para desbloquear el dispositivo.}other{Introduce el PIN de la SIM. Te quedan # intentos.}}"</string>
- <string name="kg_password_default_puk_message" msgid="1025139786449741950">"{count,plural, =1{La SIM se ha inhabilitado. Introduce el código PUK para continuar. Te queda # intento antes de que la SIM quede inservible permanentemente. Ponte en contacto con tu operador para obtener más información.}other{La SIM se ha inhabilitado. Introduce el código PUK para continuar. Te quedan # intentos antes de que la SIM quede inservible permanentemente. Ponte en contacto con tu operador para obtener más información.}}"</string>
+ <string name="kg_password_default_pin_message" msgid="1434544655827987873">"{count,plural, =1{Introduce el PIN de la SIM. Te queda # intento antes de tener que ponerte en contacto con tu operador para desbloquear el dispositivo.}many{Introduce el PIN de la SIM. Te quedan # intentos.}other{Introduce el PIN de la SIM. Te quedan # intentos.}}"</string>
+ <string name="kg_password_default_puk_message" msgid="1025139786449741950">"{count,plural, =1{La SIM se ha inhabilitado. Introduce el código PUK para continuar. Te queda # intento antes de que la SIM quede inservible permanentemente. Ponte en contacto con tu operador para obtener más información.}many{La SIM se ha inhabilitado. Introduce el código PUK para continuar. Te quedan # intentos antes de que la SIM quede inservible permanentemente. Ponte en contacto con tu operador para obtener más información.}other{La SIM se ha inhabilitado. Introduce el código PUK para continuar. Te quedan # intentos antes de que la SIM quede inservible permanentemente. Ponte en contacto con tu operador para obtener más información.}}"</string>
<string name="clock_title_default" msgid="6342735240617459864">"Predeterminado"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Burbuja"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analógico"</string>
diff --git a/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml b/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml
index 92ab77e..077fe11 100644
--- a/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml
@@ -53,7 +53,7 @@
<string name="kg_wrong_pattern" msgid="5907301342430102842">"Schéma incorrect"</string>
<string name="kg_wrong_password" msgid="4143127991071670512">"Mot de passe incorrect"</string>
<string name="kg_wrong_pin" msgid="4160978845968732624">"NIP incorrect"</string>
- <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Réessayez dans # seconde.}one{Réessayez dans # seconde.}other{Réessayez dans # secondes.}}"</string>
+ <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Réessayez dans # seconde.}one{Réessayez dans # seconde.}many{Réessayez dans # secondes.}other{Réessayez dans # secondes.}}"</string>
<string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Entrez le NIP de la carte SIM."</string>
<string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Entrez le NIP de la carte SIM pour « <xliff:g id="CARRIER">%1$s</xliff:g> »."</string>
<string name="kg_sim_lock_esim_instructions" msgid="5577169988158738030">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> Désactivez la carte eSIM pour utiliser l\'appareil sans service cellulaire."</string>
@@ -68,9 +68,9 @@
<string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Vous avez entré un mot de passe incorrect à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises.\n\nVeuillez réessayer dans <xliff:g id="NUMBER_1">%2$d</xliff:g> secondes."</string>
<string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises.\n\nVeuillez réessayer dans <xliff:g id="NUMBER_1">%2$d</xliff:g> secondes."</string>
<string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"NIP de carte SIM incorrect. Vous devez maintenant communiquer avec votre fournisseur de services pour déverrouiller votre appareil."</string>
- <string name="kg_password_wrong_pin_code" msgid="5629415765976820357">"{count,plural, =1{NIP de la carte SIM incorrect. Il vous reste # tentative. Après cela, vous devrez communiquer avec votre fournisseur de services pour déverrouiller votre appareil.}one{NIP de la carte SIM incorrect. Il vous reste # tentative. }other{NIP de la carte SIM incorrect. Il vous reste # tentatives. }}"</string>
+ <string name="kg_password_wrong_pin_code" msgid="5629415765976820357">"{count,plural, =1{NIP de la carte SIM incorrect. Il vous reste # tentative. Après cela, vous devrez communiquer avec votre fournisseur de services pour déverrouiller votre appareil.}one{NIP de la carte SIM incorrect. Il vous reste # tentative. }many{NIP de la carte SIM incorrect. Il vous reste # de tentatives. }other{NIP de la carte SIM incorrect. Il vous reste # tentatives. }}"</string>
<string name="kg_password_wrong_puk_code_dead" msgid="3698285357028468617">"La carte SIM est inutilisable. Communiquez avec votre fournisseur de services."</string>
- <string name="kg_password_wrong_puk_code" msgid="6820515467645087827">"{count,plural, =1{Code PUK de la carte SIM incorrect. Il vous reste # tentative avant que votre carte SIM devienne définitivement inutilisable.}one{Code PUK de la carte SIM incorrect. Il vous reste # tentative avant que votre carte SIM devienne définitivement inutilisable.}other{Code PUK de la carte SIM incorrect. Il vous reste # tentatives avant que votre carte SIM devienne définitivement inutilisable.}}"</string>
+ <string name="kg_password_wrong_puk_code" msgid="6820515467645087827">"{count,plural, =1{Code PUK de la carte SIM incorrect. Il vous reste # tentative avant que votre carte SIM devienne définitivement inutilisable.}one{Code PUK de la carte SIM incorrect. Il vous reste # tentative avant que votre carte SIM devienne définitivement inutilisable.}many{Code PUK de la carte SIM incorrect. Il vous reste # de tentatives avant que votre carte SIM devienne définitivement inutilisable.}other{Code PUK de la carte SIM incorrect. Il vous reste # tentatives avant que votre carte SIM devienne définitivement inutilisable.}}"</string>
<string name="kg_password_pin_failed" msgid="5136259126330604009">"Le déverrouillage par NIP de la carte SIM a échoué."</string>
<string name="kg_password_puk_failed" msgid="6778867411556937118">"Le déverrouillage de la carte SIM par code PUK a échoué."</string>
<string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Changer de méthode d\'entrée"</string>
@@ -85,8 +85,8 @@
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"L\'appareil a été verrouillé manuellement"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Doigt non reconnu"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="939511161763558512">"Déverr. rec. faciale : activez accès app. photo dans Param."</string>
- <string name="kg_password_default_pin_message" msgid="1434544655827987873">"{count,plural, =1{Entrez le NIP de la carte SIM. Il vous reste # tentative. Après cela, vous devrez communiquer avec votre fournisseur de services pour déverrouiller votre appareil.}one{Entrez le NIP de la carte SIM. Il vous reste # tentative.}other{Entrez le NIP de la carte SIM. Il vous reste # tentatives.}}"</string>
- <string name="kg_password_default_puk_message" msgid="1025139786449741950">"{count,plural, =1{La carte SIM est maintenant désactivée. Entrez le code PUK pour continuer. Il vous reste # tentative avant que votre carte SIM devienne définitivement inutilisable. Communiquez avec votre fournisseur de services pour en savoir plus.}one{La carte SIM est maintenant désactivée. Entrez le code PUK pour continuer. Il vous reste # tentative avant que votre carte SIM devienne définitivement inutilisable. Communiquez avec votre fournisseur de services pour en savoir plus.}other{La carte SIM est maintenant désactivée. Entrez le code PUK pour continuer. Il vous reste # tentatives avant que votre carte SIM devienne définitivement inutilisable. Communiquez avec votre fournisseur de services pour en savoir plus.}}"</string>
+ <string name="kg_password_default_pin_message" msgid="1434544655827987873">"{count,plural, =1{Entrez le NIP de la carte SIM. Il vous reste # tentative. Après cela, vous devrez communiquer avec votre fournisseur de services pour déverrouiller votre appareil.}one{Entrez le NIP de la carte SIM. Il vous reste # tentative.}many{Entrez le NIP de la carte SIM. Il vous reste # de tentatives.}other{Entrez le NIP de la carte SIM. Il vous reste # tentatives.}}"</string>
+ <string name="kg_password_default_puk_message" msgid="1025139786449741950">"{count,plural, =1{La carte SIM est maintenant désactivée. Entrez le code PUK pour continuer. Il vous reste # tentative avant que votre carte SIM devienne définitivement inutilisable. Communiquez avec votre fournisseur de services pour en savoir plus.}one{La carte SIM est maintenant désactivée. Entrez le code PUK pour continuer. Il vous reste # tentative avant que votre carte SIM devienne définitivement inutilisable. Communiquez avec votre fournisseur de services pour en savoir plus.}many{La carte SIM est maintenant désactivée. Entrez le code PUK pour continuer. Il vous reste # de tentatives avant que votre carte SIM devienne définitivement inutilisable. Communiquez avec votre fournisseur de services pour en savoir plus.}other{La carte SIM est maintenant désactivée. Entrez le code PUK pour continuer. Il vous reste # tentatives avant que votre carte SIM devienne définitivement inutilisable. Communiquez avec votre fournisseur de services pour en savoir plus.}}"</string>
<string name="clock_title_default" msgid="6342735240617459864">"Par défaut"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Bulle"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analogique"</string>
diff --git a/packages/SystemUI/res-keyguard/values-fr/strings.xml b/packages/SystemUI/res-keyguard/values-fr/strings.xml
index 01facd1..62379f8 100644
--- a/packages/SystemUI/res-keyguard/values-fr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fr/strings.xml
@@ -53,7 +53,7 @@
<string name="kg_wrong_pattern" msgid="5907301342430102842">"Schéma incorrect"</string>
<string name="kg_wrong_password" msgid="4143127991071670512">"Mot de passe incorrect"</string>
<string name="kg_wrong_pin" msgid="4160978845968732624">"Code incorrect"</string>
- <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Réessayez dans # seconde.}one{Réessayez dans # seconde.}other{Réessayez dans # secondes.}}"</string>
+ <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Réessayez dans # seconde.}one{Réessayez dans # seconde.}many{Réessayez dans # secondes.}other{Réessayez dans # secondes.}}"</string>
<string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Saisissez le code PIN de la carte SIM."</string>
<string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Saisissez le code PIN de la carte SIM \"<xliff:g id="CARRIER">%1$s</xliff:g>\"."</string>
<string name="kg_sim_lock_esim_instructions" msgid="5577169988158738030">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> Désactivez la carte eSIM pour utiliser l\'appareil sans service mobile."</string>
@@ -68,9 +68,9 @@
<string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Vous avez saisi un mot de passe incorrect à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises.\n\nRéessayez dans <xliff:g id="NUMBER_1">%2$d</xliff:g> secondes."</string>
<string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises.\n\nRéessayez dans <xliff:g id="NUMBER_1">%2$d</xliff:g> secondes."</string>
<string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Code PIN de la carte SIM incorrect. Vous devez désormais contacter votre opérateur pour déverrouiller votre appareil."</string>
- <string name="kg_password_wrong_pin_code" msgid="5629415765976820357">"{count,plural, =1{Code PIN SIM incorrect. Il vous reste # tentative avant de devoir contacter votre opérateur pour déverrouiller l\'appareil.}one{Code PIN SIM incorrect. Il vous reste # tentative. }other{Code PIN SIM incorrect. Il vous reste # tentatives. }}"</string>
+ <string name="kg_password_wrong_pin_code" msgid="5629415765976820357">"{count,plural, =1{Code PIN SIM incorrect. Il vous reste # tentative avant de devoir contacter votre opérateur pour déverrouiller l\'appareil.}one{Code PIN SIM incorrect. Il vous reste # tentative. }many{Code PIN SIM incorrect. Il vous reste # tentatives. }other{Code PIN SIM incorrect. Il vous reste # tentatives. }}"</string>
<string name="kg_password_wrong_puk_code_dead" msgid="3698285357028468617">"La carte SIM est inutilisable. Contactez votre opérateur."</string>
- <string name="kg_password_wrong_puk_code" msgid="6820515467645087827">"{count,plural, =1{Clé PUK de la SIM incorrecte. Il vous reste # tentative avant que la SIM ne devienne définitivement inutilisable.}one{Clé PUK de la SIM incorrecte. Il vous reste # tentative avant que la carte SIM ne devienne définitivement inutilisable.}other{Clé PUK de la SIM incorrecte. Il vous reste # tentatives avant que la carte SIM ne devienne définitivement inutilisable.}}"</string>
+ <string name="kg_password_wrong_puk_code" msgid="6820515467645087827">"{count,plural, =1{Clé PUK de la SIM incorrecte. Il vous reste # tentative avant que la SIM ne devienne définitivement inutilisable.}one{Clé PUK de la SIM incorrecte. Il vous reste # tentative avant que la carte SIM ne devienne définitivement inutilisable.}many{Clé PUK de la SIM incorrecte. Il vous reste # tentatives avant que la carte SIM ne devienne définitivement inutilisable.}other{Clé PUK de la SIM incorrecte. Il vous reste # tentatives avant que la carte SIM ne devienne définitivement inutilisable.}}"</string>
<string name="kg_password_pin_failed" msgid="5136259126330604009">"Échec du déverrouillage à l\'aide du code PIN de la carte SIM."</string>
<string name="kg_password_puk_failed" msgid="6778867411556937118">"Échec du déverrouillage à l\'aide de la clé PUK de la carte SIM."</string>
<string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Changer le mode de saisie"</string>
@@ -85,8 +85,8 @@
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Appareil verrouillé manuellement"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Non reconnu"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="939511161763558512">"Pour le déverrouillage par reconnaissance faciale, activez l\'accès à l\'app. photo dans Paramètres"</string>
- <string name="kg_password_default_pin_message" msgid="1434544655827987873">"{count,plural, =1{Saisissez le code PIN SIM. Il vous reste # tentative avant de devoir contacter votre opérateur pour déverrouiller l\'appareil.}one{Saisissez le code PIN SIM. Il vous reste # tentative.}other{Saisissez le code PIN SIM. Il vous reste # tentatives.}}"</string>
- <string name="kg_password_default_puk_message" msgid="1025139786449741950">"{count,plural, =1{La SIM est maintenant désactivée. Saisissez la clé PUK pour continuer. Il vous reste # tentative avant que la SIM ne devienne définitivement inutilisable. Pour plus d\'infos, contactez votre opérateur.}one{La SIM est maintenant désactivée. Saisissez la clé PUK pour continuer. Il vous reste # tentative avant que la SIM ne devienne définitivement inutilisable. Pour plus d\'infos, contactez votre opérateur.}other{La SIM est maintenant désactivée. Saisissez la clé PUK pour continuer. Il vous reste # tentatives avant que la SIM ne devienne définitivement inutilisable. Pour plus d\'infos, contactez votre opérateur.}}"</string>
+ <string name="kg_password_default_pin_message" msgid="1434544655827987873">"{count,plural, =1{Saisissez le code PIN SIM. Il vous reste # tentative avant de devoir contacter votre opérateur pour déverrouiller l\'appareil.}one{Saisissez le code PIN SIM. Il vous reste # tentative.}many{Saisissez le code PIN SIM. Il vous reste # tentatives.}other{Saisissez le code PIN SIM. Il vous reste # tentatives.}}"</string>
+ <string name="kg_password_default_puk_message" msgid="1025139786449741950">"{count,plural, =1{La SIM est maintenant désactivée. Saisissez la clé PUK pour continuer. Il vous reste # tentative avant que la SIM ne devienne définitivement inutilisable. Pour plus d\'infos, contactez votre opérateur.}one{La SIM est maintenant désactivée. Saisissez la clé PUK pour continuer. Il vous reste # tentative avant que la SIM ne devienne définitivement inutilisable. Pour plus d\'infos, contactez votre opérateur.}many{La SIM est maintenant désactivée. Saisissez la clé PUK pour continuer. Il vous reste # tentatives avant que la SIM ne devienne définitivement inutilisable. Pour plus d\'infos, contactez votre opérateur.}other{La SIM est maintenant désactivée. Saisissez la clé PUK pour continuer. Il vous reste # tentatives avant que la SIM ne devienne définitivement inutilisable. Pour plus d\'infos, contactez votre opérateur.}}"</string>
<string name="clock_title_default" msgid="6342735240617459864">"Par défaut"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Bulle"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analogique"</string>
diff --git a/packages/SystemUI/res-keyguard/values-it/strings.xml b/packages/SystemUI/res-keyguard/values-it/strings.xml
index d3a683b..9fed5f7 100644
--- a/packages/SystemUI/res-keyguard/values-it/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-it/strings.xml
@@ -53,7 +53,7 @@
<string name="kg_wrong_pattern" msgid="5907301342430102842">"Sequenza errata"</string>
<string name="kg_wrong_password" msgid="4143127991071670512">"Password errata"</string>
<string name="kg_wrong_pin" msgid="4160978845968732624">"PIN errato"</string>
- <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Riprova fra # secondo.}other{Riprova fra # secondi.}}"</string>
+ <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Riprova fra # secondo.}many{Riprova fra # secondi.}other{Riprova fra # secondi.}}"</string>
<string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Inserisci il PIN della SIM."</string>
<string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Inserisci il PIN della SIM \"<xliff:g id="CARRIER">%1$s</xliff:g>\"."</string>
<string name="kg_sim_lock_esim_instructions" msgid="5577169988158738030">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> Disattiva la eSIM per usare il dispositivo senza servizio dati mobile."</string>
@@ -68,9 +68,9 @@
<string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Hai digitato la tua password <xliff:g id="NUMBER_0">%1$d</xliff:g> volte in modo errato. \n\nRiprova tra <xliff:g id="NUMBER_1">%2$d</xliff:g> secondi."</string>
<string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"<xliff:g id="NUMBER_0">%1$d</xliff:g> tentativi errati di inserimento della sequenza di sblocco. \n\nRiprova tra <xliff:g id="NUMBER_1">%2$d</xliff:g> secondi."</string>
<string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Codice PIN della SIM errato. Devi contattare l\'operatore per sbloccare il dispositivo."</string>
- <string name="kg_password_wrong_pin_code" msgid="5629415765976820357">"{count,plural, =1{Codice PIN della SIM errato. Hai ancora # tentativo a disposizione, dopodiché dovrai contattare l\'operatore per sbloccare il dispositivo.}other{Codice PIN della SIM errato. Hai ancora # tentativi a disposizione. }}"</string>
+ <string name="kg_password_wrong_pin_code" msgid="5629415765976820357">"{count,plural, =1{Codice PIN della SIM errato. Hai ancora # tentativo a disposizione, dopodiché dovrai contattare l\'operatore per sbloccare il dispositivo.}many{Codice PIN della SIM errato. Hai ancora # tentativi a disposizione. }other{Codice PIN della SIM errato. Hai ancora # tentativi a disposizione. }}"</string>
<string name="kg_password_wrong_puk_code_dead" msgid="3698285357028468617">"SIM inutilizzabile. Contatta il tuo operatore."</string>
- <string name="kg_password_wrong_puk_code" msgid="6820515467645087827">"{count,plural, =1{Codice PUK della SIM errato. Hai ancora # tentativo a disposizione prima che la SIM diventi definitivamente inutilizzabile.}other{Codice PUK della SIM errato. Hai ancora # tentativi a disposizione prima che la SIM diventi definitivamente inutilizzabile.}}"</string>
+ <string name="kg_password_wrong_puk_code" msgid="6820515467645087827">"{count,plural, =1{Codice PUK della SIM errato. Hai ancora # tentativo a disposizione prima che la SIM diventi definitivamente inutilizzabile.}many{Codice PUK della SIM errato. Hai ancora # tentativi a disposizione prima che la SIM diventi definitivamente inutilizzabile.}other{Codice PUK della SIM errato. Hai ancora # tentativi a disposizione prima che la SIM diventi definitivamente inutilizzabile.}}"</string>
<string name="kg_password_pin_failed" msgid="5136259126330604009">"Operazione con PIN della SIM non riuscita."</string>
<string name="kg_password_puk_failed" msgid="6778867411556937118">"Operazione con PUK della SIM non riuscita."</string>
<string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Cambia metodo di immissione"</string>
@@ -85,8 +85,8 @@
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Il dispositivo è stato bloccato manualmente"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Non riconosciuto"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="939511161763558512">"Sblocco con volto richiede l\'accesso alla fotocamera"</string>
- <string name="kg_password_default_pin_message" msgid="1434544655827987873">"{count,plural, =1{Inserisci il codice PIN della SIM. Hai ancora # tentativo a disposizione, dopodiché dovrai contattare l\'operatore per sbloccare il dispositivo.}other{Inserisci il PIN della SIM. Hai a disposizione ancora # tentativi.}}"</string>
- <string name="kg_password_default_puk_message" msgid="1025139786449741950">"{count,plural, =1{La scheda SIM è ora disattivata. Inserisci il codice PUK per continuare. Hai ancora # tentativo a disposizione prima che la SIM diventi definitivamente inutilizzabile. Per informazioni dettagliate, contatta l\'operatore.}other{La scheda SIM è ora disattivata. Inserisci il codice PUK per continuare. Hai ancora # tentativi a disposizione prima che la SIM diventi definitivamente inutilizzabile. Per informazioni dettagliate, contatta l\'operatore.}}"</string>
+ <string name="kg_password_default_pin_message" msgid="1434544655827987873">"{count,plural, =1{Inserisci il codice PIN della SIM. Hai ancora # tentativo a disposizione, dopodiché dovrai contattare l\'operatore per sbloccare il dispositivo.}many{Inserisci il PIN della SIM. Hai a disposizione ancora # tentativi.}other{Inserisci il PIN della SIM. Hai a disposizione ancora # tentativi.}}"</string>
+ <string name="kg_password_default_puk_message" msgid="1025139786449741950">"{count,plural, =1{La scheda SIM è ora disattivata. Inserisci il codice PUK per continuare. Hai ancora # tentativo a disposizione prima che la SIM diventi definitivamente inutilizzabile. Per informazioni dettagliate, contatta l\'operatore.}many{La scheda SIM è ora disattivata. Inserisci il codice PUK per continuare. Hai ancora # tentativi a disposizione prima che la SIM diventi definitivamente inutilizzabile. Per informazioni dettagliate, contatta l\'operatore.}other{La scheda SIM è ora disattivata. Inserisci il codice PUK per continuare. Hai ancora # tentativi a disposizione prima che la SIM diventi definitivamente inutilizzabile. Per informazioni dettagliate, contatta l\'operatore.}}"</string>
<string name="clock_title_default" msgid="6342735240617459864">"Predefinito"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Bolla"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analogico"</string>
diff --git a/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml b/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml
index 76ced12..b934826 100644
--- a/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml
@@ -53,7 +53,7 @@
<string name="kg_wrong_pattern" msgid="5907301342430102842">"Padrão incorreto"</string>
<string name="kg_wrong_password" msgid="4143127991071670512">"Senha incorreta"</string>
<string name="kg_wrong_pin" msgid="4160978845968732624">"PIN incorreto"</string>
- <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Tente novamente em # segundo.}one{Tente novamente em # segundo.}other{Tente novamente em # segundos.}}"</string>
+ <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Tente novamente em # segundo.}one{Tente novamente em # segundo.}many{Tente novamente em # segundos.}other{Tente novamente em # segundos.}}"</string>
<string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Informe o PIN do chip."</string>
<string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Informe o PIN do chip para \"<xliff:g id="CARRIER">%1$s</xliff:g>\"."</string>
<string name="kg_sim_lock_esim_instructions" msgid="5577169988158738030">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> Desative o eSIM para usar o dispositivo sem serviço móvel."</string>
@@ -68,9 +68,9 @@
<string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Você digitou sua senha incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. \n\nTente novamente em <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
<string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. \n\nTente novamente em <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
<string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Código PIN do chip incorreto. Entre em contato com a operadora para desbloquear o dispositivo."</string>
- <string name="kg_password_wrong_pin_code" msgid="5629415765976820357">"{count,plural, =1{Código PIN do chip incorreto. Você tem # tentativa restante. Se o código correto não for digitado, será necessário entrar em contato com a operadora para desbloquear o dispositivo.}one{Código PIN do chip incorreto. Você tem # tentativa restante. }other{Código PIN do chip incorreto. Você tem # tentativas restantes. }}"</string>
+ <string name="kg_password_wrong_pin_code" msgid="5629415765976820357">"{count,plural, =1{Código PIN do chip incorreto. Você tem # tentativa restante. Se o código correto não for digitado, será necessário entrar em contato com a operadora para desbloquear o dispositivo.}one{Código PIN do chip incorreto. Você tem # tentativa restante. }many{Código PIN do chip incorreto. Você tem # de tentativas restantes. }other{Código PIN do chip incorreto. Você tem # tentativas restantes. }}"</string>
<string name="kg_password_wrong_puk_code_dead" msgid="3698285357028468617">"O chip não pode ser utilizado. Entre em contato com a operadora."</string>
- <string name="kg_password_wrong_puk_code" msgid="6820515467645087827">"{count,plural, =1{Código PUK do chip incorreto. Você tem # tentativa restante. Se o código correto não for digitado, o chip vai ficar permanentemente inutilizável.}one{Código PUK do chip incorreto. Você tem # tentativa restante. Se o código correto não for digitado, o chip vai ficar permanentemente inutilizável.}other{Código PUK do chip incorreto. Você tem # tentativas restantes. Se o código correto não for digitado, o chip vai ficar permanentemente inutilizável.}}"</string>
+ <string name="kg_password_wrong_puk_code" msgid="6820515467645087827">"{count,plural, =1{Código PUK do chip incorreto. Você tem # tentativa restante. Se o código correto não for digitado, o chip vai ficar permanentemente inutilizável.}one{Código PUK do chip incorreto. Você tem # tentativa restante. Se o código correto não for digitado, o chip vai ficar permanentemente inutilizável.}many{Código PUK do chip incorreto. Você tem # de tentativas restantes. Se o código correto não for digitado, o chip vai ficar permanentemente inutilizável.}other{Código PUK do chip incorreto. Você tem # tentativas restantes. Se o código correto não for digitado, o chip vai ficar permanentemente inutilizável.}}"</string>
<string name="kg_password_pin_failed" msgid="5136259126330604009">"Falha na operação de PIN do chip."</string>
<string name="kg_password_puk_failed" msgid="6778867411556937118">"Falha na operação de PUK do chip."</string>
<string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Alterar o método de entrada"</string>
@@ -85,8 +85,8 @@
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"O dispositivo foi bloqueado manualmente"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Não reconhecido"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="939511161763558512">"Para usar o Desbloqueio facial, ative o acesso à câmera nas Configurações"</string>
- <string name="kg_password_default_pin_message" msgid="1434544655827987873">"{count,plural, =1{Informe o PIN do chip. Você tem # tentativa restante antes de precisar entrar em contato com a operadora para desbloquear seu dispositivo.}one{Informe o PIN do chip. Você tem # tentativa restante.}other{Informe o PIN do chip. Você tem # tentativas restantes.}}"</string>
- <string name="kg_password_default_puk_message" msgid="1025139786449741950">"{count,plural, =1{O chip está desativado. Informe o código PUK para continuar. Você tem # tentativa restante antes que o chip fique permanentemente inutilizável. Consulte sua operadora para saber mais.}one{O chip está desativado. Informe o código PUK para continuar. Você tem # tentativa restante antes que o chip fique permanentemente inutilizável. Consulte sua operadora para saber mais.}other{O chip está desativado. Informe o código PUK para continuar. Você tem # tentativas restantes antes que o chip fique permanentemente inutilizável. Consulte sua operadora para saber mais.}}"</string>
+ <string name="kg_password_default_pin_message" msgid="1434544655827987873">"{count,plural, =1{Informe o PIN do chip. Você tem # tentativa restante antes de precisar entrar em contato com a operadora para desbloquear seu dispositivo.}one{Informe o PIN do chip. Você tem # tentativa restante.}many{Informe o PIN do chip. Você tem # de tentativas restantes.}other{Informe o PIN do chip. Você tem # tentativas restantes.}}"</string>
+ <string name="kg_password_default_puk_message" msgid="1025139786449741950">"{count,plural, =1{O chip está desativado. Informe o código PUK para continuar. Você tem # tentativa restante antes que o chip fique permanentemente inutilizável. Consulte sua operadora para saber mais.}one{O chip está desativado. Informe o código PUK para continuar. Você tem # tentativa restante antes que o chip fique permanentemente inutilizável. Consulte sua operadora para saber mais.}many{O chip está desativado. Informe o código PUK para continuar. Você tem # de tentativas restantes antes que o chip fique permanentemente inutilizável. Consulte sua operadora para saber mais.}other{O chip está desativado. Informe o código PUK para continuar. Você tem # tentativas restantes antes que o chip fique permanentemente inutilizável. Consulte sua operadora para saber mais.}}"</string>
<string name="clock_title_default" msgid="6342735240617459864">"Padrão"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Bolha"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analógico"</string>
diff --git a/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml b/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml
index 94afc5f..a67bfb0 100644
--- a/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml
@@ -53,7 +53,7 @@
<string name="kg_wrong_pattern" msgid="5907301342430102842">"Padrão incorreto."</string>
<string name="kg_wrong_password" msgid="4143127991071670512">"Palavra-passe incorreta."</string>
<string name="kg_wrong_pin" msgid="4160978845968732624">"PIN incorreto"</string>
- <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Tente novamente dentro de # segundo.}other{Tente novamente dentro de # segundos.}}"</string>
+ <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Tente novamente dentro de # segundo.}many{Tente novamente dentro de # segundos.}other{Tente novamente dentro de # segundos.}}"</string>
<string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Introduza o PIN do cartão SIM."</string>
<string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Introduza o PIN do cartão SIM \"<xliff:g id="CARRIER">%1$s</xliff:g>\"."</string>
<string name="kg_sim_lock_esim_instructions" msgid="5577169988158738030">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> Desative o eSIM para utilizar o dispositivo sem serviço móvel."</string>
@@ -68,9 +68,9 @@
<string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Introduziu a palavra-passe incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. \n\nTente novamente dentro de <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
<string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Desenhou a sua padrão de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. \n\nTente novamente dentro de <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
<string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Código PIN do cartão SIM incorreto. Tem de contactar o seu operador para desbloquear o dispositivo."</string>
- <string name="kg_password_wrong_pin_code" msgid="5629415765976820357">"{count,plural, =1{Código PIN do SIM incorreto. Tem mais # tentativa antes de ser necessário contactar o operador para desbloquear o dispositivo.}other{Código PIN do SIM incorreto. Tem mais # tentativas. }}"</string>
+ <string name="kg_password_wrong_pin_code" msgid="5629415765976820357">"{count,plural, =1{Código PIN do SIM incorreto. Tem mais # tentativa antes de ser necessário contactar o operador para desbloquear o dispositivo.}many{Código PIN do SIM incorreto. Tem mais # tentativas. }other{Código PIN do SIM incorreto. Tem mais # tentativas. }}"</string>
<string name="kg_password_wrong_puk_code_dead" msgid="3698285357028468617">"Cartão SIM inutilizável. Contacte o seu operador."</string>
- <string name="kg_password_wrong_puk_code" msgid="6820515467645087827">"{count,plural, =1{Código PUK do SIM incorreto. Tem mais # tentativa antes de o SIM ficar permanentemente inutilizável.}other{Código PUK do SIM incorreto. Tem mais # tentativas antes de o SIM ficar permanentemente inutilizável.}}"</string>
+ <string name="kg_password_wrong_puk_code" msgid="6820515467645087827">"{count,plural, =1{Código PUK do SIM incorreto. Tem mais # tentativa antes de o SIM ficar permanentemente inutilizável.}many{Código PUK do SIM incorreto. Tem mais # tentativas antes de o SIM ficar permanentemente inutilizável.}other{Código PUK do SIM incorreto. Tem mais # tentativas antes de o SIM ficar permanentemente inutilizável.}}"</string>
<string name="kg_password_pin_failed" msgid="5136259126330604009">"Falha ao introduzir o PIN do cartão SIM!"</string>
<string name="kg_password_puk_failed" msgid="6778867411556937118">"Falha ao introduzir o PUK do cartão SIM!"</string>
<string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Alternar o método de introdução"</string>
@@ -85,8 +85,8 @@
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"O dispositivo foi bloqueado manualmente"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Não reconhecido."</string>
<string name="kg_face_sensor_privacy_enabled" msgid="939511161763558512">"Ative acesso à câmara nas Def. p/ usar Desbl. facial"</string>
- <string name="kg_password_default_pin_message" msgid="1434544655827987873">"{count,plural, =1{Introduza o PIN do SIM. Tem mais # tentativa antes de ser necessário contactar o operador para desbloquear o dispositivo.}other{Introduza o PIN do SIM. Tem mais # tentativas.}}"</string>
- <string name="kg_password_default_puk_message" msgid="1025139786449741950">"{count,plural, =1{O SIM está desativado. Introduza o código PUK para continuar. Tem mais # tentativa antes de o SIM ficar permanentemente inutilizável. Contacte o operador para obter mais detalhes.}other{O SIM está desativado. Introduza o código PUK para continuar. Tem mais # tentativas antes de o SIM ficar permanentemente inutilizável. Contacte o operador para obter mais detalhes.}}"</string>
+ <string name="kg_password_default_pin_message" msgid="1434544655827987873">"{count,plural, =1{Introduza o PIN do SIM. Tem mais # tentativa antes de ser necessário contactar o operador para desbloquear o dispositivo.}many{Introduza o PIN do SIM. Tem mais # tentativas.}other{Introduza o PIN do SIM. Tem mais # tentativas.}}"</string>
+ <string name="kg_password_default_puk_message" msgid="1025139786449741950">"{count,plural, =1{O SIM está desativado. Introduza o código PUK para continuar. Tem mais # tentativa antes de o SIM ficar permanentemente inutilizável. Contacte o operador para obter mais detalhes.}many{O SIM está desativado. Introduza o código PUK para continuar. Tem mais # tentativas antes de o SIM ficar permanentemente inutilizável. Contacte o operador para obter mais detalhes.}other{O SIM está desativado. Introduza o código PUK para continuar. Tem mais # tentativas antes de o SIM ficar permanentemente inutilizável. Contacte o operador para obter mais detalhes.}}"</string>
<string name="clock_title_default" msgid="6342735240617459864">"Predefinido"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Balão"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analógico"</string>
diff --git a/packages/SystemUI/res-keyguard/values-pt/strings.xml b/packages/SystemUI/res-keyguard/values-pt/strings.xml
index 76ced12..b934826 100644
--- a/packages/SystemUI/res-keyguard/values-pt/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pt/strings.xml
@@ -53,7 +53,7 @@
<string name="kg_wrong_pattern" msgid="5907301342430102842">"Padrão incorreto"</string>
<string name="kg_wrong_password" msgid="4143127991071670512">"Senha incorreta"</string>
<string name="kg_wrong_pin" msgid="4160978845968732624">"PIN incorreto"</string>
- <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Tente novamente em # segundo.}one{Tente novamente em # segundo.}other{Tente novamente em # segundos.}}"</string>
+ <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Tente novamente em # segundo.}one{Tente novamente em # segundo.}many{Tente novamente em # segundos.}other{Tente novamente em # segundos.}}"</string>
<string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Informe o PIN do chip."</string>
<string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Informe o PIN do chip para \"<xliff:g id="CARRIER">%1$s</xliff:g>\"."</string>
<string name="kg_sim_lock_esim_instructions" msgid="5577169988158738030">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> Desative o eSIM para usar o dispositivo sem serviço móvel."</string>
@@ -68,9 +68,9 @@
<string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Você digitou sua senha incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. \n\nTente novamente em <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
<string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. \n\nTente novamente em <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
<string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Código PIN do chip incorreto. Entre em contato com a operadora para desbloquear o dispositivo."</string>
- <string name="kg_password_wrong_pin_code" msgid="5629415765976820357">"{count,plural, =1{Código PIN do chip incorreto. Você tem # tentativa restante. Se o código correto não for digitado, será necessário entrar em contato com a operadora para desbloquear o dispositivo.}one{Código PIN do chip incorreto. Você tem # tentativa restante. }other{Código PIN do chip incorreto. Você tem # tentativas restantes. }}"</string>
+ <string name="kg_password_wrong_pin_code" msgid="5629415765976820357">"{count,plural, =1{Código PIN do chip incorreto. Você tem # tentativa restante. Se o código correto não for digitado, será necessário entrar em contato com a operadora para desbloquear o dispositivo.}one{Código PIN do chip incorreto. Você tem # tentativa restante. }many{Código PIN do chip incorreto. Você tem # de tentativas restantes. }other{Código PIN do chip incorreto. Você tem # tentativas restantes. }}"</string>
<string name="kg_password_wrong_puk_code_dead" msgid="3698285357028468617">"O chip não pode ser utilizado. Entre em contato com a operadora."</string>
- <string name="kg_password_wrong_puk_code" msgid="6820515467645087827">"{count,plural, =1{Código PUK do chip incorreto. Você tem # tentativa restante. Se o código correto não for digitado, o chip vai ficar permanentemente inutilizável.}one{Código PUK do chip incorreto. Você tem # tentativa restante. Se o código correto não for digitado, o chip vai ficar permanentemente inutilizável.}other{Código PUK do chip incorreto. Você tem # tentativas restantes. Se o código correto não for digitado, o chip vai ficar permanentemente inutilizável.}}"</string>
+ <string name="kg_password_wrong_puk_code" msgid="6820515467645087827">"{count,plural, =1{Código PUK do chip incorreto. Você tem # tentativa restante. Se o código correto não for digitado, o chip vai ficar permanentemente inutilizável.}one{Código PUK do chip incorreto. Você tem # tentativa restante. Se o código correto não for digitado, o chip vai ficar permanentemente inutilizável.}many{Código PUK do chip incorreto. Você tem # de tentativas restantes. Se o código correto não for digitado, o chip vai ficar permanentemente inutilizável.}other{Código PUK do chip incorreto. Você tem # tentativas restantes. Se o código correto não for digitado, o chip vai ficar permanentemente inutilizável.}}"</string>
<string name="kg_password_pin_failed" msgid="5136259126330604009">"Falha na operação de PIN do chip."</string>
<string name="kg_password_puk_failed" msgid="6778867411556937118">"Falha na operação de PUK do chip."</string>
<string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Alterar o método de entrada"</string>
@@ -85,8 +85,8 @@
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"O dispositivo foi bloqueado manualmente"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Não reconhecido"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="939511161763558512">"Para usar o Desbloqueio facial, ative o acesso à câmera nas Configurações"</string>
- <string name="kg_password_default_pin_message" msgid="1434544655827987873">"{count,plural, =1{Informe o PIN do chip. Você tem # tentativa restante antes de precisar entrar em contato com a operadora para desbloquear seu dispositivo.}one{Informe o PIN do chip. Você tem # tentativa restante.}other{Informe o PIN do chip. Você tem # tentativas restantes.}}"</string>
- <string name="kg_password_default_puk_message" msgid="1025139786449741950">"{count,plural, =1{O chip está desativado. Informe o código PUK para continuar. Você tem # tentativa restante antes que o chip fique permanentemente inutilizável. Consulte sua operadora para saber mais.}one{O chip está desativado. Informe o código PUK para continuar. Você tem # tentativa restante antes que o chip fique permanentemente inutilizável. Consulte sua operadora para saber mais.}other{O chip está desativado. Informe o código PUK para continuar. Você tem # tentativas restantes antes que o chip fique permanentemente inutilizável. Consulte sua operadora para saber mais.}}"</string>
+ <string name="kg_password_default_pin_message" msgid="1434544655827987873">"{count,plural, =1{Informe o PIN do chip. Você tem # tentativa restante antes de precisar entrar em contato com a operadora para desbloquear seu dispositivo.}one{Informe o PIN do chip. Você tem # tentativa restante.}many{Informe o PIN do chip. Você tem # de tentativas restantes.}other{Informe o PIN do chip. Você tem # tentativas restantes.}}"</string>
+ <string name="kg_password_default_puk_message" msgid="1025139786449741950">"{count,plural, =1{O chip está desativado. Informe o código PUK para continuar. Você tem # tentativa restante antes que o chip fique permanentemente inutilizável. Consulte sua operadora para saber mais.}one{O chip está desativado. Informe o código PUK para continuar. Você tem # tentativa restante antes que o chip fique permanentemente inutilizável. Consulte sua operadora para saber mais.}many{O chip está desativado. Informe o código PUK para continuar. Você tem # de tentativas restantes antes que o chip fique permanentemente inutilizável. Consulte sua operadora para saber mais.}other{O chip está desativado. Informe o código PUK para continuar. Você tem # tentativas restantes antes que o chip fique permanentemente inutilizável. Consulte sua operadora para saber mais.}}"</string>
<string name="clock_title_default" msgid="6342735240617459864">"Padrão"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Bolha"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analógico"</string>
diff --git a/packages/SystemUI/res-keyguard/values/dimens.xml b/packages/SystemUI/res-keyguard/values/dimens.xml
index 32871f0..ac131ae 100644
--- a/packages/SystemUI/res-keyguard/values/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values/dimens.xml
@@ -84,6 +84,10 @@
<!-- The translation for disappearing security views after having solved them. -->
<dimen name="disappear_y_translation">-32dp</dimen>
+ <!-- Dimens for animation for the Bouncer PIN view -->
+ <dimen name="pin_view_trans_y_entry">120dp</dimen>
+ <dimen name="pin_view_trans_y_entry_offset">10dp</dimen>
+
<!-- Spacing around each button used for PIN view -->
<dimen name="num_pad_key_width">72dp</dimen>
<dimen name="num_pad_entry_row_margin_bottom">12dp</dimen>
diff --git a/packages/SystemUI/res-keyguard/values/styles.xml b/packages/SystemUI/res-keyguard/values/styles.xml
index 625ffd3..a1d1266 100644
--- a/packages/SystemUI/res-keyguard/values/styles.xml
+++ b/packages/SystemUI/res-keyguard/values/styles.xml
@@ -50,7 +50,7 @@
<item name="android:background">@null</item>
<item name="android:textSize">32sp</item>
<item name="android:textColor">?android:attr/textColorPrimary</item>
- <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
+ <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
<item name="android:paddingBottom">-16dp</item>
</style>
<style name="Widget.TextView.Password" parent="@android:style/Widget.TextView">
diff --git a/packages/SystemUI/res/drawable/ic_present_to_all.xml b/packages/SystemUI/res/drawable/ic_present_to_all.xml
new file mode 100644
index 0000000..d6c9bbe
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_present_to_all.xml
@@ -0,0 +1,25 @@
+ <!--
+ ~ 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.
+ -->
+ <vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M21,3L3,3c-1.11,0 -2,0.89 -2,2v14c0,1.11 0.89,2 2,2h18c1.11,0 2,-0.89 2,-2L23,5c0,-1.11 -0.89,-2 -2,-2zM21,19.02L3,19.02L3,4.98h18v14.04zM8,12l4,-4 4,4 -1.41,1.41L13,11.83L13,16h-2v-4.17l-1.59,1.59L8,12z"/>
+ </vector>
diff --git a/packages/SystemUI/res/drawable/media_output_dialog_background.xml b/packages/SystemUI/res/drawable/media_output_dialog_background.xml
new file mode 100644
index 0000000..40bfd83
--- /dev/null
+++ b/packages/SystemUI/res/drawable/media_output_dialog_background.xml
@@ -0,0 +1,22 @@
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <corners
+ android:radius="28dp"/>
+ <solid android:color="@color/media_dialog_background" />
+</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/media_seekbar_thumb.xml b/packages/SystemUI/res/drawable/media_seekbar_thumb.xml
new file mode 100644
index 0000000..5eb2bfd
--- /dev/null
+++ b/packages/SystemUI/res/drawable/media_seekbar_thumb.xml
@@ -0,0 +1,50 @@
+<!--
+ ~ 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.
+ -->
+
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector android:height="16dp"
+ android:width="4dp"
+ android:viewportHeight="16"
+ android:viewportWidth="4">
+ <group android:name="_R_G">
+ <group android:name="_R_G_L_0_G"
+ android:translateX="2"
+ android:translateY="8">
+ <path android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillColor="#ffffff"
+ android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M2 -6 C2,-6 2,6 2,6 C2,7.1 1.1,8 0,8 C0,8 0,8 0,8 C-1.1,8 -2,7.1 -2,6 C-2,6 -2,-6 -2,-6 C-2,-7.1 -1.1,-8 0,-8 C0,-8 0,-8 0,-8 C1.1,-8 2,-7.1 2,-6c "/>
+ </group>
+ </group>
+ <group android:name="time_group"/>
+ </vector>
+ </aapt:attr>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="translateX"
+ android:duration="1017"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType"/>
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector>
diff --git a/packages/SystemUI/res/layout/auth_biometric_contents.xml b/packages/SystemUI/res/layout/auth_biometric_contents.xml
index d633803..be76405 100644
--- a/packages/SystemUI/res/layout/auth_biometric_contents.xml
+++ b/packages/SystemUI/res/layout/auth_biometric_contents.xml
@@ -51,7 +51,7 @@
android:id="@+id/biometric_icon_frame"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_gravity="center_horizontal">
+ android:layout_gravity="center">
<com.airbnb.lottie.LottieAnimationView
android:id="@+id/biometric_icon"
@@ -61,6 +61,13 @@
android:contentDescription="@null"
android:scaleType="fitXY" />
+ <com.airbnb.lottie.LottieAnimationView
+ android:id="@+id/biometric_icon_overlay"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:contentDescription="@null"
+ android:scaleType="fitXY" />
</FrameLayout>
<!-- For sensors such as UDFPS, this view is used during custom measurement/layout to add extra
diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
index 0ca19d9..8df8c49 100644
--- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml
+++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
@@ -83,48 +83,6 @@
android:layout_marginBottom="@dimen/keyguard_affordance_vertical_offset"
android:visibility="gone" />
- <ImageView
- android:id="@+id/wallet_button"
- android:layout_height="@dimen/keyguard_affordance_fixed_height"
- android:layout_width="@dimen/keyguard_affordance_fixed_width"
- android:layout_gravity="bottom|end"
- android:scaleType="center"
- android:tint="?android:attr/textColorPrimary"
- android:src="@drawable/ic_wallet_lockscreen"
- android:background="@drawable/keyguard_bottom_affordance_bg"
- android:layout_marginEnd="@dimen/keyguard_affordance_horizontal_offset"
- android:layout_marginBottom="@dimen/keyguard_affordance_vertical_offset"
- android:contentDescription="@string/accessibility_wallet_button"
- android:visibility="gone" />
-
- <ImageView
- android:id="@+id/qr_code_scanner_button"
- android:layout_height="@dimen/keyguard_affordance_fixed_height"
- android:layout_width="@dimen/keyguard_affordance_fixed_width"
- android:layout_gravity="bottom|end"
- android:scaleType="center"
- android:tint="?android:attr/textColorPrimary"
- android:src="@drawable/ic_qr_code_scanner"
- android:background="@drawable/keyguard_bottom_affordance_bg"
- android:layout_marginEnd="@dimen/keyguard_affordance_horizontal_offset"
- android:layout_marginBottom="@dimen/keyguard_affordance_vertical_offset"
- android:contentDescription="@string/accessibility_qr_code_scanner_button"
- android:visibility="gone" />
-
- <ImageView
- android:id="@+id/controls_button"
- android:layout_height="@dimen/keyguard_affordance_fixed_height"
- android:layout_width="@dimen/keyguard_affordance_fixed_width"
- android:layout_gravity="bottom|start"
- android:scaleType="center"
- android:tint="?android:attr/textColorPrimary"
- android:src="@drawable/controls_icon"
- android:background="@drawable/keyguard_bottom_affordance_bg"
- android:layout_marginStart="@dimen/keyguard_affordance_horizontal_offset"
- android:layout_marginBottom="@dimen/keyguard_affordance_vertical_offset"
- android:contentDescription="@string/quick_controls_title"
- android:visibility="gone" />
-
<FrameLayout
android:id="@+id/overlay_container"
android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout/media_output_dialog.xml b/packages/SystemUI/res/layout/media_output_dialog.xml
index 93c16e4..b76de5a 100644
--- a/packages/SystemUI/res/layout/media_output_dialog.xml
+++ b/packages/SystemUI/res/layout/media_output_dialog.xml
@@ -20,6 +20,7 @@
android:id="@+id/media_output_dialog"
android:layout_width="@dimen/large_dialog_width"
android:layout_height="wrap_content"
+ android:background="@drawable/media_output_dialog_background"
android:orientation="vertical">
<LinearLayout
diff --git a/packages/SystemUI/res/layout/media_projection_app_selector.xml b/packages/SystemUI/res/layout/media_projection_app_selector.xml
new file mode 100644
index 0000000..4ad6849
--- /dev/null
+++ b/packages/SystemUI/res/layout/media_projection_app_selector.xml
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+<com.android.internal.widget.ResolverDrawerLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="center"
+ androidprv:maxCollapsedHeight="0dp"
+ androidprv:maxCollapsedHeightSmall="56dp"
+ androidprv:maxWidth="@*android:dimen/chooser_width"
+ android:id="@*android:id/contentPanel">
+
+ <LinearLayout
+ android:id="@*android:id/chooser_header"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ androidprv:layout_alwaysShow="true"
+ android:gravity="center"
+ android:elevation="0dp"
+ android:background="@*android:drawable/bottomsheet_background">
+
+ <ImageView
+ android:id="@*android:id/icon"
+ android:layout_width="@dimen/media_projection_app_selector_icon_size"
+ android:layout_height="@dimen/media_projection_app_selector_icon_size"
+ android:layout_marginTop="@*android:dimen/chooser_edge_margin_normal"
+ android:layout_marginBottom="@*android:dimen/chooser_edge_margin_normal"
+ android:importantForAccessibility="no"
+ android:tint="?android:attr/textColorPrimary"/>
+
+ <TextView android:id="@*android:id/title"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:gravity="center"
+ android:paddingBottom="@*android:dimen/chooser_view_spacing"
+ android:paddingLeft="24dp"
+ android:paddingRight="24dp"/>
+ </LinearLayout>
+
+ <FrameLayout
+ android:id="@*android:id/content_preview_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:visibility="gone" />
+
+ <TabHost
+ android:id="@*android:id/profile_tabhost"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentTop="true"
+ android:layout_centerHorizontal="true"
+ android:background="?android:attr/colorBackground">
+ <LinearLayout
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+ <TabWidget
+ android:id="@*android:id/tabs"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:visibility="gone">
+ </TabWidget>
+ <FrameLayout
+ android:id="@*android:id/tabcontent"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+ <com.android.internal.app.ResolverViewPager
+ android:id="@*android:id/profile_pager"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"/>
+ </FrameLayout>
+ </LinearLayout>
+ </TabHost>
+
+</com.android.internal.widget.ResolverDrawerLayout>
diff --git a/packages/SystemUI/res/layout/super_notification_shade.xml b/packages/SystemUI/res/layout/super_notification_shade.xml
index 86f8ce2..0c57b934 100644
--- a/packages/SystemUI/res/layout/super_notification_shade.xml
+++ b/packages/SystemUI/res/layout/super_notification_shade.xml
@@ -88,7 +88,7 @@
android:layout_marginTop="@dimen/status_bar_height"
android:layout_gravity="top|center_horizontal"
android:gravity="center_horizontal">
- <com.android.keyguard.KeyguardMessageArea
+ <com.android.keyguard.AuthKeyguardMessageArea
android:id="@+id/keyguard_message_area"
style="@style/Keyguard.TextView"
android:layout_width="wrap_content"
diff --git a/packages/SystemUI/res/raw/biometricprompt_fingerprint_to_error_landscape.json b/packages/SystemUI/res/raw/biometricprompt_fingerprint_to_error_landscape.json
new file mode 100644
index 0000000..3d33b2a
--- /dev/null
+++ b/packages/SystemUI/res/raw/biometricprompt_fingerprint_to_error_landscape.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":21,"w":340,"h":340,"nm":"BiometricPrompt_Symbol_Fingerprint_To_Error_Landscape","ddd":0,"assets":[{"id":"comp_0","nm":"Fingerprint_Animation_ForConfirm_Short","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"circle fill 5","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":249,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":388,"s":[100]},{"t":408,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":239,"op":1411,"st":239,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-52.056,-2.445],[-17.306,32.25],[52.194,-37.194]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"t":249,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":239,"op":1139,"st":239,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".green400","cl":"green400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":249,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":388,"s":[100]},{"t":408,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.450980392157,0.709803921569,0.470588235294,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":239,"op":1411,"st":239,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"circle fill 3","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":80,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":90,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.8,"y":0},"t":108,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"t":118,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,35.389],[-0.111,50.111]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0.049,42.698],"ix":2},"a":{"a":0,"k":[0.049,42.698],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":80,"op":980,"st":80,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".red400","cl":"red400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":7,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0.333},"t":85,"s":[209.333,136.333,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":440,"s":[209.333,136.333,0],"to":[1.944,2.278,0],"ti":[3.056,-2.278,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":450,"s":[221,150,0],"to":[-3.056,2.278,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":460,"s":[191,150,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":470,"s":[221,150,0],"to":[0,0,0],"ti":[2.5,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":480,"s":[191,150,0],"to":[-2.5,0,0],"ti":[-2.5,0,0]},{"t":490,"s":[206,150,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[132,132,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"Fingerprint_Animation_ForConfirm_Short","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[170,77.667,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[30,30,100],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":0,"op":830,"st":-70,"bm":0}],"markers":[{"tm":255,"cm":"","dr":0},{"tm":364,"cm":"","dr":0},{"tm":482,"cm":"","dr":0},{"tm":600,"cm":"","dr":0}]}
\ No newline at end of file
diff --git a/packages/SystemUI/res/raw/biometricprompt_landscape_base.json b/packages/SystemUI/res/raw/biometricprompt_landscape_base.json
new file mode 100644
index 0000000..3781eee
--- /dev/null
+++ b/packages/SystemUI/res/raw/biometricprompt_landscape_base.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":21,"w":340,"h":340,"nm":"biometricprompt_landscape_base","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 16","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[170,170,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":3,"nm":"Null_Circle","parent":1,"sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-108,"s":[70.333,-88.75,0],"to":[-11.722,17.639,0],"ti":[11.722,-17.639,0]},{"t":-48,"s":[0,17.083,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".grey600","cl":"grey600","parent":2,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.501960784314,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"circle mask 3","parent":2,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Finger","parent":2,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":-60,"s":[55]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":110,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":140,"s":[10]},{"t":170,"s":[0]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-60,"s":[92.146,-65.896,0],"to":[1.361,6.667,0],"ti":[-1.361,-6.667,0]},{"i":{"x":0.2,"y":0.2},"o":{"x":0.167,"y":0.167},"t":0,"s":[100.313,-25.896,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.2,"y":0.2},"o":{"x":0.7,"y":0.7},"t":110,"s":[100.313,-25.896,0],"to":[0,0,0],"ti":[0,0,0]},{"t":170,"s":[100.313,-25.896,0]}],"ix":2,"l":2},"a":{"a":0,"k":[160.315,58.684,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-11.013,2.518],[5.251,5.023],[8.982,-2.829],[-0.264,-5.587]],"o":[[12.768,-2.854],[-14.961,2.071],[-6.004,1.89],[8.052,1.403]],"v":[[5.115,7.499],[19.814,-10.087],[-16.489,-3.588],[-24.801,8.684]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.760784373564,0.478431402468,0.400000029919,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[34.67,28.053],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[22.231,-7],[-27.395,-1.197],[-26.792,4.092],[14.179,15.736]],"o":[[-17.931,5.646],[56.062,2.45],[-1.765,-22.396],[-51.819,17.744]],"v":[[-62.102,-8.314],[-39.958,30.079],[80.033,25.905],[54.879,-32.529]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.678431372549,0.403921598547,0.305882352941,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[80.283,32.779],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":4,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"circle mask 7","parent":2,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".grey600","cl":"grey600","parent":2,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-0.25,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[114.218,-17.096],[-112.938,-17.096]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.501960784314,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":10,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":36.9,"ix":2},"o":{"a":0,"k":114.2,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"circle mask","parent":2,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":".grey800","cl":"grey800","parent":2,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-0.5,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[114.218,-17.096],[-112.938,-17.096]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":10,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":"circle mask 6","parent":2,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":".grey900","cl":"grey900","parent":2,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":377,"s":[-180]},{"t":417,"s":[0]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":377,"s":[-1.137,1.771,0],"to":[0.375,0,0],"ti":[-0.375,0,0]},{"t":417,"s":[1.113,1.771,0]}],"ix":2,"l":2},"a":{"a":0,"k":[6.238,5.063,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":77,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,-4.637],[-10.23,-3.195],[-2.196,4.813],[5.988,-3.371],[4.545,-4.813],[-2.196,1.918]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":107,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,0.393],[-10.23,1.835],[-2.196,9.843],[5.988,1.659],[4.545,0.217],[-2.196,6.948]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":137,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,-4.637],[-10.23,-3.195],[-2.196,4.813],[5.988,-3.371],[4.545,-4.813],[-2.196,1.918]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":167,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,0.393],[-10.23,1.835],[-2.196,9.843],[5.988,1.659],[4.545,0.217],[-2.196,6.948]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":197,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,-4.637],[-10.23,-3.195],[-2.196,4.813],[5.988,-3.371],[4.545,-4.813],[-2.196,1.918]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.7,"y":0},"t":232,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,0.393],[-10.23,1.835],[-2.196,9.843],[5.988,1.659],[4.545,0.217],[-2.196,6.948]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":562,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,0.393],[-10.23,1.835],[-2.196,9.843],[5.988,1.659],[4.545,0.217],[-2.196,6.948]],"c":false}]},{"t":602,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-4.546,-0.421],[-5.988,1.021],[-2.196,4.813],[5.988,-3.371],[4.545,-4.813],[-2.196,1.918]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.125490196078,0.129411764706,0.141176470588,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[6.238,5.063],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":"circle mask 2","parent":2,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":".blue400","cl":"blue400","parent":2,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,8.308,0],"ix":2,"l":2},"a":{"a":0,"k":[41.706,20.979,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[18.645,0],[0,18.645]],"o":[[0,18.645],[-18.644,0],[0,0]],"v":[[33.76,-16.88],[-0.001,16.88],[-33.76,-16.88]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.400000029919,0.61568627451,0.964705942191,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[41.706,17.13],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[22.896,0],[0,22.896]],"o":[[0,22.896],[-22.896,0],[0,0]],"v":[[41.457,-20.729],[-0.001,20.729],[-41.457,-20.729]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.400000029919,0.61568627451,0.964705942191,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[41.706,20.979],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":4,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":"circle mask 4","parent":2,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":15,"ty":1,"nm":".grey900","cl":"grey900","parent":2,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,66,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[52,52,100],"ix":6,"l":2}},"ao":0,"sw":412,"sh":300,"sc":"#202124","ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":16,"ty":4,"nm":"circle mask 5","parent":2,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":17,"ty":1,"nm":".black","cl":"black","parent":2,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,-17.333,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[72,72,100],"ix":6,"l":2}},"ao":0,"sw":412,"sh":300,"sc":"#000000","ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":18,"ty":4,"nm":".grey800","cl":"grey800","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-108,"s":[-192.25,99.933,0],"to":[5,3.333,0],"ti":[-5,-3.333,0]},{"t":-48,"s":[-162.25,119.933,0]}],"ix":2,"l":2},"a":{"a":0,"k":[-163,100.85,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2,0.833],"y":[1,1,1]},"o":{"x":[0.7,0.7,0.167],"y":[0,0,0]},"t":-108,"s":[100,100,100]},{"t":-48,"s":[59,59,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":19,"ty":4,"nm":".grey900","cl":"grey900","parent":23,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-239,"s":[0,18.167,0],"to":[0,-1.25,0],"ti":[0,1.25,0]},{"t":-199,"s":[0,10.667,0]}],"ix":2,"l":2},"a":{"a":0,"k":[5.5,4,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.7,"y":0},"t":-239,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-0.07,1.5],[0,-1.5],[-0.047,1.5]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":-199,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,1.5],[0,-1.5],[3,1.5]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":-171,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,1.5],[0,-1.5],[3,1.5]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":-141,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,3.512],[0,0.512],[3,3.512]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":-111,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,1.5],[0,-1.5],[3,1.5]],"c":false}]},{"t":-81,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,3.967],[0,0.967],[3,3.967]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.125490196078,0.129411764706,0.141176470588,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[5.5,4],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-199,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":20,"ty":4,"nm":"Shape Layer 4","parent":1,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-239,"s":[71,-116.083,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.7,"y":0},"t":-199,"s":[71,-101.083,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":365,"s":[71,-101.083,0],"to":[0,0,0],"ti":[16.833,-14.361,0]},{"t":405,"s":[-30,-14.917,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-239,"s":[29,29]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-199,"s":[29,38]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":365,"s":[29,36]},{"t":405,"s":[83,83]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":365,"s":[50]},{"t":405,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.400000029919,0.61568627451,0.964705942191,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":21,"ty":4,"nm":".grey900","cl":"grey900","parent":1,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-239,"s":[71,-82.917,0],"to":[0,-1.25,0],"ti":[0,1.25,0]},{"t":-199,"s":[71,-90.417,0]}],"ix":2,"l":2},"a":{"a":0,"k":[5.5,4,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-239,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-0.07,1.5],[0,-1.5],[-0.047,1.5]],"c":false}]},{"t":-199,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,1.5],[0,-1.5],[3,1.5]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.125490196078,0.129411764706,0.141176470588,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[5.5,4],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":-199,"st":-255,"bm":0},{"ddd":0,"ind":22,"ty":4,"nm":"device frame mask","parent":24,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,1.167,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":23,"ty":4,"nm":".blue400","cl":"blue400","parent":18,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-239,"s":[100.25,-115.167,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-199,"s":[100.25,-100.167,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.7,"y":0},"t":-159,"s":[100.25,-105.667,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":365,"s":[100.25,-100.167,0],"to":[0,0,0],"ti":[16.833,-14.361,0]},{"t":405,"s":[-0.75,-14,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-239,"s":[29,29]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-199,"s":[29,38]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":365,"s":[29,36]},{"t":405,"s":[83,83]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":365,"s":[50]},{"t":405,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.400000029919,0.61568627451,0.964705942191,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":24,"ty":3,"nm":"device frame mask 5","parent":18,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":-165,"op":6.00000000000001,"st":-271,"bm":0},{"ddd":0,"ind":28,"ty":4,"nm":"device frame mask 9","parent":1,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-29.25,-0.917,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-181,"op":-62,"st":-181,"bm":0},{"ddd":0,"ind":29,"ty":4,"nm":".blue400","cl":"blue400","parent":23,"tt":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":-145,"s":[50]},{"t":-75,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-165,"s":[0,0]},{"t":-75,"s":[94,94]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":73,"s":[50]},{"t":113,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-181,"op":-62,"st":-181,"bm":0},{"ddd":0,"ind":30,"ty":4,"nm":"device frame mask 8","parent":1,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-29.25,-0.917,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-211,"op":-92,"st":-211,"bm":0},{"ddd":0,"ind":31,"ty":4,"nm":".blue400","cl":"blue400","parent":23,"tt":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":-165,"s":[50]},{"t":-95,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-195,"s":[0,0]},{"t":-105,"s":[94,94]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":43,"s":[50]},{"t":83,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-211,"op":-92,"st":-211,"bm":0},{"ddd":0,"ind":32,"ty":4,"nm":"device frame mask 7","parent":1,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-29.25,-0.917,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-241,"op":-122,"st":-241,"bm":0},{"ddd":0,"ind":33,"ty":4,"nm":".blue400","cl":"blue400","parent":23,"tt":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":-195,"s":[50]},{"t":-125,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-225,"s":[0,0]},{"t":-135,"s":[94,94]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":13,"s":[50]},{"t":53,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-241,"op":-122,"st":-241,"bm":0},{"ddd":0,"ind":34,"ty":4,"nm":"device frame mask 6","parent":1,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-29.25,-0.917,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-271,"op":-152,"st":-271,"bm":0},{"ddd":0,"ind":35,"ty":4,"nm":".blue400","cl":"blue400","parent":23,"tt":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":-225,"s":[50]},{"t":-155,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-255,"s":[0,0]},{"t":-165,"s":[94,94]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":-17,"s":[50]},{"t":23,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-271,"op":-152,"st":-271,"bm":0}],"markers":[{"tm":255,"cm":"","dr":0},{"tm":364,"cm":"","dr":0},{"tm":482,"cm":"","dr":0},{"tm":600,"cm":"","dr":0}]}
\ No newline at end of file
diff --git a/packages/SystemUI/res/raw/biometricprompt_portrait_base_bottomright.json b/packages/SystemUI/res/raw/biometricprompt_portrait_base_bottomright.json
new file mode 100644
index 0000000..4950666
--- /dev/null
+++ b/packages/SystemUI/res/raw/biometricprompt_portrait_base_bottomright.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":21,"w":340,"h":340,"nm":"biometricprompt_portrait_base_bottomright","ddd":0,"assets":[{"id":"comp_0","nm":"biometricprompt_landscape_base","fr":60,"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 16","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[170,170,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":3,"nm":"Null_Circle","parent":1,"sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-108,"s":[70.333,-88.75,0],"to":[-11.722,17.639,0],"ti":[11.722,-17.639,0]},{"t":-48,"s":[0,17.083,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".grey600","cl":"grey600","parent":2,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.501960784314,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"circle mask 3","parent":2,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Finger","parent":2,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":-60,"s":[55]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":110,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":140,"s":[10]},{"t":170,"s":[0]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-60,"s":[92.146,-65.896,0],"to":[1.361,6.667,0],"ti":[-1.361,-6.667,0]},{"i":{"x":0.2,"y":0.2},"o":{"x":0.167,"y":0.167},"t":0,"s":[100.313,-25.896,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.2,"y":0.2},"o":{"x":0.7,"y":0.7},"t":110,"s":[100.313,-25.896,0],"to":[0,0,0],"ti":[0,0,0]},{"t":170,"s":[100.313,-25.896,0]}],"ix":2,"l":2},"a":{"a":0,"k":[160.315,58.684,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-11.013,2.518],[5.251,5.023],[8.982,-2.829],[-0.264,-5.587]],"o":[[12.768,-2.854],[-14.961,2.071],[-6.004,1.89],[8.052,1.403]],"v":[[5.115,7.499],[19.814,-10.087],[-16.489,-3.588],[-24.801,8.684]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.760784373564,0.478431402468,0.400000029919,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[34.67,28.053],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[22.231,-7],[-27.395,-1.197],[-26.792,4.092],[14.179,15.736]],"o":[[-17.931,5.646],[56.062,2.45],[-1.765,-22.396],[-51.819,17.744]],"v":[[-62.102,-8.314],[-39.958,30.079],[80.033,25.905],[54.879,-32.529]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.678431372549,0.403921598547,0.305882352941,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[80.283,32.779],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":4,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"circle mask 7","parent":2,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".grey600","cl":"grey600","parent":2,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-0.25,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[114.218,-17.096],[-112.938,-17.096]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.501960784314,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":10,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":36.9,"ix":2},"o":{"a":0,"k":114.2,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"circle mask","parent":2,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":".grey800","cl":"grey800","parent":2,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-0.5,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[114.218,-17.096],[-112.938,-17.096]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":10,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":"circle mask 6","parent":2,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":".grey900","cl":"grey900","parent":2,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":377,"s":[-180]},{"t":417,"s":[0]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":377,"s":[-1.137,1.771,0],"to":[0.375,0,0],"ti":[-0.375,0,0]},{"t":417,"s":[1.113,1.771,0]}],"ix":2,"l":2},"a":{"a":0,"k":[6.238,5.063,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":77,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,-4.637],[-10.23,-3.195],[-2.196,4.813],[5.988,-3.371],[4.545,-4.813],[-2.196,1.918]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":107,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,0.393],[-10.23,1.835],[-2.196,9.843],[5.988,1.659],[4.545,0.217],[-2.196,6.948]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":137,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,-4.637],[-10.23,-3.195],[-2.196,4.813],[5.988,-3.371],[4.545,-4.813],[-2.196,1.918]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":167,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,0.393],[-10.23,1.835],[-2.196,9.843],[5.988,1.659],[4.545,0.217],[-2.196,6.948]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":197,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,-4.637],[-10.23,-3.195],[-2.196,4.813],[5.988,-3.371],[4.545,-4.813],[-2.196,1.918]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.7,"y":0},"t":232,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,0.393],[-10.23,1.835],[-2.196,9.843],[5.988,1.659],[4.545,0.217],[-2.196,6.948]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":562,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,0.393],[-10.23,1.835],[-2.196,9.843],[5.988,1.659],[4.545,0.217],[-2.196,6.948]],"c":false}]},{"t":602,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-4.546,-0.421],[-5.988,1.021],[-2.196,4.813],[5.988,-3.371],[4.545,-4.813],[-2.196,1.918]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.125490196078,0.129411764706,0.141176470588,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[6.238,5.063],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":"circle mask 2","parent":2,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":".blue400","cl":"blue400","parent":2,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,8.308,0],"ix":2,"l":2},"a":{"a":0,"k":[41.706,20.979,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[18.645,0],[0,18.645]],"o":[[0,18.645],[-18.644,0],[0,0]],"v":[[33.76,-16.88],[-0.001,16.88],[-33.76,-16.88]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.400000029919,0.61568627451,0.964705942191,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[41.706,17.13],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[22.896,0],[0,22.896]],"o":[[0,22.896],[-22.896,0],[0,0]],"v":[[41.457,-20.729],[-0.001,20.729],[-41.457,-20.729]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.400000029919,0.61568627451,0.964705942191,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[41.706,20.979],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":4,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":"circle mask 4","parent":2,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":15,"ty":1,"nm":".grey900","cl":"grey900","parent":2,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,66,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[52,52,100],"ix":6,"l":2}},"ao":0,"sw":412,"sh":300,"sc":"#202124","ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":16,"ty":4,"nm":"circle mask 5","parent":2,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":17,"ty":1,"nm":".black","cl":"black","parent":2,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,-17.333,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[72,72,100],"ix":6,"l":2}},"ao":0,"sw":412,"sh":300,"sc":"#000000","ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":18,"ty":4,"nm":".grey800","cl":"grey800","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-108,"s":[-192.25,99.933,0],"to":[5,3.333,0],"ti":[-5,-3.333,0]},{"t":-48,"s":[-162.25,119.933,0]}],"ix":2,"l":2},"a":{"a":0,"k":[-163,100.85,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2,0.833],"y":[1,1,1]},"o":{"x":[0.7,0.7,0.167],"y":[0,0,0]},"t":-108,"s":[100,100,100]},{"t":-48,"s":[59,59,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":19,"ty":4,"nm":".grey900","cl":"grey900","parent":23,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-239,"s":[0,18.167,0],"to":[0,-1.25,0],"ti":[0,1.25,0]},{"t":-199,"s":[0,10.667,0]}],"ix":2,"l":2},"a":{"a":0,"k":[5.5,4,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.7,"y":0},"t":-239,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-0.07,1.5],[0,-1.5],[-0.047,1.5]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":-199,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,1.5],[0,-1.5],[3,1.5]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":-171,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,1.5],[0,-1.5],[3,1.5]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":-141,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,3.512],[0,0.512],[3,3.512]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":-111,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,1.5],[0,-1.5],[3,1.5]],"c":false}]},{"t":-81,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,3.967],[0,0.967],[3,3.967]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.125490196078,0.129411764706,0.141176470588,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[5.5,4],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-199,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":20,"ty":4,"nm":"Shape Layer 4","parent":1,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-239,"s":[71,-116.083,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.7,"y":0},"t":-199,"s":[71,-101.083,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":365,"s":[71,-101.083,0],"to":[0,0,0],"ti":[16.833,-14.361,0]},{"t":405,"s":[-30,-14.917,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-239,"s":[29,29]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-199,"s":[29,38]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":365,"s":[29,36]},{"t":405,"s":[83,83]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":365,"s":[50]},{"t":405,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.400000029919,0.61568627451,0.964705942191,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":21,"ty":4,"nm":".grey900","cl":"grey900","parent":1,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-239,"s":[71,-82.917,0],"to":[0,-1.25,0],"ti":[0,1.25,0]},{"t":-199,"s":[71,-90.417,0]}],"ix":2,"l":2},"a":{"a":0,"k":[5.5,4,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-239,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-0.07,1.5],[0,-1.5],[-0.047,1.5]],"c":false}]},{"t":-199,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,1.5],[0,-1.5],[3,1.5]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.125490196078,0.129411764706,0.141176470588,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[5.5,4],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":-199,"st":-255,"bm":0},{"ddd":0,"ind":22,"ty":4,"nm":"device frame mask","parent":24,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,1.167,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":23,"ty":4,"nm":".blue400","cl":"blue400","parent":18,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-239,"s":[100.25,-115.167,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-199,"s":[100.25,-100.167,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.7,"y":0},"t":-159,"s":[100.25,-105.667,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":365,"s":[100.25,-100.167,0],"to":[0,0,0],"ti":[16.833,-14.361,0]},{"t":405,"s":[-0.75,-14,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-239,"s":[29,29]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-199,"s":[29,38]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":365,"s":[29,36]},{"t":405,"s":[83,83]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":365,"s":[50]},{"t":405,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.400000029919,0.61568627451,0.964705942191,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":24,"ty":3,"nm":"device frame mask 5","parent":18,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":-165,"op":6.00000000000001,"st":-271,"bm":0},{"ddd":0,"ind":28,"ty":4,"nm":"device frame mask 9","parent":1,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-29.25,-0.917,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-181,"op":-62,"st":-181,"bm":0},{"ddd":0,"ind":29,"ty":4,"nm":".blue400","cl":"blue400","parent":23,"tt":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":-145,"s":[50]},{"t":-75,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-165,"s":[0,0]},{"t":-75,"s":[94,94]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":73,"s":[50]},{"t":113,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-181,"op":-62,"st":-181,"bm":0},{"ddd":0,"ind":30,"ty":4,"nm":"device frame mask 8","parent":1,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-29.25,-0.917,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-211,"op":-92,"st":-211,"bm":0},{"ddd":0,"ind":31,"ty":4,"nm":".blue400","cl":"blue400","parent":23,"tt":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":-165,"s":[50]},{"t":-95,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-195,"s":[0,0]},{"t":-105,"s":[94,94]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":43,"s":[50]},{"t":83,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-211,"op":-92,"st":-211,"bm":0},{"ddd":0,"ind":32,"ty":4,"nm":"device frame mask 7","parent":1,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-29.25,-0.917,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-241,"op":-122,"st":-241,"bm":0},{"ddd":0,"ind":33,"ty":4,"nm":".blue400","cl":"blue400","parent":23,"tt":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":-195,"s":[50]},{"t":-125,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-225,"s":[0,0]},{"t":-135,"s":[94,94]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":13,"s":[50]},{"t":53,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-241,"op":-122,"st":-241,"bm":0},{"ddd":0,"ind":34,"ty":4,"nm":"device frame mask 6","parent":1,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-29.25,-0.917,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-271,"op":-152,"st":-271,"bm":0},{"ddd":0,"ind":35,"ty":4,"nm":".blue400","cl":"blue400","parent":23,"tt":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":-225,"s":[50]},{"t":-155,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-255,"s":[0,0]},{"t":-165,"s":[94,94]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":-17,"s":[50]},{"t":23,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-271,"op":-152,"st":-271,"bm":0}]}],"layers":[{"ddd":0,"ind":6,"ty":0,"nm":"biometricprompt_landscape_base","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":90,"ix":10},"p":{"a":0,"k":[170,170,0],"ix":2,"l":2},"a":{"a":0,"k":[170,170,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":340,"h":340,"ip":0,"op":900,"st":0,"bm":0}],"markers":[{"tm":255,"cm":"","dr":0},{"tm":364,"cm":"","dr":0},{"tm":482,"cm":"","dr":0},{"tm":600,"cm":"","dr":0}]}
\ No newline at end of file
diff --git a/packages/SystemUI/res/raw/biometricprompt_portrait_base_topleft.json b/packages/SystemUI/res/raw/biometricprompt_portrait_base_topleft.json
new file mode 100644
index 0000000..b161609
--- /dev/null
+++ b/packages/SystemUI/res/raw/biometricprompt_portrait_base_topleft.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":21,"w":340,"h":340,"nm":"biometricprompt_portrait_base_topleft","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":6,"ty":3,"nm":"Null 16","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":-90,"ix":10},"p":{"a":0,"k":[170,170,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":3,"nm":"Null_Circle","parent":6,"sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-108,"s":[70.333,-88.75,0],"to":[-11.722,17.639,0],"ti":[11.722,-17.639,0]},{"t":-48,"s":[0,17.083,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":".grey905","cl":"grey905","parent":7,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.501960784314,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"circle mask 3","parent":7,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":"Finger_Flipped","parent":6,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":90,"ix":10},"p":{"a":0,"k":[-24.98,-35.709,0],"ix":2,"l":2},"a":{"a":0,"k":[31.791,75.23,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[5.03,5.25],[-2.83,8.98],[-5.59,-0.26],[2.52,-11.02]],"o":[[-2.85,12.77],[2.07,-14.96],[1.9,-6],[1.4,8.05],[0,0]],"v":[[7.5,4.99],[-10.09,19.69],[-3.59,-16.61],[8.69,-24.92],[7.5,5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.760784373564,0.478431402468,0.400000029919,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[27.8,24.94],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-7.01,22.23],[-1.2,-27.39],[4.09,-26.79],[15.73,14.18]],"o":[[5.64,-17.93],[2.45,56.06],[-22.4,-1.77],[17.73,-51.82]],"v":[[-7.57,-66.9],[30.82,-44.76],[26.65,75.23],[-31.78,50.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.678431372549,0.403921598547,0.305882352941,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[31.79,75.23],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":4,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":"circle mask 7","parent":7,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":".grey600","cl":"grey600","parent":7,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-0.25,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[114.218,-17.096],[-112.938,-17.096]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.501960784314,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":10,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":36.9,"ix":2},"o":{"a":0,"k":114.2,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":"circle mask","parent":7,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":".grey904","cl":"grey904","parent":7,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-0.5,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[114.218,-17.096],[-112.938,-17.096]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":10,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":15,"ty":4,"nm":"circle mask 6","parent":7,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":16,"ty":4,"nm":".grey903","cl":"grey903","parent":7,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":377,"s":[-180]},{"t":417,"s":[0]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":377,"s":[-1.137,1.771,0],"to":[0.375,0,0],"ti":[-0.375,0,0]},{"t":417,"s":[1.113,1.771,0]}],"ix":2,"l":2},"a":{"a":0,"k":[6.238,5.063,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":77,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,-4.637],[-10.23,-3.195],[-2.196,4.813],[5.988,-3.371],[4.545,-4.813],[-2.196,1.918]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":107,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,0.393],[-10.23,1.835],[-2.196,9.843],[5.988,1.659],[4.545,0.217],[-2.196,6.948]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":137,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,-4.637],[-10.23,-3.195],[-2.196,4.813],[5.988,-3.371],[4.545,-4.813],[-2.196,1.918]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":167,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,0.393],[-10.23,1.835],[-2.196,9.843],[5.988,1.659],[4.545,0.217],[-2.196,6.948]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":197,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,-4.637],[-10.23,-3.195],[-2.196,4.813],[5.988,-3.371],[4.545,-4.813],[-2.196,1.918]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.7,"y":0},"t":232,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,0.393],[-10.23,1.835],[-2.196,9.843],[5.988,1.659],[4.545,0.217],[-2.196,6.948]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":562,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,0.393],[-10.23,1.835],[-2.196,9.843],[5.988,1.659],[4.545,0.217],[-2.196,6.948]],"c":false}]},{"t":602,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-4.546,-0.421],[-5.988,1.021],[-2.196,4.813],[5.988,-3.371],[4.545,-4.813],[-2.196,1.918]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.125490196078,0.129411764706,0.141176470588,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[6.238,5.063],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":17,"ty":4,"nm":"circle mask 2","parent":7,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":18,"ty":4,"nm":".blue400","cl":"blue400","parent":7,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,8.308,0],"ix":2,"l":2},"a":{"a":0,"k":[41.706,20.979,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[18.645,0],[0,18.645]],"o":[[0,18.645],[-18.644,0],[0,0]],"v":[[33.76,-16.88],[-0.001,16.88],[-33.76,-16.88]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.400000029919,0.61568627451,0.964705942191,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[41.706,17.13],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[22.896,0],[0,22.896]],"o":[[0,22.896],[-22.896,0],[0,0]],"v":[[41.457,-20.729],[-0.001,20.729],[-41.457,-20.729]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.400000029919,0.61568627451,0.964705942191,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[41.706,20.979],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":4,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":19,"ty":4,"nm":"circle mask 4","parent":7,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":20,"ty":1,"nm":".grey902","cl":"grey902","parent":7,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,66,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[52,52,100],"ix":6,"l":2}},"ao":0,"sw":412,"sh":300,"sc":"#202124","ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":21,"ty":4,"nm":"circle mask 5","parent":7,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":22,"ty":1,"nm":".black","cl":"black","parent":7,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,-17.333,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[72,72,100],"ix":6,"l":2}},"ao":0,"sw":412,"sh":300,"sc":"#000000","ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":23,"ty":4,"nm":".grey800","cl":"grey800","parent":6,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-108,"s":[-192.25,99.933,0],"to":[5,3.333,0],"ti":[-5,-3.333,0]},{"t":-48,"s":[-162.25,119.933,0]}],"ix":2,"l":2},"a":{"a":0,"k":[-163,100.85,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2,0.833],"y":[1,1,1]},"o":{"x":[0.7,0.7,0.167],"y":[0,0,0]},"t":-108,"s":[100,100,100]},{"t":-48,"s":[59,59,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":24,"ty":4,"nm":".grey901","cl":"grey901","parent":23,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-239,"s":[100.25,-87.156,0],"to":[0,-1.25,0],"ti":[0,1.25,0]},{"t":-199,"s":[100.25,-94.656,0]}],"ix":2,"l":2},"a":{"a":0,"k":[5.5,4,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.7,"y":0},"t":-239,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-0.07,1.5],[0,-1.5],[-0.047,1.5]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":-199,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,1.5],[0,-1.5],[3,1.5]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":-171,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,1.5],[0,-1.5],[3,1.5]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":-141,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,3.512],[0,0.512],[3,3.512]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":-111,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,1.5],[0,-1.5],[3,1.5]],"c":false}]},{"t":-81,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,3.967],[0,0.967],[3,3.967]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.125490196078,0.129411764706,0.141176470588,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[5.5,4],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-199,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":25,"ty":4,"nm":"Shape Layer 4","parent":6,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-239,"s":[71,-116.083,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.7,"y":0},"t":-199,"s":[71,-101.083,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":365,"s":[71,-101.083,0],"to":[0,0,0],"ti":[16.833,-14.361,0]},{"t":405,"s":[-30,-14.917,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-239,"s":[29,29]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-199,"s":[29,38]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":365,"s":[29,36]},{"t":405,"s":[83,83]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":365,"s":[50]},{"t":405,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.400000029919,0.61568627451,0.964705942191,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":26,"ty":4,"nm":".grey900","cl":"grey900","parent":6,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-239,"s":[71,-82.917,0],"to":[0,-1.25,0],"ti":[0,1.25,0]},{"t":-199,"s":[71,-90.417,0]}],"ix":2,"l":2},"a":{"a":0,"k":[5.5,4,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-239,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-0.07,1.5],[0,-1.5],[-0.047,1.5]],"c":false}]},{"t":-199,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,1.5],[0,-1.5],[3,1.5]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.125490196078,0.129411764706,0.141176470588,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[5.5,4],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":-199,"st":-255,"bm":0}],"markers":[{"tm":255,"cm":"","dr":0},{"tm":364,"cm":"","dr":0},{"tm":482,"cm":"","dr":0},{"tm":600,"cm":"","dr":0}]}
\ No newline at end of file
diff --git a/packages/SystemUI/res/raw/biometricprompt_symbol_error_to_fingerprint_landscape.json b/packages/SystemUI/res/raw/biometricprompt_symbol_error_to_fingerprint_landscape.json
new file mode 100644
index 0000000..034ac87
--- /dev/null
+++ b/packages/SystemUI/res/raw/biometricprompt_symbol_error_to_fingerprint_landscape.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":21,"w":340,"h":340,"nm":"biometricprompt_symbol_error_to_fingerprint_landscape","ddd":0,"assets":[{"id":"comp_0","nm":"Fingerprint_Animation_ForConfirm_Short_For_ErrorToFingerprint","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"circle fill 5","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":249,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":388,"s":[100]},{"t":408,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":239,"op":1411,"st":239,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-52.056,-2.445],[-17.306,32.25],[52.194,-37.194]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"t":249,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":239,"op":1139,"st":239,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".green400","cl":"green400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":249,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":388,"s":[100]},{"t":408,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.450980392157,0.709803921569,0.470588235294,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":239,"op":1411,"st":239,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"circle fill 3","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":80,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":90,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.8,"y":0},"t":108,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"t":118,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,35.389],[-0.111,50.111]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0.049,42.698],"ix":2},"a":{"a":0,"k":[0.049,42.698],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":80,"op":980,"st":80,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".red400","cl":"red400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":7,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0.333},"t":85,"s":[209.333,136.333,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":440,"s":[209.333,136.333,0],"to":[1.944,2.278,0],"ti":[3.056,-2.278,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":450,"s":[221,150,0],"to":[-3.056,2.278,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":460,"s":[191,150,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":470,"s":[221,150,0],"to":[0,0,0],"ti":[2.5,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":480,"s":[191,150,0],"to":[-2.5,0,0],"ti":[-2.5,0,0]},{"t":490,"s":[206,150,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[132,132,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"Fingerprint_Animation_ForConfirm_Short_For_ErrorToFingerprint","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[170,77.667,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[30,30,100],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":0,"op":792,"st":-108,"bm":0}],"markers":[{"tm":255,"cm":"","dr":0},{"tm":364,"cm":"","dr":0},{"tm":482,"cm":"","dr":0},{"tm":600,"cm":"","dr":0}]}
\ No newline at end of file
diff --git a/packages/SystemUI/res/raw/biometricprompt_symbol_error_to_fingerprint_portrait_bottomright.json b/packages/SystemUI/res/raw/biometricprompt_symbol_error_to_fingerprint_portrait_bottomright.json
new file mode 100644
index 0000000..e5cc565e
--- /dev/null
+++ b/packages/SystemUI/res/raw/biometricprompt_symbol_error_to_fingerprint_portrait_bottomright.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":21,"w":340,"h":340,"nm":"biometricprompt_symbol_error_to_fingerprint_portrait_bottomright","ddd":0,"assets":[{"id":"comp_0","nm":"Fingerprint_Animation_ForConfirm_Short_For_ErrorToFingerprint","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"circle fill 5","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":249,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":388,"s":[100]},{"t":408,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":239,"op":1411,"st":239,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-52.056,-2.445],[-17.306,32.25],[52.194,-37.194]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"t":249,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":239,"op":1139,"st":239,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".green400","cl":"green400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":249,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":388,"s":[100]},{"t":408,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.450980392157,0.709803921569,0.470588235294,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":239,"op":1411,"st":239,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"circle fill 3","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":80,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":90,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.8,"y":0},"t":108,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"t":118,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,35.389],[-0.111,50.111]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0.049,42.698],"ix":2},"a":{"a":0,"k":[0.049,42.698],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":80,"op":980,"st":80,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".red400","cl":"red400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":7,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0.333},"t":85,"s":[209.333,136.333,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":440,"s":[209.333,136.333,0],"to":[1.944,2.278,0],"ti":[3.056,-2.278,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":450,"s":[221,150,0],"to":[-3.056,2.278,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":460,"s":[191,150,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":470,"s":[221,150,0],"to":[0,0,0],"ti":[2.5,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":480,"s":[191,150,0],"to":[-2.5,0,0],"ti":[-2.5,0,0]},{"t":490,"s":[206,150,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[132,132,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 12","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":90,"ix":10},"p":{"a":0,"k":[170,170,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":0,"nm":"Fingerprint_Animation_ForConfirm_Short_For_ErrorToFingerprint","parent":1,"refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":-90,"ix":10},"p":{"a":0,"k":[0,-92.333,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[30,30,100],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":0,"op":792,"st":-108,"bm":0}],"markers":[{"tm":255,"cm":"","dr":0},{"tm":364,"cm":"","dr":0},{"tm":482,"cm":"","dr":0},{"tm":600,"cm":"","dr":0}]}
\ No newline at end of file
diff --git a/packages/SystemUI/res/raw/biometricprompt_symbol_error_to_fingerprint_portrait_topleft.json b/packages/SystemUI/res/raw/biometricprompt_symbol_error_to_fingerprint_portrait_topleft.json
new file mode 100644
index 0000000..b082265
--- /dev/null
+++ b/packages/SystemUI/res/raw/biometricprompt_symbol_error_to_fingerprint_portrait_topleft.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":21,"w":340,"h":340,"nm":"biometricprompt_symbol_error_to_fingerprint_portrait_topleft","ddd":0,"assets":[{"id":"comp_0","nm":"Fingerprint_Animation_ForConfirm_Short_For_ErrorToFingerprint","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"circle fill 5","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":249,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":388,"s":[100]},{"t":408,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":239,"op":1411,"st":239,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-52.056,-2.445],[-17.306,32.25],[52.194,-37.194]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"t":249,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":239,"op":1139,"st":239,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".green400","cl":"green400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":249,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":388,"s":[100]},{"t":408,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.450980392157,0.709803921569,0.470588235294,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":239,"op":1411,"st":239,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"circle fill 3","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":80,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":90,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.8,"y":0},"t":108,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"t":118,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,35.389],[-0.111,50.111]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0.049,42.698],"ix":2},"a":{"a":0,"k":[0.049,42.698],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":80,"op":980,"st":80,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".red400","cl":"red400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":7,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0.333},"t":85,"s":[209.333,136.333,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":440,"s":[209.333,136.333,0],"to":[1.944,2.278,0],"ti":[3.056,-2.278,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":450,"s":[221,150,0],"to":[-3.056,2.278,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":460,"s":[191,150,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":470,"s":[221,150,0],"to":[0,0,0],"ti":[2.5,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":480,"s":[191,150,0],"to":[-2.5,0,0],"ti":[-2.5,0,0]},{"t":490,"s":[206,150,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[132,132,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 12","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":-90,"ix":10},"p":{"a":0,"k":[170,170,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":0,"nm":"Fingerprint_Animation_ForConfirm_Short_For_ErrorToFingerprint","parent":1,"refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":90,"ix":10},"p":{"a":0,"k":[0,-92.333,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[30,30,100],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":0,"op":792,"st":-108,"bm":0}],"markers":[{"tm":255,"cm":"","dr":0},{"tm":364,"cm":"","dr":0},{"tm":482,"cm":"","dr":0},{"tm":600,"cm":"","dr":0}]}
\ No newline at end of file
diff --git a/packages/SystemUI/res/raw/biometricprompt_symbol_error_to_success_landscape.json b/packages/SystemUI/res/raw/biometricprompt_symbol_error_to_success_landscape.json
new file mode 100644
index 0000000..befe3bb
--- /dev/null
+++ b/packages/SystemUI/res/raw/biometricprompt_symbol_error_to_success_landscape.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":21,"w":340,"h":340,"nm":"biometricprompt_symbol_error_to_success_landscape","ddd":0,"assets":[{"id":"comp_0","nm":"Fingerprint_Animation_ForConfirm_ErrorToSuccess","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"circle fill 5","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":118,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":257,"s":[100]},{"t":277,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":108,"op":1280,"st":108,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-52.056,-2.445],[-17.306,32.25],[52.194,-37.194]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":112,"s":[0]},{"t":122,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":112,"op":1012,"st":112,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".green400","cl":"green400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":118,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":257,"s":[100]},{"t":277,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.450980392157,0.709803921569,0.470588235294,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":108,"op":1280,"st":108,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"circle fill 3","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":80,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":90,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.8,"y":0},"t":108,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"t":118,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,35.389],[-0.111,50.111]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0.049,42.698],"ix":2},"a":{"a":0,"k":[0.049,42.698],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":80,"op":980,"st":80,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".red400","cl":"red400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":7,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0.333},"t":85,"s":[209.333,136.333,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":440,"s":[209.333,136.333,0],"to":[1.944,2.278,0],"ti":[3.056,-2.278,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":450,"s":[221,150,0],"to":[-3.056,2.278,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":460,"s":[191,150,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":470,"s":[221,150,0],"to":[0,0,0],"ti":[2.5,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":480,"s":[191,150,0],"to":[-2.5,0,0],"ti":[-2.5,0,0]},{"t":490,"s":[206,150,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[132,132,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"Fingerprint_Animation_ForConfirm_ErrorToSuccess","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[170,77.667,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[30,30,100],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":0,"op":792,"st":-108,"bm":0}],"markers":[{"tm":255,"cm":"","dr":0},{"tm":364,"cm":"","dr":0},{"tm":482,"cm":"","dr":0},{"tm":600,"cm":"","dr":0}]}
\ No newline at end of file
diff --git a/packages/SystemUI/res/raw/biometricprompt_symbol_error_to_success_portrait_bottomright.json b/packages/SystemUI/res/raw/biometricprompt_symbol_error_to_success_portrait_bottomright.json
new file mode 100644
index 0000000..d75b335
--- /dev/null
+++ b/packages/SystemUI/res/raw/biometricprompt_symbol_error_to_success_portrait_bottomright.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":21,"w":340,"h":340,"nm":"biometricprompt_symbol_error_to_success_portrait_bottomright","ddd":0,"assets":[{"id":"comp_0","nm":"Fingerprint_Animation_ForConfirm_ErrorToSuccess","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"circle fill 5","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":118,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":257,"s":[100]},{"t":277,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":108,"op":1280,"st":108,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-52.056,-2.445],[-17.306,32.25],[52.194,-37.194]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":112,"s":[0]},{"t":122,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":112,"op":1012,"st":112,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".green400","cl":"green400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":118,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":257,"s":[100]},{"t":277,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.450980392157,0.709803921569,0.470588235294,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":108,"op":1280,"st":108,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"circle fill 3","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":80,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":90,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.8,"y":0},"t":108,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"t":118,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,35.389],[-0.111,50.111]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0.049,42.698],"ix":2},"a":{"a":0,"k":[0.049,42.698],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":80,"op":980,"st":80,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".red400","cl":"red400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":7,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0.333},"t":85,"s":[209.333,136.333,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":440,"s":[209.333,136.333,0],"to":[1.944,2.278,0],"ti":[3.056,-2.278,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":450,"s":[221,150,0],"to":[-3.056,2.278,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":460,"s":[191,150,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":470,"s":[221,150,0],"to":[0,0,0],"ti":[2.5,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":480,"s":[191,150,0],"to":[-2.5,0,0],"ti":[-2.5,0,0]},{"t":490,"s":[206,150,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[132,132,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 13","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":90,"ix":10},"p":{"a":0,"k":[170,170,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":0,"nm":"Fingerprint_Animation_ForConfirm_ErrorToSuccess","parent":1,"refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":-90,"ix":10},"p":{"a":0,"k":[0,-92.333,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[30,30,100],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":0,"op":792,"st":-108,"bm":0}],"markers":[{"tm":255,"cm":"","dr":0},{"tm":364,"cm":"","dr":0},{"tm":482,"cm":"","dr":0},{"tm":600,"cm":"","dr":0}]}
\ No newline at end of file
diff --git a/packages/SystemUI/res/raw/biometricprompt_symbol_error_to_success_portrait_topleft.json b/packages/SystemUI/res/raw/biometricprompt_symbol_error_to_success_portrait_topleft.json
new file mode 100644
index 0000000..e6b2db1
--- /dev/null
+++ b/packages/SystemUI/res/raw/biometricprompt_symbol_error_to_success_portrait_topleft.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":21,"w":340,"h":340,"nm":"biometricprompt_symbol_error_to_success_portrait_topleft","ddd":0,"assets":[{"id":"comp_0","nm":"Fingerprint_Animation_ForConfirm_ErrorToSuccess","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"circle fill 5","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":118,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":257,"s":[100]},{"t":277,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":108,"op":1280,"st":108,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-52.056,-2.445],[-17.306,32.25],[52.194,-37.194]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":112,"s":[0]},{"t":122,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":112,"op":1012,"st":112,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".green400","cl":"green400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":118,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":257,"s":[100]},{"t":277,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.450980392157,0.709803921569,0.470588235294,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":108,"op":1280,"st":108,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"circle fill 3","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":80,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":90,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.8,"y":0},"t":108,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"t":118,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,35.389],[-0.111,50.111]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0.049,42.698],"ix":2},"a":{"a":0,"k":[0.049,42.698],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":80,"op":980,"st":80,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".red400","cl":"red400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":7,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0.333},"t":85,"s":[209.333,136.333,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":440,"s":[209.333,136.333,0],"to":[1.944,2.278,0],"ti":[3.056,-2.278,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":450,"s":[221,150,0],"to":[-3.056,2.278,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":460,"s":[191,150,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":470,"s":[221,150,0],"to":[0,0,0],"ti":[2.5,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":480,"s":[191,150,0],"to":[-2.5,0,0],"ti":[-2.5,0,0]},{"t":490,"s":[206,150,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[132,132,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 13","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":-90,"ix":10},"p":{"a":0,"k":[170,170,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":0,"nm":"Fingerprint_Animation_ForConfirm_ErrorToSuccess","parent":1,"refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":90,"ix":10},"p":{"a":0,"k":[0,-92.333,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[30,30,100],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":0,"op":792,"st":-108,"bm":0}],"markers":[{"tm":255,"cm":"","dr":0},{"tm":364,"cm":"","dr":0},{"tm":482,"cm":"","dr":0},{"tm":600,"cm":"","dr":0}]}
\ No newline at end of file
diff --git a/packages/SystemUI/res/raw/biometricprompt_symbol_fingerprint_to_error_portrait_bottomright.json b/packages/SystemUI/res/raw/biometricprompt_symbol_fingerprint_to_error_portrait_bottomright.json
new file mode 100644
index 0000000..0da143c
--- /dev/null
+++ b/packages/SystemUI/res/raw/biometricprompt_symbol_fingerprint_to_error_portrait_bottomright.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":21,"w":340,"h":340,"nm":"biometricprompt_symbol_fingerprint_to_error_portrait_bottomright","ddd":0,"assets":[{"id":"comp_0","nm":"Fingerprint_Animation_ForConfirm_Short","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"circle fill 5","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":249,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":388,"s":[100]},{"t":408,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":239,"op":1411,"st":239,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-52.056,-2.445],[-17.306,32.25],[52.194,-37.194]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"t":249,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":239,"op":1139,"st":239,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".green400","cl":"green400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":249,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":388,"s":[100]},{"t":408,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.450980392157,0.709803921569,0.470588235294,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":239,"op":1411,"st":239,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"circle fill 3","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":80,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":90,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.8,"y":0},"t":108,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"t":118,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,35.389],[-0.111,50.111]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0.049,42.698],"ix":2},"a":{"a":0,"k":[0.049,42.698],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":80,"op":980,"st":80,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".red400","cl":"red400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":7,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0.333},"t":85,"s":[209.333,136.333,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":440,"s":[209.333,136.333,0],"to":[1.944,2.278,0],"ti":[3.056,-2.278,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":450,"s":[221,150,0],"to":[-3.056,2.278,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":460,"s":[191,150,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":470,"s":[221,150,0],"to":[0,0,0],"ti":[2.5,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":480,"s":[191,150,0],"to":[-2.5,0,0],"ti":[-2.5,0,0]},{"t":490,"s":[206,150,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[132,132,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 14","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":90,"ix":10},"p":{"a":0,"k":[170,170,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":0,"nm":"Fingerprint_Animation_ForConfirm_Short","parent":1,"refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":-90,"ix":10},"p":{"a":0,"k":[0,-92.333,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[30,30,100],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":0,"op":830,"st":-70,"bm":0}],"markers":[{"tm":255,"cm":"","dr":0},{"tm":364,"cm":"","dr":0},{"tm":482,"cm":"","dr":0},{"tm":600,"cm":"","dr":0}]}
\ No newline at end of file
diff --git a/packages/SystemUI/res/raw/biometricprompt_symbol_fingerprint_to_error_portrait_topleft.json b/packages/SystemUI/res/raw/biometricprompt_symbol_fingerprint_to_error_portrait_topleft.json
new file mode 100644
index 0000000..15457c7
--- /dev/null
+++ b/packages/SystemUI/res/raw/biometricprompt_symbol_fingerprint_to_error_portrait_topleft.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":21,"w":340,"h":340,"nm":"biometricprompt_symbol_fingerprint_to_error_portrait_topleft","ddd":0,"assets":[{"id":"comp_0","nm":"Fingerprint_Animation_ForConfirm_Short","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"circle fill 5","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":249,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":388,"s":[100]},{"t":408,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":239,"op":1411,"st":239,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-52.056,-2.445],[-17.306,32.25],[52.194,-37.194]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"t":249,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":239,"op":1139,"st":239,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".green400","cl":"green400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":249,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":388,"s":[100]},{"t":408,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.450980392157,0.709803921569,0.470588235294,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":239,"op":1411,"st":239,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"circle fill 3","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":80,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":90,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.8,"y":0},"t":108,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"t":118,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,35.389],[-0.111,50.111]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0.049,42.698],"ix":2},"a":{"a":0,"k":[0.049,42.698],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":80,"op":980,"st":80,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".red400","cl":"red400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":7,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0.333},"t":85,"s":[209.333,136.333,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":440,"s":[209.333,136.333,0],"to":[1.944,2.278,0],"ti":[3.056,-2.278,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":450,"s":[221,150,0],"to":[-3.056,2.278,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":460,"s":[191,150,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":470,"s":[221,150,0],"to":[0,0,0],"ti":[2.5,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":480,"s":[191,150,0],"to":[-2.5,0,0],"ti":[-2.5,0,0]},{"t":490,"s":[206,150,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[132,132,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 14","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":-90,"ix":10},"p":{"a":0,"k":[170,170,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":0,"nm":"Fingerprint_Animation_ForConfirm_Short","parent":1,"refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":90,"ix":10},"p":{"a":0,"k":[0,-92.333,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[30,30,100],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":0,"op":830,"st":-70,"bm":0}],"markers":[{"tm":255,"cm":"","dr":0},{"tm":364,"cm":"","dr":0},{"tm":482,"cm":"","dr":0},{"tm":600,"cm":"","dr":0}]}
\ No newline at end of file
diff --git a/packages/SystemUI/res/raw/biometricprompt_symbol_fingerprint_to_success_landscape.json b/packages/SystemUI/res/raw/biometricprompt_symbol_fingerprint_to_success_landscape.json
new file mode 100644
index 0000000..f39894b
--- /dev/null
+++ b/packages/SystemUI/res/raw/biometricprompt_symbol_fingerprint_to_success_landscape.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":21,"w":340,"h":340,"nm":"biometricprompt_symbol_fingerprint_to_success_landscape","ddd":0,"assets":[{"id":"comp_0","nm":"Fingerprint_Animation_ForConfirm_Short","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"circle fill 5","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":249,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":388,"s":[100]},{"t":408,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":239,"op":1411,"st":239,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-52.056,-2.445],[-17.306,32.25],[52.194,-37.194]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"t":249,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":239,"op":1139,"st":239,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".green400","cl":"green400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":249,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":388,"s":[100]},{"t":408,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.450980392157,0.709803921569,0.470588235294,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":239,"op":1411,"st":239,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"circle fill 3","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":80,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":90,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.8,"y":0},"t":108,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"t":118,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,35.389],[-0.111,50.111]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0.049,42.698],"ix":2},"a":{"a":0,"k":[0.049,42.698],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":80,"op":980,"st":80,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".red400","cl":"red400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":7,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0.333},"t":85,"s":[209.333,136.333,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":440,"s":[209.333,136.333,0],"to":[1.944,2.278,0],"ti":[3.056,-2.278,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":450,"s":[221,150,0],"to":[-3.056,2.278,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":460,"s":[191,150,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":470,"s":[221,150,0],"to":[0,0,0],"ti":[2.5,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":480,"s":[191,150,0],"to":[-2.5,0,0],"ti":[-2.5,0,0]},{"t":490,"s":[206,150,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[132,132,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"Fingerprint_Animation_ForConfirm_Short","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[170,77.667,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[30,30,100],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":0,"op":661,"st":-239,"bm":0}],"markers":[{"tm":255,"cm":"","dr":0},{"tm":364,"cm":"","dr":0},{"tm":482,"cm":"","dr":0},{"tm":600,"cm":"","dr":0}]}
\ No newline at end of file
diff --git a/packages/SystemUI/res/raw/biometricprompt_symbol_fingerprint_to_success_portrait_bottomright.json b/packages/SystemUI/res/raw/biometricprompt_symbol_fingerprint_to_success_portrait_bottomright.json
new file mode 100644
index 0000000..6d4f4e2
--- /dev/null
+++ b/packages/SystemUI/res/raw/biometricprompt_symbol_fingerprint_to_success_portrait_bottomright.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":21,"w":340,"h":340,"nm":"biometricprompt_symbol_fingerprint_to_success_portrait_bottomright","ddd":0,"assets":[{"id":"comp_0","nm":"Fingerprint_Animation_ForConfirm_Short","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"circle fill 5","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":249,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":388,"s":[100]},{"t":408,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":239,"op":1411,"st":239,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-52.056,-2.445],[-17.306,32.25],[52.194,-37.194]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"t":249,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":239,"op":1139,"st":239,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".green400","cl":"green400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":249,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":388,"s":[100]},{"t":408,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.450980392157,0.709803921569,0.470588235294,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":239,"op":1411,"st":239,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"circle fill 3","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":80,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":90,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.8,"y":0},"t":108,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"t":118,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,35.389],[-0.111,50.111]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0.049,42.698],"ix":2},"a":{"a":0,"k":[0.049,42.698],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":80,"op":980,"st":80,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".red400","cl":"red400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":7,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0.333},"t":85,"s":[209.333,136.333,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":440,"s":[209.333,136.333,0],"to":[1.944,2.278,0],"ti":[3.056,-2.278,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":450,"s":[221,150,0],"to":[-3.056,2.278,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":460,"s":[191,150,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":470,"s":[221,150,0],"to":[0,0,0],"ti":[2.5,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":480,"s":[191,150,0],"to":[-2.5,0,0],"ti":[-2.5,0,0]},{"t":490,"s":[206,150,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[132,132,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 15","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":90,"ix":10},"p":{"a":0,"k":[170,170,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":0,"nm":"Fingerprint_Animation_ForConfirm_Short","parent":1,"refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":-90,"ix":10},"p":{"a":0,"k":[0,-92.333,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[30,30,100],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":0,"op":661,"st":-239,"bm":0}],"markers":[{"tm":255,"cm":"","dr":0},{"tm":364,"cm":"","dr":0},{"tm":482,"cm":"","dr":0},{"tm":600,"cm":"","dr":0}]}
\ No newline at end of file
diff --git a/packages/SystemUI/res/raw/biometricprompt_symbol_fingerprint_to_success_portrait_topleft.json b/packages/SystemUI/res/raw/biometricprompt_symbol_fingerprint_to_success_portrait_topleft.json
new file mode 100644
index 0000000..b7bb0d5
--- /dev/null
+++ b/packages/SystemUI/res/raw/biometricprompt_symbol_fingerprint_to_success_portrait_topleft.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":21,"w":340,"h":340,"nm":"biometricprompt_symbol_fingerprint_to_success_portrait_topleft","ddd":0,"assets":[{"id":"comp_0","nm":"Fingerprint_Animation_ForConfirm_Short","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"circle fill 5","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":249,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":388,"s":[100]},{"t":408,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":239,"op":1411,"st":239,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-52.056,-2.445],[-17.306,32.25],[52.194,-37.194]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"t":249,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":239,"op":1139,"st":239,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".green400","cl":"green400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":249,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":388,"s":[100]},{"t":408,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.450980392157,0.709803921569,0.470588235294,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":239,"op":1411,"st":239,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"circle fill 3","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":80,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":90,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.8,"y":0},"t":108,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"t":118,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,35.389],[-0.111,50.111]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0.049,42.698],"ix":2},"a":{"a":0,"k":[0.049,42.698],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":80,"op":980,"st":80,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".red400","cl":"red400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":7,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0.333},"t":85,"s":[209.333,136.333,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":440,"s":[209.333,136.333,0],"to":[1.944,2.278,0],"ti":[3.056,-2.278,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":450,"s":[221,150,0],"to":[-3.056,2.278,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":460,"s":[191,150,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":470,"s":[221,150,0],"to":[0,0,0],"ti":[2.5,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":480,"s":[191,150,0],"to":[-2.5,0,0],"ti":[-2.5,0,0]},{"t":490,"s":[206,150,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[132,132,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 15","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":-90,"ix":10},"p":{"a":0,"k":[170,170,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":0,"nm":"Fingerprint_Animation_ForConfirm_Short","parent":1,"refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":90,"ix":10},"p":{"a":0,"k":[0,-92.333,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[30,30,100],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":0,"op":661,"st":-239,"bm":0}],"markers":[{"tm":255,"cm":"","dr":0},{"tm":364,"cm":"","dr":0},{"tm":482,"cm":"","dr":0},{"tm":600,"cm":"","dr":0}]}
\ No newline at end of file
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index fa6b896..3eead52 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Kan nie gesig herken nie. Gebruik eerder vingerafdruk."</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"Kan nie gesig herken nie"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Gebruik eerder vingerafdruk"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth gekoppel."</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Batterypersentasie is onbekend."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Gekoppel aan <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -419,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Onderskrifteoorlegger"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"aktiveer"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"deaktiveer"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"Klank en vibrasie"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Instellings"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"Program is vasgespeld"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Dit hou dit in sig totdat jy dit ontspeld. Raak en hou Terug en Oorsig om dit te ontspeld."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Dit hou dit in sig totdat jy dit ontspeld. Raak en hou Terug en Tuis om dit te ontspeld."</string>
@@ -594,7 +598,7 @@
<string name="switch_bar_on" msgid="1770868129120096114">"Aan"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"Af"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"Onbeskikbaar"</string>
- <string name="tile_disabled" msgid="373212051546573069">"Gedeaktiveer"</string>
+ <string name="accessibility_tile_disabled_by_policy_action_description" msgid="6958422730461646926">"kom meer te wete"</string>
<string name="nav_bar" msgid="4642708685386136807">"Navigasiebalk"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"Uitleg"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"Ekstra linksknoppie-tipe"</string>
@@ -667,8 +671,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"Sommige kenmerke is beperk terwyl foon afkoel.\nTik vir meer inligting"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Jou foon sal outomaties probeer om af te koel. Jy kan steeds jou foon gebruik, maar dit sal dalk stadiger wees.\n\nJou foon sal normaalweg werk nadat dit afgekoel het."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Sien versorgingstappe"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"Trek laaier uit"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Kan nie hierdie toestel laai nie. Trek die kragprop uit, en wees versigtig, want die kabel kan warm wees."</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Sien versorgingstappe"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Links-kortpad"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Regs-kortpad"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 9ae63db..f49e2af 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"መልክን መለየት አልተቻለም። በምትኩ የጣት አሻራ ይጠቀሙ።"</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"መልክን መለየት አልተቻለም"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"በምትኩ የጣት አሻራን ይጠቀሙ"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"ብሉቱዝ ተያይዟል።"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"የባትሪ መቶኛ አይታወቅም።"</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"ከ<xliff:g id="BLUETOOTH">%s</xliff:g> ጋር ተገናኝቷል።"</string>
@@ -339,8 +341,7 @@
<string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ኃይል በመሙላት ላይ • በ<xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> ውስጥ ይሞላል"</string>
<string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • በፍጥነት ኃይልን በመሙላት ላይ • በ<xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> ውስጥ ይሞላል"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • በዝግታ ኃይልን በመሙላት ላይ • በ<xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> ውስጥ ይሞላል"</string>
- <!-- no translation found for keyguard_indication_charging_time_dock (3149328898931741271) -->
- <skip />
+ <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="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ተጠቃሚ ቀይር"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"ወደታች ተጎታች ምናሌ"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"በዚህ ክፍለ-ጊዜ ውስጥ ያሉ ሁሉም መተግበሪያዎች እና ውሂብ ይሰረዛሉ።"</string>
@@ -420,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"የሥዕል መግለጫ ጽሑፎች ንብርብር"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"አንቃ"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"አሰናክል"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"ድምጽ እና ንዝረት"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"ቅንብሮች"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"መተግበሪያ ተሰክቷል"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"ይሄ እስኪነቅሉት ድረስ በእይታ ውስጥ ያስቀምጠዋል። ለመንቀል ተመለስ እና አጠቃላይ ዕይታ የሚለውን ይጫኑ እና ይያዙ።"</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"ይሄ እስኪነቅሉት ድረስ በእይታ ውስጥ ያስቀምጠዋል። ለመንቀል ተመለስ እና መነሻ የሚለውን ይንኩ እና ይያዙ።"</string>
@@ -595,7 +598,8 @@
<string name="switch_bar_on" msgid="1770868129120096114">"በርቷል"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"ጠፍቷል"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"አይገኝም"</string>
- <string name="tile_disabled" msgid="373212051546573069">"ተሰናክሏል"</string>
+ <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+ <skip />
<string name="nav_bar" msgid="4642708685386136807">"የአሰሳ አሞሌ"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"አቀማመጥ"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"ተጨማሪ የግራ አዝራር ዓይነት"</string>
@@ -668,8 +672,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"አንዳንድ ባሕሪያት ስልኩ እየቀዘቀዘ እያለ ውስን ይሆናሉ።\nለተጨማሪ መረጃ መታ ያድርጉ"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"የእርስዎ ስልክ በራስ-ሰር ለመቀዝቀዝ ይሞክራል። አሁንም ስልክዎን መጠቀም ይችላሉ፣ ነገር ግን ሊንቀራፈፍ ይችላል።\n\nአንዴ ስልክዎ ከቀዘቀዘ በኋላ በመደበኝነት ያሄዳል።"</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"የእንክብካቤ ደረጃዎችን ይመልከቱ"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"ኃይል መሙያን ይንቀሉ"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"የዚህን መሣሪያ ባትሪ መሙላት ላይ ችግር አለ። የኃይል አስማሚውን ይንቀሉትና ሊግል ስለሚችል ገመዱን ይጠብቁት።"</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"የእንክብካቤ ደረጃዎችን ይመልከቱ"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"የግራ አቋራጭ"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"የቀኝ አቋራጭ"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 8d7dc9b2..fd576b3 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -21,7 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"واجهة مستخدم النظام"</string>
<string name="battery_low_title" msgid="5319680173344341779">"هل تريد تفعيل ميزة \"توفير شحن البطارية\"؟"</string>
- <string name="battery_low_description" msgid="3282977755476423966">"يتبقى لديك <xliff:g id="PERCENTAGE">%s</xliff:g> من شحن البطارية. يؤدي استخدام ميزة \"توفير شحن البطارية\" إلى تفعيل وضع \"المظهر الداكن\" وتقييد الأنشطة في الخلفية وتأخير الإشعارات."</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"يتبقى لديك <xliff:g id="PERCENTAGE">%s</xliff:g> من شحن البطارية. يؤدي استخدام ميزة \"توفير شحن البطارية\" إلى تفعيل وضع \"المظهر الداكن\" وحظر الأنشطة في الخلفية وتأخير الإشعارات."</string>
<string name="battery_low_intro" msgid="5148725009653088790">"يؤدي استخدام ميزة \"توفير شحن البطارية\" إلى تفعيل وضع \"المظهر الداكن\" وتقييد الأنشطة في الخلفية وتأخير الإشعارات."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"متبقي <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"يتعذّر الشحن باستخدام USB."</string>
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"يتعذّر التعرّف على الوجه. استخدِم بصمة الإصبع بدلاً من ذلك."</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"يتعذّر التعرّف على الوجه."</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"يمكنك استخدام بصمة إصبعك."</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"تم توصيل البلوتوث."</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"نسبة شحن البطارية غير معروفة."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"متصل بـ <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -339,8 +341,7 @@
<string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • جارٍ الشحن • ستمتلئ البطارية خلال <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
<string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • جارٍ الشحن سريعًا • ستمتلئ البطارية خلال <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • جارٍ الشحن ببطء • ستمتلئ البطارية خلال <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
- <!-- no translation found for keyguard_indication_charging_time_dock (3149328898931741271) -->
- <skip />
+ <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="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"تبديل المستخدم"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"القائمة المنسدلة"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"سيتم حذف كل التطبيقات والبيانات في هذه الجلسة."</string>
@@ -420,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"تراكب الشرح"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"تفعيل"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"إيقاف"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"الصوت والاهتزاز"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"الإعدادات"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"تم تثبيت الشاشة على التطبيق"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"يؤدي هذا إلى استمرار عرض الشاشة المُختارة إلى أن تتم إزالة تثبيتها. المس مع الاستمرار الزرين \"رجوع\" و\"نظرة عامة\" لإزالة التثبيت."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"يؤدي هذا إلى استمرار عرض الشاشة المُختارة إلى أن تتم إزالة تثبيتها. المس مع الاستمرار الزرين \"رجوع\" و\"الشاشة الرئيسية\" لإزالة التثبيت."</string>
@@ -595,7 +598,8 @@
<string name="switch_bar_on" msgid="1770868129120096114">"مفعّل"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"متوقف"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"غير متوفّر"</string>
- <string name="tile_disabled" msgid="373212051546573069">"غير مفعّل"</string>
+ <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+ <skip />
<string name="nav_bar" msgid="4642708685386136807">"شريط التنقل"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"التنسيق"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"نوع زر اليسار الإضافي"</string>
@@ -668,8 +672,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"يتم تقييد عمل بعض الميزات إلى أن تنخفض درجة حرارة الهاتف.\nانقر للحصول على مزيد من المعلومات."</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"سيحاول الهاتف تخفيض درجة حرارته تلقائيًا. سيظل بإمكانك استخدام هاتفك، ولكن قد يعمل بشكل أبطأ.\n\nبعد أن تنخفض درجة حرارة الهاتف، سيستعيد سرعته المعتادة."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"الاطّلاع على خطوات العناية"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"فصل الشاحن"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"هناك مشكلة في شحن هذا الجهاز. يُرجى فصل محوِّل الطاقة بحرص لأن الكابل قد يكون ساخنًا."</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"الاطّلاع على خطوات العناية"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"اختصار اليسار"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"اختصار اليمين"</string>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index 056094d..b735215 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"মুখাৱয়ব চিনিব নোৱাৰি। ফিংগাৰপ্ৰিণ্ট ব্যৱহাৰ কৰক।"</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"মুখাৱয়ব চিনিব নোৱাৰি"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"ইয়াৰ সলনি ফিংগাৰপ্ৰিণ্ট ব্যৱহাৰ কৰক"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"ব্লুটুথ সংযোগ হ’ল।"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"বেটাৰীৰ চাৰ্জৰ শতাংশ অজ্ঞাত।"</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g>ৰ লগত সংযোগ কৰা হ’ল।"</string>
@@ -300,7 +302,7 @@
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"অৱলোকন ট’গল কৰক"</string>
<string name="zen_priority_introduction" msgid="3159291973383796646">"আপুনি নিৰ্দিষ্ট কৰা এলাৰ্ম, ৰিমাইণ্ডাৰ, ইভেন্ট আৰু কল কৰোঁতাৰ বাহিৰে আন কোনো শব্দৰ পৰা আপুনি অসুবিধা নাপাব। কিন্তু, সংগীত, ভিডিঅ\' আৰু খেলসমূহকে ধৰি আপুনি প্লে কৰিব খোজা যিকোনো বস্তু তথাপি শুনিব পাৰিব।"</string>
<string name="zen_alarms_introduction" msgid="3987266042682300470">"আপুনি নিৰ্দিষ্ট কৰা এলাৰ্মৰ বাহিৰে আন কোনো ধ্বনি আৰু কম্পনৰ পৰা আপুনি অসুবিধা নাপাব। কিন্তু, সংগীত, ভিডিঅ\' আৰু খেলসমূহকে ধৰি আপুনি প্লে কৰিব খোজা যিকোনো বস্তু তথাপি শুনিব পাৰিব।"</string>
- <string name="zen_priority_customize_button" msgid="4119213187257195047">"নিজৰ উপযোগিতা অনুসৰি"</string>
+ <string name="zen_priority_customize_button" msgid="4119213187257195047">"কাষ্টমাইজ কৰক"</string>
<string name="zen_silence_introduction_voice" msgid="853573681302712348">"এই কার্যই এলার্ম, সংগীত, ভিডিঅ\' আৰু খেলসমূহকে ধৰি আটাইবোৰৰ বাবে ধ্বনি আৰু কম্পন অৱৰোধ কৰিব। আপুনি ফ\'ন কল তথাপি কৰিবলৈ সক্ষম হ\'ব।"</string>
<string name="zen_silence_introduction" msgid="6117517737057344014">"এই কার্যই এলার্ম, মিউজিক, ভিডিঅ\' আৰু গেইমকে ধৰি আটাইবোৰৰ ধ্বনি আৰু কম্পন অৱৰোধ কৰে।"</string>
<string name="notification_tap_again" msgid="4477318164947497249">"খুলিবলৈ পুনৰাই টিপক"</string>
@@ -339,8 +341,7 @@
<string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • চাৰ্জ হৈ আছে • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>ত সম্পূৰ্ণ হ’ব"</string>
<string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • দ্ৰুতগতিৰে চাৰ্জ হৈ আছে • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>ত সম্পূৰ্ণ হ’ব"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • লাহে লাহে চাৰ্জ হৈ আছে • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>ত সম্পূৰ্ণ হ’ব"</string>
- <!-- no translation found for keyguard_indication_charging_time_dock (3149328898931741271) -->
- <skip />
+ <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="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ব্যৱহাৰকাৰী সলনি কৰক"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"পুল-ডাউনৰ মেনু"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"এই ছেশ্বনৰ আটাইবোৰ এপ্ আৰু ডেটা মচা হ\'ব।"</string>
@@ -420,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"কেপশ্বন অভাৰলে’"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"সক্ষম কৰক"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"অক্ষম কৰক"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"ধ্বনি আৰু কম্পন"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"ছেটিং"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"এপ্টো পিন কৰা আছে"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"এই কাৰ্যই আপুনি আনপিন নকৰালৈকে ইয়াক দেখা পোৱা অৱস্থাত ৰাখে। আনপিন কৰিবলৈ \'পিছলৈ যাওক\' আৰু \'অৱলোকন\'-ত স্পৰ্শ কৰি থাকক।"</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"এই কাৰ্যই আপুনি আনপিন নকৰালৈকে ইয়াক দেখা পোৱা অৱস্থাত ৰাখে। আনপিন কৰিবলৈ পিছলৈ যাওক আৰু হ\'মত স্পৰ্শ কৰি সেঁচি ধৰক।"</string>
@@ -529,7 +532,7 @@
<string name="notification_channel_controls_opened_accessibility" msgid="6111817750774381094">"<xliff:g id="APP_NAME">%1$s</xliff:g>ৰ জাননী নিয়ন্ত্ৰণসমূহ খোলা অৱস্থাত আছে"</string>
<string name="notification_channel_controls_closed_accessibility" msgid="1561909368876911701">"<xliff:g id="APP_NAME">%1$s</xliff:g>ৰ জাননী নিয়ন্ত্ৰণসমূহ বন্ধ অৱস্থাত আছে"</string>
<string name="notification_more_settings" msgid="4936228656989201793">"অধিক ছেটিং"</string>
- <string name="notification_app_settings" msgid="8963648463858039377">"নিজৰ উপযোগিতা অনুসৰি"</string>
+ <string name="notification_app_settings" msgid="8963648463858039377">"কাষ্টমাইজ কৰক"</string>
<string name="notification_conversation_bubble" msgid="2242180995373949022">"বাবল হিচাপে দেখুৱাওক"</string>
<string name="notification_conversation_unbubble" msgid="6908427185031099868">"Bubbles আঁতৰাওক"</string>
<string name="notification_menu_accessibility" msgid="8984166825879886773">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
@@ -595,7 +598,8 @@
<string name="switch_bar_on" msgid="1770868129120096114">"অন"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"অফ"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"উপলব্ধ নহয়"</string>
- <string name="tile_disabled" msgid="373212051546573069">"অক্ষম কৰা আছে"</string>
+ <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+ <skip />
<string name="nav_bar" msgid="4642708685386136807">"নেভিগেশ্বন দণ্ড"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"লেআউট"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"বাওঁ বুটামৰ অতিৰিক্ত প্ৰকাৰ"</string>
@@ -668,8 +672,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"ফ’নটো ঠাণ্ডা হৈ থকাৰ সময়ত কিছুমান সুবিধা উপলব্ধ নহয়।\nঅধিক তথ্যৰ বাবে টিপক"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"আপোনাৰ ফ\'নটোৱে নিজে নিজে ঠাণ্ডা হ\'বলৈ স্বয়ংক্ৰিয়ভাৱে চেষ্টা কৰিব। আপুনি ফ\'নটো ব্যৱহাৰ কৰি থাকিব পাৰে কিন্তু ই লাহে লাহে চলিব পাৰে।\n\nফ\'নটো সম্পূৰ্ণভাৱে ঠাণ্ডা হোৱাৰ পিছত ই আগৰ নিচিনাকৈয়েই চলিব।"</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"যত্ন লোৱাৰ পদক্ষেপসমূহ চাওক"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"চ্চার্জাৰ আনপ্লাগ কৰক"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"এই ডিভাইচটো চ্চার্জ কৰোঁতে কিবা সমস্যা হৈছে। পাৱাৰ এডাপ্টাৰটো আনপ্লাগ কৰক, কেব’লডাল গৰম হ’ব পাৰে গতিকে সাবধান হ’ব।"</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"যত্ন লোৱাৰ পদক্ষেপসমূহ চাওক"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"বাওঁ শ্বৰ্টকাট"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"সোঁ শ্বৰ্টকাট"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index cb1ff11..c797a0d 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Tanımaq olmur. Barmaq izini işlədin."</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"Üzü tanımaq olmur"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Barmaq izi istifadə edin"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth qoşulub."</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Batareyanın faizi naməlumdur."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> üzərindən qoşuldu."</string>
@@ -419,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Subtitr başlığı"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"aktiv edin"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"deaktiv edin"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"Səs və vibrasiya"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Ayarlar"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"Tətbiq bərkidilib"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Sancaq götürülənə qədər bu görünəcək. Sancağı götürmək üçün Geri və İcmal düymələrinə basıb saxlayın."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"\"Geri\" və \"Əsas ekran\" düymələrinin davamlı basılması ilə çıxarılana qədər tətbiq göz önündə qalır."</string>
@@ -594,7 +598,8 @@
<string name="switch_bar_on" msgid="1770868129120096114">"Aktiv"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"Deaktiv"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"Əlçatan deyil"</string>
- <string name="tile_disabled" msgid="373212051546573069">"Deaktiv edilib"</string>
+ <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+ <skip />
<string name="nav_bar" msgid="4642708685386136807">"Naviqasiya paneli"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"Tərtibat"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"Əlavə sol düymə növü"</string>
@@ -667,8 +672,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"Telefon soyuyana kimi bəzi funksiyalar məhdudlaşdırılır.\nƏtraflı məlumat üçün toxunun"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Telefonunuz avtomatik olaraq soyumağa başlayacaq. Telefon istifadəsinə davam edə bilərsiniz, lakin sürəti yavaşlaya bilər.\n\nTelefonunuz soyuduqdan sonra normal işləyəcək."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Ehtiyat tədbiri mərhələlərinə baxın"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"Adapteri cərəyandan ayırın"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Bu cihazın batareya yığmasında problem var. Adapteri cərəyandan ayırın. Ehtiyatlı olun, kabel isti ola bilər."</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Ehtiyat tədbiri mərhələlərinə baxın"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Sol qısayol"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Sağ qısayol"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index a432568..c39e77e 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Lice nije prepoznato. Koristite otisak prsta."</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"Lice nije prepoznato"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Koristite otisak prsta"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth je priključen."</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Procenat napunjenosti baterije nije poznat."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Povezani ste sa <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -419,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Preklapanje titlova"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"omogućite"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"onemogućite"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"Zvuk i vibriranje"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Podešavanja"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"Aplikacija je zakačena"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Na ovaj način se ovo stalno prikazuje dok ga ne otkačite. Dodirnite i zadržite Nazad i Pregled da biste ga otkačili."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Na ovaj način se ovo stalno prikazuje dok ga ne otkačite. Dodirnite i zadržite Nazad i Početna da biste ga otkačili."</string>
@@ -594,7 +598,8 @@
<string name="switch_bar_on" msgid="1770868129120096114">"Uključeno"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"Isključeno"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"Nedostupno"</string>
- <string name="tile_disabled" msgid="373212051546573069">"Onemogućeno"</string>
+ <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+ <skip />
<string name="nav_bar" msgid="4642708685386136807">"Traka za navigaciju"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"Raspored"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"Dodatni tip levog dugmeta"</string>
@@ -667,8 +672,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"Neke funkcije su ograničene dok se telefon ne ohladi.\nDodirnite za više informacija"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Telefon će automatski pokušati da se ohladi. I dalje ćete moći da koristite telefon, ali će sporije reagovati.\n\nKada se telefon ohladi, normalno će raditi."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Pogledajte upozorenja"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"Isključite punjač iz struje"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Došlo je do problema sa punjenjem ovog uređaja. Isključite adapter iz napajanja i budite pažljivi jer kabl može da bude topao."</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Pogledajte upozorenja"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Leva prečica"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Desna prečica"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index a73a5e5..a43d065 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Твар не распазнаны. Скарыстайце адбітак пальца."</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"Твар не распазнаны"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Скарыстайце адбітак пальца"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth-сувязь."</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Працэнт зараду акумулятара невядомы."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Падлучаны да <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -339,8 +341,7 @@
<string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Ідзе зарадка • Поўны зарад праз <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
<string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Ідзе хуткая зарадка • Поўны зарад праз <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Ідзе павольная зарадка • Поўны зарад праз <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
- <!-- no translation found for keyguard_indication_charging_time_dock (3149328898931741271) -->
- <skip />
+ <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="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Перайсці да іншага карыстальніка"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"высоўнае меню"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Усе праграмы і даныя гэтага сеанса будуць выдалены."</string>
@@ -420,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Накладанне субцітраў"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"уключыць"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"адключыць"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"Гук і вібрацыя"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Налады"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"Праграма замацавана"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Будзе паказвацца, пакуль не адмацуеце. Каб адмацаваць, краніце і ўтрымлівайце кнопкі \"Назад\" і \"Агляд\"."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Будзе паказвацца, пакуль не адмацуеце. Каб адмацаваць, націсніце і ўтрымлівайце кнопкі \"Назад\" і \"Галоўны экран\"."</string>
@@ -595,7 +598,8 @@
<string name="switch_bar_on" msgid="1770868129120096114">"Уключана"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"Выключана"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"Недаступна"</string>
- <string name="tile_disabled" msgid="373212051546573069">"Выключана"</string>
+ <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+ <skip />
<string name="nav_bar" msgid="4642708685386136807">"Панэль навігацыі"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"Раскладка"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"Дадатковы тып кнопкі \"ўлева\""</string>
@@ -668,8 +672,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"Некаторыя функцыі абмежаваны, пакуль тэлефон не астыне.\nНацісніце, каб даведацца больш"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Ваш тэлефон аўтаматычна паспрабуе астыць. Вы можаце па-ранейшаму карыстацца сваім тэлефонам, але ён можа працаваць больш павольна.\n\nПасля таго як ваш тэлефон астыне, ён будзе працаваць у звычайным рэжыме."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Глядзець паэтапную дапамогу"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"Адключыце зарадную прыладу"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Узнікла праблема з зарадкай гэтай прылады. Адключыце адаптар сілкавання і праверце, ці не нагрэўся кабель."</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Глядзець паэтапную дапамогу"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Ярлык \"улева\""</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Ярлык \"управа\""</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 88a1cea..634e758 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Лицето не е разпознато. Използвайте отпечатък."</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"Лицето не е разпознато"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Използвайте отпечатък"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth е включен."</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Процентът на батерията е неизвестен."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Има връзка с <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -419,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Наслагване на надписите"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"активиране"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"деактивиране"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"Звук и вибриране"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Настройки"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"Приложението е фиксирано"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Екранът ще се показва, докато не го освободите с докосване и задържане на бутона за връщане назад и този за общ преглед."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Екранът ще се показва, докато не го освободите с докосване и задържане на бутона за връщане назад и „Начало“."</string>
@@ -594,7 +598,8 @@
<string name="switch_bar_on" msgid="1770868129120096114">"Вкл."</string>
<string name="switch_bar_off" msgid="5669805115416379556">"Изкл."</string>
<string name="tile_unavailable" msgid="3095879009136616920">"Не е налице"</string>
- <string name="tile_disabled" msgid="373212051546573069">"Деактивирано"</string>
+ <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+ <skip />
<string name="nav_bar" msgid="4642708685386136807">"Лента за навигация"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"Оформление"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"Тип на допълнителния ляв бутон"</string>
@@ -667,8 +672,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"Някои функции са ограничени, докато телефонът се охлажда.\nДокоснете за още информация"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Телефонът ви автоматично ще направи опит за охлаждане. Пак можете да го използвате, но той може да работи по-бавно.\n\nСлед като се охлади, ще работи нормално."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Вижте стъпките, които да предприемете"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"Изключете зарядното устройство"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"При зареждането на това устройство възникна проблем. Изключете захранващия адаптер и внимавайте, тъй като кабелът може да е топъл."</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Вижте стъпките, които да предприемете"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Ляв пряк път"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Десен пряк път"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 498c49c..f36827b 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"মুখ শনাক্ত করতে পারছি না। পরিবর্তে আঙ্গুলের ছাপ ব্যবহার করুন।"</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"ফেস শনাক্ত করা যায়নি"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"পরিবর্তে ফিঙ্গারপ্রিন্ট ব্যবহার করুন"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"ব্লুটুথ সংযুক্ত হয়েছে৷"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"ব্যাটারি কত শতাংশ আছে তা জানা যায়নি।"</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g>এ সংযুক্ত হয়ে আছে।"</string>
@@ -419,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"ক্যাপশন ওভারলে"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"চালু হবে"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"বন্ধ হবে"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"সাউন্ড ও ভাইব্রেশন"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"সেটিংস"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"অ্যাপ পিন করা হয়েছে"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"এটি আপনি আনপিন না করা পর্যন্ত এটিকে প্রদর্শিত করবে৷ আনপিন করতে ফিরুন এবং ওভারভিউ স্পর্শ করে ধরে থাকুন।"</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"এর ফলে আপনি এটি আনপিন না করা পর্যন্ত এটি দেখানো হতে থাকবে। আনপিন করতে \"ফিরে যান\" এবং \"হোম\" বোতামদুটি ট্যাপ করে ধরে রাখুন।"</string>
@@ -594,7 +598,7 @@
<string name="switch_bar_on" msgid="1770868129120096114">"চালু আছে"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"বন্ধ আছে"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"উপলভ্য নয়"</string>
- <string name="tile_disabled" msgid="373212051546573069">"বন্ধ করা আছে"</string>
+ <string name="accessibility_tile_disabled_by_policy_action_description" msgid="6958422730461646926">"আরও জানুন"</string>
<string name="nav_bar" msgid="4642708685386136807">"নেভিগেশন বার"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"লেআউট"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"অতিরিক্ত বাঁদিকের বোতামের ধরণ"</string>
@@ -667,8 +671,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"ফোন ঠাণ্ডা না হওয়া পর্যন্ত কিছু ফিচার কাজ করে না।\nআরও তথ্যের জন্য ট্যাপ করুন"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"আপনার ফোনটি নিজে থেকেই ঠাণ্ডা হওয়ার চেষ্টা করবে৷ আপনি তবুও আপনার ফোন ব্যবহার করতে পারেন, কিন্তু এটি একটু ধীরে চলতে পারে৷\n\nআপনার ফোনটি পুরোপুরি ঠাণ্ডা হয়ে গেলে এটি স্বাভাবিকভাবে চলবে৷"</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"ডিভাইস রক্ষণাবেক্ষণের ধাপগুলি দেখুন"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"চার্জার আনপ্লাগ করুন"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"এই ডিভাইস চার্জ করার সময় সমস্যা হয়েছে। চার্জিং কেবলটি হয়ত গরম হয়ে গেছে, পাওয়ার অ্যাডাপ্টারটি আনপ্লাগ করুন।"</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"কী করতে হবে ধাপে ধাপে দেখুন"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"বাঁদিকের শর্টকাট"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"ডানদিকের শর্টকাট"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 6105a66..cc2afc8 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Nije moguće prepoznati lice. Koristite otisak prsta."</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"Nije moguće prepoznati lice"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Koristite otisak prsta"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth je povezan."</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Postotak napunjenosti baterije nije poznat"</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Povezan na <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -419,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Preklapanje titlova"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"omogući"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"onemogući"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"Zvuk i vibracija"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Postavke"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"Aplikacija je zakačena"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Ekran ostaje prikazan ovako dok ga ne otkačite. Da ga otkačite, dodirnite i držite dugme Nazad."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Na ovaj način ekran ostaje prikazan dok ga ne otkačite. Da otkačite ekran, dodirnite i držite dugme Nazad i Početna."</string>
@@ -594,7 +598,8 @@
<string name="switch_bar_on" msgid="1770868129120096114">"Uključeno"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"Isključeno"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"Nedostupno"</string>
- <string name="tile_disabled" msgid="373212051546573069">"Onemogućeno"</string>
+ <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+ <skip />
<string name="nav_bar" msgid="4642708685386136807">"Navigaciona traka"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"Raspored"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"Vrsta dodatnog dugmeta lijevo"</string>
@@ -667,8 +672,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"Neke funkcije su ograničene dok se telefon hladi.\nDodirnite za više informacija"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Vaš telefon će se automatski pokušati ohladiti. I dalje možete koristi telefon, ali će možda raditi sporije.\n\nNakon što se ohladi, telefon će normalno raditi."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Pogledajte korake za zaštitu"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"Isključite punjač"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Došlo je do problema prilikom punjenja ovog uređaja. Pažljivo isključite adapter za napajanje jer je moguće da je kabl vruć."</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Prikaz koraka za zaštitu"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Prečica lijevo"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Prečica desno"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 320430c..f8bc77e 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"No podem detectar la cara. Usa l\'empremta digital."</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"No es reconeix la cara"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Utilitza l\'empremta digital"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth connectat."</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Es desconeix el percentatge de bateria."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"S\'ha connectat a <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -339,8 +341,7 @@
<string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<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="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Carregant ràpidament • Es completarà d\'aquí a <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Carregant lentament • Es completarà d\'aquí a <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
- <!-- no translation found for keyguard_indication_charging_time_dock (3149328898931741271) -->
- <skip />
+ <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="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Canvia d\'usuari"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menú desplegable"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Totes les aplicacions i les dades d\'aquesta sessió se suprimiran."</string>
@@ -420,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Superposició de subtítols"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"activar"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"desactivar"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"So i vibració"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Configuració"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"L\'aplicació està fixada"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Aquest element es continuarà mostrant fins que deixis de fixar-lo. Per fer-ho, toca i mantén premudes els botons Enrere i Aplicacions recents."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Aquest element es continuarà mostrant fins que deixis de fixar-lo. Per fer-ho, mantén premuts els botons Enrere i Inici."</string>
@@ -595,7 +598,8 @@
<string name="switch_bar_on" msgid="1770868129120096114">"Activat"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"Desactivat"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"No disponible"</string>
- <string name="tile_disabled" msgid="373212051546573069">"Desactivat"</string>
+ <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+ <skip />
<string name="nav_bar" msgid="4642708685386136807">"Barra de navegació"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"Disposició"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"Tipus de botó addicional de l\'esquerra"</string>
@@ -668,8 +672,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"Algunes funcions estan limitades mentre el telèfon es refreda.\nToca per obtenir més informació"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"El telèfon provarà de refredar-se automàticament. Podràs continuar utilitzant-lo, però és possible que funcioni més lentament.\n\nUn cop s\'hagi refredat, funcionarà amb normalitat."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Mostra els passos de manteniment"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"Desconnecta el carregador"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"No es pot carregar el dispositiu. Desconnecta l\'adaptador de corrent amb compte, ja que el cable podria estar calent."</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Mostra els pasos de manteniment"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Drecera de l\'esquerra"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Drecera de la dreta"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 4fc77ed..dc0b9f5 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -161,6 +161,8 @@
<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 keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"Obličej nelze rozpoznat"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Použijte otisk prstu"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Rozhraní Bluetooth je připojeno."</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Procento baterie není známé."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Připojeno k zařízení <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -419,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Překryvná vrstva titulků"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"aktivovat"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"deaktivovat"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"Zvuk a vibrace"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Nastavení"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"Aplikace je připnutá"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Obsah bude připnut v zobrazení, dokud jej neuvolníte. Uvolníte jej stisknutím a podržením tlačítek Zpět a Přehled."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Obsah bude připnut v zobrazení, dokud ho neuvolníte. Uvolníte ho podržením tlačítek Zpět a Plocha."</string>
@@ -594,7 +598,8 @@
<string name="switch_bar_on" msgid="1770868129120096114">"Zapnuto"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"Vypnuto"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"Nedostupné"</string>
- <string name="tile_disabled" msgid="373212051546573069">"Vypnuto"</string>
+ <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+ <skip />
<string name="nav_bar" msgid="4642708685386136807">"Navigační panel"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"Rozvržení"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"Zvláštní typ tlačítka vlevo"</string>
@@ -667,8 +672,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"Některé funkce jsou při chladnutí telefonu omezeny.\nKlepnutím zobrazíte další informace"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Telefon se automaticky pokusí vychladnout. Lze jej nadále používat, ale může být pomalejší.\n\nAž telefon vychladne, bude fungovat normálně."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Zobrazit pokyny, co dělat"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"Odpojte nabíječku"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Při nabíjení zařízení došlo k problému. Odpojte napájecí adaptér (dávejte pozor, kabel může být horký)."</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Zobrazit pokyny, co dělat"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Zkratka vlevo"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Zkratka vpravo"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 0e266a2..a38caf5 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Ansigtet kan ikke genkendes. Brug fingeraftryk i stedet."</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"Ansigt kan ikke genkendes"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Brug fingeraftryk i stedet"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth tilsluttet."</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Batteriniveauet er ukendt."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Tilsluttet <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -339,8 +341,7 @@
<string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<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="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Oplader hurtigt • Fuldt opladet om <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Oplader langsomt • Fuldt opladet om <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
- <!-- no translation found for keyguard_indication_charging_time_dock (3149328898931741271) -->
- <skip />
+ <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="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Skift bruger"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"rullemenu"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alle apps og data i denne session slettes."</string>
@@ -420,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Overlejrede undertekster"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"aktivér"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"deaktiver"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"Lyd og vibration"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Indstillinger"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"Appen er fastgjort"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Dette fastholder skærmen i visningen, indtil du frigør den. Tryk på Tilbage og Overblik, og hold fingeren nede for at frigøre skærmen."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Dette fastholder skærmen i visningen, indtil du frigør den. Hold Tilbage og Startskærm nede for at frigøre skærmen."</string>
@@ -595,7 +598,8 @@
<string name="switch_bar_on" msgid="1770868129120096114">"Til"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"Fra"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"Ikke tilgængelig"</string>
- <string name="tile_disabled" msgid="373212051546573069">"Deaktiveret"</string>
+ <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+ <skip />
<string name="nav_bar" msgid="4642708685386136807">"Navigationslinje"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"Layout"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"Ekstra venstre knaptype"</string>
@@ -668,8 +672,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"Nogle funktioner er begrænsede, mens telefonen køler ned.\nTryk for at få flere oplysninger"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Din telefon forsøger automatisk at køle ned. Du kan stadig bruge telefonen, men den kører muligvis langsommere.\n\nNår din telefon er kølet ned, fungerer den normalt igen."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Se håndteringsvejledning"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"Frakobl opladeren"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Der er et problem med opladning af denne enhed. Frakobl strømadapteren, og vær forsigtig, da kablet kan være varmt."</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Se vejledningen i pleje"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Venstre genvej"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Højre genvej"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index eef397b..b4f8252 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Gesicht wurde nicht erkannt. Verwende stattdessen den Fingerabdruck."</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"Gesicht nicht erkannt"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Fingerabdruck verwenden"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Mit Bluetooth verbunden"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Akkustand unbekannt."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Mit <xliff:g id="BLUETOOTH">%s</xliff:g> verbunden"</string>
@@ -312,10 +314,8 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Gerät mit dem Gesicht entsperrt. Tippe zum Öffnen."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Gesicht erkannt. Tippe zum Öffnen."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Gesicht erkannt. Tippe zum Öffnen auf das Symbol „Entsperren“."</string>
- <!-- no translation found for keyguard_face_successful_unlock (4203999851465708287) -->
- <skip />
- <!-- no translation found for keyguard_face_successful_unlock_alt1 (5853906076353839628) -->
- <skip />
+ <string name="keyguard_face_successful_unlock" msgid="4203999851465708287">"Gerät mit Gesicht entsperrt"</string>
+ <string name="keyguard_face_successful_unlock_alt1" msgid="5853906076353839628">"Gesicht erkannt"</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"Nach links bewegen"</item>
<item msgid="5558598599408514296">"Nach unten bewegen"</item>
@@ -341,8 +341,7 @@
<string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<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="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Wird schnell geladen • Voll in <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Wird langsam geladen • Voll in <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
- <!-- no translation found for keyguard_indication_charging_time_dock (3149328898931741271) -->
- <skip />
+ <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="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Nutzer wechseln"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"Pull-down-Menü"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alle Apps und Daten in dieser Sitzung werden gelöscht."</string>
@@ -422,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Untertitel-Overlay"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"aktivieren"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"deaktivieren"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"Ton & Vibration"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Einstellungen"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"App ist auf dem Bildschirm fixiert"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Die App bleibt so lange auf dem Bildschirm fixiert, bis du die Fixierung aufhebst. Berühre und halte dazu \"Zurück\" und \"Übersicht\"."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Die App bleibt so lange auf dem Bildschirm fixiert, bis du die Fixierung aufhebst. Berühre und halte dazu \"Zurück\" und \"Startbildschirm\"."</string>
@@ -597,7 +598,8 @@
<string name="switch_bar_on" msgid="1770868129120096114">"An"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"Aus"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"Nicht verfügbar"</string>
- <string name="tile_disabled" msgid="373212051546573069">"Deaktiviert"</string>
+ <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+ <skip />
<string name="nav_bar" msgid="4642708685386136807">"Navigationsleiste"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"Layout"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"Zusätzlicher linker Schaltflächentyp"</string>
@@ -670,8 +672,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"Einige Funktionen sind während der Abkühlphase des Smartphones eingeschränkt.\nFür mehr Informationen tippen."</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Dein Smartphone kühlt sich automatisch ab. Du kannst dein Smartphone weiterhin nutzen, aber es reagiert möglicherweise langsamer.\n\nSobald dein Smartphone abgekühlt ist, funktioniert es wieder normal."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Schritte zur Abkühlung des Geräts ansehen"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"Ladegerät vom Stromnetz trennen"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Beim Laden dieses Geräts ist ein Problem aufgetreten. Trenne das Netzteil vom Stromnetz. Sei dabei vorsichtig, denn das Netzteil oder das Kabel könnte heiß sein."</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Schritte zur Fehlerbehebung ansehen"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Linke Verknüpfung"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Rechte Verknüpfung"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 14258ee..3c6f95f 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Το πρόσωπο δεν αναγνωρίζεται. Χρησιμ. δακτ. αποτ."</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"Αδύνατη η αναγν. προσώπου"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Χρησιμ. δακτυλ. αποτύπ."</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Το Bluetooth είναι συνδεδεμένο."</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Άγνωστο ποσοστό μπαταρίας."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Συνδέθηκε στο <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -419,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Επικάλυψη υπότιτλων"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"ενεργοποίηση"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"απενεργοποίηση"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"Ήχος και δόνηση"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Ρυθμίσεις"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"Η εφαρμογή είναι καρφιτσωμένη."</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Με αυτόν τον τρόπο παραμένει σε προβολή μέχρι να το ξεκαρφιτσώσετε. Αγγίξτε παρατεταμένα τα στοιχεία \"Επιστροφή\" και \"Επισκόπηση\" για ξεκαρφίτσωμα."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Με αυτόν τον τρόπο, παραμένει σε προβολή μέχρι να το ξεκαρφιτσώσετε. Αγγίξτε παρατεταμένα τα στοιχεία \"Πίσω\" και \"Αρχική οθόνη\" για ξεκαρφίτσωμα."</string>
@@ -594,7 +598,8 @@
<string name="switch_bar_on" msgid="1770868129120096114">"Ενεργό"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"Απενεργοποίηση"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"Μη διαθέσιμο"</string>
- <string name="tile_disabled" msgid="373212051546573069">"Ανενεργό"</string>
+ <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+ <skip />
<string name="nav_bar" msgid="4642708685386136807">"Γραμμή πλοήγησης"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"Διάταξη"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"Επιπλέον τύπος αριστερού κουμπιού"</string>
@@ -667,8 +672,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"Ορισμένες λειτουργίες περιορίζονται κατά τη μείωση της θερμοκρασίας.\nΠατήστε για περισσότερες πληροφορίες."</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Το τηλέφωνό σας θα προσπαθήσει να μειώσει αυτόματα τη θερμοκρασία. Μπορείτε να εξακολουθήσετε να το χρησιμοποιείτε, αλλά είναι πιθανό να λειτουργεί πιο αργά.\n\nΜόλις μειωθεί η θερμοκρασία του τηλεφώνου σας, θα λειτουργεί ξανά κανονικά."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Δείτε βήματα αντιμετώπισης."</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"Αποσυνδέστε τον φορτιστή"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Υπάρχει κάποιο πρόβλημα με τη φόρτιση αυτής της συσκευής. Αποσυνδέστε τον μετασχηματιστή με προσοχή, λαμβάνοντας υπόψη ότι το καλώδιο μπορεί να είναι ζεστό."</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Δείτε βήματα αντιμετώπισης"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Αριστερή συντόμευση"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Δεξιά συντόμευση"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 1851d37..a067d96 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Can’t recognise face. Use fingerprint instead."</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"Can’t recognise face"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Use fingerprint instead"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth connected."</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Battery percentage unknown."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Connected to <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -419,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Captions overlay"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"enable"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"disable"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"Sound and vibration"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Settings"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"App is pinned"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"This keeps it in view until you unpin. Touch & hold Back and Overview to unpin."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"This keeps it in view until you unpin. Touch & hold Back and Home to unpin."</string>
@@ -594,7 +598,7 @@
<string name="switch_bar_on" msgid="1770868129120096114">"On"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"Off"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"Unavailable"</string>
- <string name="tile_disabled" msgid="373212051546573069">"Disabled"</string>
+ <string name="accessibility_tile_disabled_by_policy_action_description" msgid="6958422730461646926">"learn more"</string>
<string name="nav_bar" msgid="4642708685386136807">"Navigation bar"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"Layout"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"Extra left button type"</string>
@@ -667,8 +671,8 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"Some features are limited while phone cools down.\nTap for more info"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Your phone will automatically try to cool down. You can still use your phone, but it may run more slowly.\n\nOnce your phone has cooled down, it will run normally."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"See care steps"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"Unplug charger"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"There’s an issue charging this device. Unplug the power adaptor, and take care as the cable may be warm."</string>
+ <string name="high_temp_alarm_title" msgid="8654754369605452169">"Unplug your device"</string>
+ <string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"Your device is getting warm near the charging port. If it’s connected to a charger or USB accessory, unplug it and take care as the cable may also be warm."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"See care steps"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Left shortcut"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Right shortcut"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index e948f27..30183eb 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Can’t recognise face. Use fingerprint instead."</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"Can’t recognise face"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Use fingerprint instead"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth connected."</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Battery percentage unknown."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Connected to <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -419,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Captions overlay"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"enable"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"disable"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"Sound and vibration"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Settings"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"App is pinned"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"This keeps it in view until you unpin. Touch & hold Back and Overview to unpin."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"This keeps it in view until you unpin. Touch & hold Back and Home to unpin."</string>
@@ -594,7 +598,7 @@
<string name="switch_bar_on" msgid="1770868129120096114">"On"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"Off"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"Unavailable"</string>
- <string name="tile_disabled" msgid="373212051546573069">"Disabled"</string>
+ <string name="accessibility_tile_disabled_by_policy_action_description" msgid="6958422730461646926">"learn more"</string>
<string name="nav_bar" msgid="4642708685386136807">"Navigation bar"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"Layout"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"Extra left button type"</string>
@@ -667,8 +671,8 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"Some features are limited while phone cools down.\nTap for more info"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Your phone will automatically try to cool down. You can still use your phone, but it may run more slowly.\n\nOnce your phone has cooled down, it will run normally."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"See care steps"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"Unplug charger"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"There’s an issue charging this device. Unplug the power adaptor, and take care as the cable may be warm."</string>
+ <string name="high_temp_alarm_title" msgid="8654754369605452169">"Unplug your device"</string>
+ <string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"Your device is getting warm near the charging port. If it’s connected to a charger or USB accessory, unplug it and take care as the cable may also be warm."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"See care steps"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Left shortcut"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Right shortcut"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 1851d37..a067d96 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Can’t recognise face. Use fingerprint instead."</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"Can’t recognise face"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Use fingerprint instead"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth connected."</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Battery percentage unknown."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Connected to <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -419,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Captions overlay"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"enable"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"disable"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"Sound and vibration"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Settings"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"App is pinned"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"This keeps it in view until you unpin. Touch & hold Back and Overview to unpin."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"This keeps it in view until you unpin. Touch & hold Back and Home to unpin."</string>
@@ -594,7 +598,7 @@
<string name="switch_bar_on" msgid="1770868129120096114">"On"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"Off"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"Unavailable"</string>
- <string name="tile_disabled" msgid="373212051546573069">"Disabled"</string>
+ <string name="accessibility_tile_disabled_by_policy_action_description" msgid="6958422730461646926">"learn more"</string>
<string name="nav_bar" msgid="4642708685386136807">"Navigation bar"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"Layout"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"Extra left button type"</string>
@@ -667,8 +671,8 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"Some features are limited while phone cools down.\nTap for more info"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Your phone will automatically try to cool down. You can still use your phone, but it may run more slowly.\n\nOnce your phone has cooled down, it will run normally."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"See care steps"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"Unplug charger"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"There’s an issue charging this device. Unplug the power adaptor, and take care as the cable may be warm."</string>
+ <string name="high_temp_alarm_title" msgid="8654754369605452169">"Unplug your device"</string>
+ <string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"Your device is getting warm near the charging port. If it’s connected to a charger or USB accessory, unplug it and take care as the cable may also be warm."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"See care steps"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Left shortcut"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Right shortcut"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 1851d37..a067d96 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Can’t recognise face. Use fingerprint instead."</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"Can’t recognise face"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Use fingerprint instead"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth connected."</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Battery percentage unknown."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Connected to <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -419,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Captions overlay"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"enable"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"disable"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"Sound and vibration"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Settings"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"App is pinned"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"This keeps it in view until you unpin. Touch & hold Back and Overview to unpin."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"This keeps it in view until you unpin. Touch & hold Back and Home to unpin."</string>
@@ -594,7 +598,7 @@
<string name="switch_bar_on" msgid="1770868129120096114">"On"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"Off"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"Unavailable"</string>
- <string name="tile_disabled" msgid="373212051546573069">"Disabled"</string>
+ <string name="accessibility_tile_disabled_by_policy_action_description" msgid="6958422730461646926">"learn more"</string>
<string name="nav_bar" msgid="4642708685386136807">"Navigation bar"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"Layout"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"Extra left button type"</string>
@@ -667,8 +671,8 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"Some features are limited while phone cools down.\nTap for more info"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Your phone will automatically try to cool down. You can still use your phone, but it may run more slowly.\n\nOnce your phone has cooled down, it will run normally."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"See care steps"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"Unplug charger"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"There’s an issue charging this device. Unplug the power adaptor, and take care as the cable may be warm."</string>
+ <string name="high_temp_alarm_title" msgid="8654754369605452169">"Unplug your device"</string>
+ <string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"Your device is getting warm near the charging port. If it’s connected to a charger or USB accessory, unplug it and take care as the cable may also be warm."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"See care steps"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Left shortcut"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Right shortcut"</string>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index b19b728..c09d197 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Can’t recognize face. 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_suggest_fingerprint" msgid="8742015961962702960">"Use fingerprint instead"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth connected."</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Battery percentage unknown."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Connected to <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -419,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Captions overlay"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"enable"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"disable"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"Sound & vibration"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Settings"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"App is pinned"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"This keeps it in view until you unpin. Touch & hold Back and Overview to unpin."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"This keeps it in view until you unpin. Touch & hold Back and Home to unpin."</string>
@@ -594,7 +598,7 @@
<string name="switch_bar_on" msgid="1770868129120096114">"On"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"Off"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"Unavailable"</string>
- <string name="tile_disabled" msgid="373212051546573069">"Disabled"</string>
+ <string name="accessibility_tile_disabled_by_policy_action_description" msgid="6958422730461646926">"learn more"</string>
<string name="nav_bar" msgid="4642708685386136807">"Navigation bar"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"Layout"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"Extra left button type"</string>
@@ -667,8 +671,8 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"Some features limited while phone cools down.\nTap for more info"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Your phone will automatically try to cool down. You can still use your phone, but it may run slower.\n\nOnce your phone has cooled down, it will run normally."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"See care steps"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"Unplug charger"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"There’s an issue charging this device. Unplug the power adapter, and take care as the cable may be warm."</string>
+ <string name="high_temp_alarm_title" msgid="8654754369605452169">"Unplug your device"</string>
+ <string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"Your device is getting warm near the charging port. If it’s connected to a charger or USB accessory, unplug it, and take care as the cable may also be warm."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"See care steps"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Left shortcut"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Right shortcut"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index f456a19..7d47715 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"No se reconoce el rostro. Usa la huella dactilar."</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"No se reconoce el rostro"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Usa la huella dactilar"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth conectado"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Se desconoce el porcentaje de la batería."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Conectado a <xliff:g id="BLUETOOTH">%s</xliff:g>"</string>
@@ -202,7 +204,7 @@
<string name="accessibility_sensors_off_active" msgid="2619725434618911551">"Sensores desactivados sí"</string>
<string name="accessibility_clear_all" msgid="970525598287244592">"Eliminar todas las notificaciones"</string>
<string name="notification_group_overflow_indicator" msgid="7605120293801012648">"<xliff:g id="NUMBER">%s</xliff:g> más"</string>
- <string name="notification_group_overflow_description" msgid="7176322877233433278">"{count,plural, =1{# notificación más en el grupo.}other{# notificaciones más en el grupo.}}"</string>
+ <string name="notification_group_overflow_description" msgid="7176322877233433278">"{count,plural, =1{# notificación más en el grupo.}many{# notificaciones más en el grupo.}other{# notificaciones más en el grupo.}}"</string>
<string name="accessibility_rotation_lock_on_landscape" msgid="936972553861524360">"La pantalla está bloqueada en modo horizontal."</string>
<string name="accessibility_rotation_lock_on_portrait" msgid="2356633398683813837">"La pantalla está bloqueada en modo vertical."</string>
<string name="dessert_case" msgid="9104973640704357717">"Caja para postres"</string>
@@ -250,7 +252,7 @@
<string name="quick_settings_hotspot_label" msgid="1199196300038363424">"Hotspot"</string>
<string name="quick_settings_hotspot_secondary_label_transient" msgid="7585604088079160564">"Activando…"</string>
<string name="quick_settings_hotspot_secondary_label_data_saver_enabled" msgid="1280433136266439372">"Ahorro de datos act."</string>
- <string name="quick_settings_hotspot_secondary_label_num_devices" msgid="7536823087501239457">"{count,plural, =1{# dispositivo}other{# dispositivos}}"</string>
+ <string name="quick_settings_hotspot_secondary_label_num_devices" msgid="7536823087501239457">"{count,plural, =1{# dispositivo}many{# dispositivos}other{# dispositivos}}"</string>
<string name="quick_settings_flashlight_label" msgid="4904634272006284185">"Linterna"</string>
<string name="quick_settings_flashlight_camera_in_use" msgid="4820591564526512571">"Cámara en uso"</string>
<string name="quick_settings_cellular_detail_title" msgid="792977203299358893">"Datos móviles"</string>
@@ -351,7 +353,7 @@
<string name="guest_notification_session_active" msgid="5567273684713471450">"Estás en el modo de invitado"</string>
<string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Si agregas un usuario nuevo, se desactivará el modo de invitado y se borrarán todas las apps y los datos de la sesión de invitado actual."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"Alcanzaste el límite de usuarios"</string>
- <string name="user_limit_reached_message" msgid="1070703858915935796">"{count,plural, =1{Solo se puede crear un usuario.}other{Puedes agregar hasta # usuarios.}}"</string>
+ <string name="user_limit_reached_message" msgid="1070703858915935796">"{count,plural, =1{Solo se puede crear un usuario.}many{Puedes agregar hasta # usuarios.}other{Puedes agregar hasta # usuarios.}}"</string>
<string name="user_remove_user_title" msgid="9124124694835811874">"¿Confirmas que quieres quitar el usuario?"</string>
<string name="user_remove_user_message" msgid="6702834122128031833">"Se borrarán todas las aplicaciones y los datos de este usuario."</string>
<string name="user_remove_user_remove" msgid="8387386066949061256">"Quitar"</string>
@@ -419,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Superposición de subtítulos"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"habilitar"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"inhabilitar"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"Sonido y vibración"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Configuración"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"La app está fijada"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Esta función mantiene la pantalla visible hasta que dejes de fijarla. Para ello, mantén presionados los botones Atrás y Recientes."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Esta función mantiene la pantalla visible hasta que dejes de fijarla. Para ello, mantén presionados los botones de inicio y Atrás."</string>
@@ -537,8 +541,8 @@
<string name="notification_menu_snooze_action" msgid="5415729610393475019">"Recuérdame"</string>
<string name="snooze_undo" msgid="2738844148845992103">"Deshacer"</string>
<string name="snoozed_for_time" msgid="7586689374860469469">"Posponer <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
- <string name="snoozeHourOptions" msgid="2332819756222425558">"{count,plural, =1{# hora}=2{# horas}other{# horas}}"</string>
- <string name="snoozeMinuteOptions" msgid="2222082405822030979">"{count,plural, =1{# minuto}other{# minutos}}"</string>
+ <string name="snoozeHourOptions" msgid="2332819756222425558">"{count,plural, =1{# hora}=2{# horas}many{# horas}other{# horas}}"</string>
+ <string name="snoozeMinuteOptions" msgid="2222082405822030979">"{count,plural, =1{# minuto}many{# minutos}other{# minutos}}"</string>
<string name="battery_detail_switch_title" msgid="6940976502957380405">"Ahorro de batería"</string>
<string name="keyboard_key_button_template" msgid="8005673627272051429">"Botón <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="3734400625170020657">"Inicio"</string>
@@ -594,7 +598,8 @@
<string name="switch_bar_on" msgid="1770868129120096114">"Activado"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"Desactivado"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"No disponible"</string>
- <string name="tile_disabled" msgid="373212051546573069">"Inhabilitada"</string>
+ <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+ <skip />
<string name="nav_bar" msgid="4642708685386136807">"Barra de navegación"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"Diseño"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"Tipo de botón izquierdo adicional"</string>
@@ -667,8 +672,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"Algunas funciones se limitan durante el enfriamiento del teléfono.\nPresiona para obtener más información"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Tu teléfono intentará enfriarse automáticamente. Podrás usarlo, pero es posible que funcione más lento.\n\nUna vez que se haya enfriado, volverá a funcionar correctamente."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Ver pasos de mantenimiento"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"Desconectar cargador"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"No se puede cargar el dispositivo. Desconecta el adaptador de la corriente con cuidado, ya que el cable podría estar caliente."</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Ver pasos de mantenimiento"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Acceso directo izquierdo"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Acceso directo derecho"</string>
@@ -762,7 +769,7 @@
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"activar o desactivar"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Controles de dispositivos"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Elige la app para agregar los controles"</string>
- <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{Se agregó # control.}other{Se agregaron # controles.}}"</string>
+ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{Se agregó # control.}many{Se agregaron # controles.}other{Se agregaron # controles.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Quitados"</string>
<string name="accessibility_control_favorite" msgid="8694362691985545985">"Está en favoritos"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"Está en favoritos en la posición <xliff:g id="NUMBER">%d</xliff:g>"</string>
@@ -919,7 +926,7 @@
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Agregar tarjeta"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"No agregar tarjeta"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Seleccionar usuario"</string>
- <string name="fgs_manager_footer_label" msgid="8276763570622288231">"{count,plural, =1{# app está activa}other{# apps están activas}}"</string>
+ <string name="fgs_manager_footer_label" msgid="8276763570622288231">"{count,plural, =1{# app está activa}many{# apps están activas}other{# apps están activas}}"</string>
<string name="fgs_dot_content_description" msgid="2865071539464777240">"Nueva información"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Apps activas"</string>
<string name="fgs_manager_dialog_message" msgid="2670045017200730076">"Estas apps están activas y en ejecución, incluso mientras no las usas. Esto mejora su funcionalidad, pero también afecta la duración de batería."</string>
@@ -949,7 +956,7 @@
<string name="dream_overlay_status_bar_camera_off" msgid="5273073778969890823">"La cámara está desactivada"</string>
<string name="dream_overlay_status_bar_mic_off" msgid="8366534415013819396">"El micrófono está desactivado"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"La cámara y el micrófono están apagados"</string>
- <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notificación}other{# notificaciones}}"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notificación}many{# notificaciones}other{# notificaciones}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Transmitiendo"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"¿Quieres dejar de transmitir <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 5027853..e23cc2f 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"No se reconoce la cara. Usa la huella digital."</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"No se reconoce la cara"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Usa la huella digital"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth conectado"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Porcentaje de batería desconocido."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Conectado a <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -202,7 +204,7 @@
<string name="accessibility_sensors_off_active" msgid="2619725434618911551">"Sensores desactivados"</string>
<string name="accessibility_clear_all" msgid="970525598287244592">"Borrar todas las notificaciones"</string>
<string name="notification_group_overflow_indicator" msgid="7605120293801012648">"<xliff:g id="NUMBER">%s</xliff:g> más"</string>
- <string name="notification_group_overflow_description" msgid="7176322877233433278">"{count,plural, =1{# notificación más en el grupo.}other{# notificaciones más en el grupo.}}"</string>
+ <string name="notification_group_overflow_description" msgid="7176322877233433278">"{count,plural, =1{# notificación más en el grupo.}many{# notificaciones más en el grupo.}other{# notificaciones más en el grupo.}}"</string>
<string name="accessibility_rotation_lock_on_landscape" msgid="936972553861524360">"La pantalla está bloqueada en modo horizontal."</string>
<string name="accessibility_rotation_lock_on_portrait" msgid="2356633398683813837">"La pantalla está bloqueada en modo vertical."</string>
<string name="dessert_case" msgid="9104973640704357717">"Caja para postres"</string>
@@ -250,7 +252,7 @@
<string name="quick_settings_hotspot_label" msgid="1199196300038363424">"Compartir Internet"</string>
<string name="quick_settings_hotspot_secondary_label_transient" msgid="7585604088079160564">"Activando…"</string>
<string name="quick_settings_hotspot_secondary_label_data_saver_enabled" msgid="1280433136266439372">"Ahorro de datos activado"</string>
- <string name="quick_settings_hotspot_secondary_label_num_devices" msgid="7536823087501239457">"{count,plural, =1{# dispositivo}other{# dispositivos}}"</string>
+ <string name="quick_settings_hotspot_secondary_label_num_devices" msgid="7536823087501239457">"{count,plural, =1{# dispositivo}many{# dispositivos}other{# dispositivos}}"</string>
<string name="quick_settings_flashlight_label" msgid="4904634272006284185">"Linterna"</string>
<string name="quick_settings_flashlight_camera_in_use" msgid="4820591564526512571">"Cámara en uso"</string>
<string name="quick_settings_cellular_detail_title" msgid="792977203299358893">"Datos móviles"</string>
@@ -339,8 +341,7 @@
<string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Cargando • En <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> terminará de cargarse"</string>
<string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Carga rápida • En <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> terminará de cargarse"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Carga lenta • En <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> terminará de cargarse"</string>
- <!-- no translation found for keyguard_indication_charging_time_dock (3149328898931741271) -->
- <skip />
+ <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="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Cambiar de usuario"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menú desplegable"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Se eliminarán todas las aplicaciones y datos de esta sesión."</string>
@@ -352,7 +353,7 @@
<string name="guest_notification_session_active" msgid="5567273684713471450">"Estás en modo Invitado"</string>
<string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Si añades un nuevo usuario, saldrás del modo Invitado y se eliminarán todas las aplicaciones y datos de la sesión de invitado actual."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"Has alcanzado el límite de usuarios"</string>
- <string name="user_limit_reached_message" msgid="1070703858915935796">"{count,plural, =1{Solo se puede crear un usuario.}other{Puedes añadir # usuarios como máximo.}}"</string>
+ <string name="user_limit_reached_message" msgid="1070703858915935796">"{count,plural, =1{Solo se puede crear un usuario.}many{Puedes añadir # usuarios como máximo.}other{Puedes añadir # usuarios como máximo.}}"</string>
<string name="user_remove_user_title" msgid="9124124694835811874">"¿Quitar usuario?"</string>
<string name="user_remove_user_message" msgid="6702834122128031833">"Se eliminarán todas las aplicaciones y datos de este usuario."</string>
<string name="user_remove_user_remove" msgid="8387386066949061256">"Quitar"</string>
@@ -420,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Superposición de subtítulos"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"activar"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"desactivar"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"Sonido y vibración"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Ajustes"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"Aplicación fijada"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"La aplicación se mantendrá visible hasta que dejes de fijarla. Para dejar de fijarla, mantén pulsados los botones Atrás y Aplicaciones recientes."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"La aplicación se mantendrá visible hasta que dejes de fijarla. Para dejar de fijarla, mantén pulsados los botones Atrás e Inicio."</string>
@@ -538,8 +541,8 @@
<string name="notification_menu_snooze_action" msgid="5415729610393475019">"Recordar"</string>
<string name="snooze_undo" msgid="2738844148845992103">"Deshacer"</string>
<string name="snoozed_for_time" msgid="7586689374860469469">"Volverá a mostrarse en <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
- <string name="snoozeHourOptions" msgid="2332819756222425558">"{count,plural, =1{# hora}=2{# horas}other{# horas}}"</string>
- <string name="snoozeMinuteOptions" msgid="2222082405822030979">"{count,plural, =1{# minuto}other{# minutos}}"</string>
+ <string name="snoozeHourOptions" msgid="2332819756222425558">"{count,plural, =1{# hora}=2{# horas}many{# horas}other{# horas}}"</string>
+ <string name="snoozeMinuteOptions" msgid="2222082405822030979">"{count,plural, =1{# minuto}many{# minutos}other{# minutos}}"</string>
<string name="battery_detail_switch_title" msgid="6940976502957380405">"Ahorro de batería"</string>
<string name="keyboard_key_button_template" msgid="8005673627272051429">"Botón <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="3734400625170020657">"Inicio"</string>
@@ -595,7 +598,8 @@
<string name="switch_bar_on" msgid="1770868129120096114">"Activado"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"Desactivado"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"No disponible"</string>
- <string name="tile_disabled" msgid="373212051546573069">"Inhabilitado"</string>
+ <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+ <skip />
<string name="nav_bar" msgid="4642708685386136807">"Barra de navegación"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"Diseño"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"Tipo de botón a la izquierda extra"</string>
@@ -668,8 +672,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"Se han limitado algunas funciones mientras el teléfono se enfría.\nToca para ver más información"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"El teléfono intentará enfriarse. Puedes seguir utilizándolo, pero es posible que funcione con mayor lentitud.\n\nUna vez que se haya enfriado, funcionará con normalidad."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Ver pasos de mantenimiento"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"Desconecta el cargador"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"No se puede cargar el dispositivo. Desconecta el adaptador de corriente con cuidado, ya que el cable puede estar caliente."</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Ver pasos de mantenimiento"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Acceso directo a la izquierda"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Acceso directo a la derecha"</string>
@@ -763,7 +769,7 @@
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"activar/desactivar"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Control de dispositivos"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Elige una aplicación para añadir controles"</string>
- <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# control añadido.}other{# controles añadidos.}}"</string>
+ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# control añadido.}many{# controles añadidos.}other{# controles añadidos.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Quitado"</string>
<string name="accessibility_control_favorite" msgid="8694362691985545985">"Añadido a favoritos"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"Añadido a favoritos (posición <xliff:g id="NUMBER">%d</xliff:g>)"</string>
@@ -920,7 +926,7 @@
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Añadir recuadro"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"No añadir recuadro"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Selecciona un usuario"</string>
- <string name="fgs_manager_footer_label" msgid="8276763570622288231">"{count,plural, =1{# aplicación activa}other{# aplicaciones activas}}"</string>
+ <string name="fgs_manager_footer_label" msgid="8276763570622288231">"{count,plural, =1{# aplicación activa}many{# aplicaciones activas}other{# aplicaciones activas}}"</string>
<string name="fgs_dot_content_description" msgid="2865071539464777240">"Información nueva"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Aplicaciones activas"</string>
<string name="fgs_manager_dialog_message" msgid="2670045017200730076">"Estas aplicaciones están activas y en funcionamiento, incluso aunque no las estés usando. Esto mejora su funcionalidad, pero también puede afectar a la duración de la batería."</string>
@@ -950,7 +956,7 @@
<string name="dream_overlay_status_bar_camera_off" msgid="5273073778969890823">"La cámara está desactivada"</string>
<string name="dream_overlay_status_bar_mic_off" msgid="8366534415013819396">"El micrófono está desactivado"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"La cámara y el micrófono están desactivados"</string>
- <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notificación}other{# notificaciones}}"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notificación}many{# notificaciones}other{# notificaciones}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Emitiendo"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"¿Dejar de emitir <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 18a58db..bc6104e 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Nägu ei õnnestu tuvastada. Kasutage sõrmejälge."</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"Nägu ei õnnestu tuvastada"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Kasutage sõrmejälge"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth on ühendatud."</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Aku laetuse protsent on teadmata."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Ühendatud: <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -339,8 +341,7 @@
<string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<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="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Kiirlaadimine • Täis <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> pärast"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Aeglane laadimine • Täis <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> pärast"</string>
- <!-- no translation found for keyguard_indication_charging_time_dock (3149328898931741271) -->
- <skip />
+ <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="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Kasutaja vahetamine"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"rippmenüü"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Seansi kõik rakendused ja andmed kustutatakse."</string>
@@ -420,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Subtiitrite ülekate"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"luba"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"keela"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"Heli ja vibreerimine"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Seaded"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"Rakendus on kinnitatud"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"See hoitakse kuval, kuni selle vabastate. Vabastamiseks puudutage pikalt nuppe Tagasi ja Ülevaade."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"See hoitakse kuval, kuni selle vabastate. Vabastamiseks puudutage pikalt nuppe Tagasi ja Avakuva."</string>
@@ -595,7 +598,8 @@
<string name="switch_bar_on" msgid="1770868129120096114">"Sees"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"Väljas"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"Pole saadaval"</string>
- <string name="tile_disabled" msgid="373212051546573069">"Keelatud"</string>
+ <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+ <skip />
<string name="nav_bar" msgid="4642708685386136807">"Navigeerimisriba"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"Paigutus"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"Täiendava vasaku nupu tüüp"</string>
@@ -668,8 +672,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"Mõned funktsioonid on piiratud, kuni telefon jahtub.\nPuudutage lisateabe saamiseks."</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Teie telefon proovib automaatselt maha jahtuda. Saate telefoni ikka kasutada, kuid see võib olla aeglasem.\n\nKui telefon on jahtunud, töötab see tavapäraselt."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Vaadake hooldusjuhiseid"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"Eemaldage laadija vooluvõrgust"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Selle seadme laadimisega on probleem. Eemaldage toiteadapter ja olge ettevaatlik, sest kaabel võib olla soe."</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Vaadake hooldusjuhiseid"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Vasak otsetee"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Parem otsetee"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 4a079cf..7f07ff2 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Ezin da hauteman aurpegia. Erabili hatz-marka."</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"Ezin da ezagutu aurpegia"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Erabili hatz-marka"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth-a konektatuta."</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Bateriaren ehunekoa ezezaguna da."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> gailura konektatuta."</string>
@@ -419,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Azpititulu gainjarriak"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"gaitu"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"desgaitu"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"Audioa eta dardara"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Ezarpenak"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"Aplikazioa ainguratuta dago"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Horrela, ikusgai egongo da aingura kendu arte. Aingura kentzeko, eduki sakatuta \"Atzera\" eta \"Ikuspegi orokorra\" botoiak."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Horrela, ikusgai egongo da aingura kendu arte. Aingura kentzeko, eduki sakatuta Atzera eta Hasiera botoiak."</string>
@@ -594,7 +598,7 @@
<string name="switch_bar_on" msgid="1770868129120096114">"Aktibatuta"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"Desaktibatuta"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"Ez dago erabilgarri"</string>
- <string name="tile_disabled" msgid="373212051546573069">"Desgaituta"</string>
+ <string name="accessibility_tile_disabled_by_policy_action_description" msgid="6958422730461646926">"lortu informazio gehiago"</string>
<string name="nav_bar" msgid="4642708685386136807">"Nabigazio-barra"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"Diseinua"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"Ezkerreko botoi gehigarriaren mota"</string>
@@ -667,8 +671,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"Eginbide batzuk ezingo dira erabili telefonoa hoztu arte.\nInformazio gehiago lortzeko, sakatu hau."</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Telefonoa automatikoki saiatuko da hozten. Hoztu bitartean, telefonoa erabiltzen jarrai dezakezu, baina mantsoago funtziona lezake.\n\nTelefonoaren tenperatura jaitsi bezain laster, ohi bezala funtzionatzen jarraituko du."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Ikusi zaintzeko urratsak"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"Deskonektatu kargagailua"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Arazo bat izan da gailua kargatzean. Deskonektatu egokigailua eta kontuz ibili, kablea bero egon baitaiteke."</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Ikusi zaintzeko urratsak"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Ezkerreko lasterbidea"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Eskuineko lasterbidea"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index b8d268c..1d5e5f2 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"چهره شناسایی نشد. درعوض از اثر انگشت استفاده کنید."</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"چهره شناسایی نشد"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"از اثر انگشت استفاده کنید"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"بلوتوث متصل است."</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"درصد شارژ باتری مشخص نیست."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"به <xliff:g id="BLUETOOTH">%s</xliff:g> متصل شد."</string>
@@ -419,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"همپوشانی زیرنویس ناشنوایان"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"فعال کردن"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"غیرفعال کردن"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"صدا و لرزش"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"تنظیمات"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"برنامه سنجاق شده است"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"تا زمانی که سنجاق را برندارید، در نما نگهداشته میشود. برای برداشتن سنجاق، «برگشت» و «نمای کلی» را لمس کنید و نگهدارید."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"تا برداشتن سنجاق، در نما نگهداشته میشود. برای برداشتن سنجاق، «برگشت» و «صفحه اصلی» را لمس کنید و نگهدارید."</string>
@@ -550,8 +554,8 @@
<string name="keyboard_key_dpad_center" msgid="4079412840715672825">"مرکز"</string>
<string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string>
<string name="keyboard_key_space" msgid="6980847564173394012">"Space"</string>
- <string name="keyboard_key_enter" msgid="8633362970109751646">"ورود"</string>
- <string name="keyboard_key_backspace" msgid="4095278312039628074">"پسبر"</string>
+ <string name="keyboard_key_enter" msgid="8633362970109751646">"Enter"</string>
+ <string name="keyboard_key_backspace" msgid="4095278312039628074">"Backspace"</string>
<string name="keyboard_key_media_play_pause" msgid="8389984232732277478">"پخش/مکث"</string>
<string name="keyboard_key_media_stop" msgid="1509943745250377699">"متوقف کردن"</string>
<string name="keyboard_key_media_next" msgid="8502476691227914952">"بعدی"</string>
@@ -562,9 +566,9 @@
<string name="keyboard_key_page_down" msgid="9035902490071829731">"صفحه قبل"</string>
<string name="keyboard_key_forward_del" msgid="5325501825762733459">"حذف"</string>
<string name="keyboard_key_move_home" msgid="3496502501803911971">"ابتدا"</string>
- <string name="keyboard_key_move_end" msgid="99190401463834854">"انتها"</string>
- <string name="keyboard_key_insert" msgid="4621692715704410493">"درج"</string>
- <string name="keyboard_key_num_lock" msgid="7209960042043090548">"قفل اعداد"</string>
+ <string name="keyboard_key_move_end" msgid="99190401463834854">"End"</string>
+ <string name="keyboard_key_insert" msgid="4621692715704410493">"Insert"</string>
+ <string name="keyboard_key_num_lock" msgid="7209960042043090548">"Num Lock"</string>
<string name="keyboard_key_numpad_template" msgid="7316338238459991821">"صفحهکلید عددی <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="notif_inline_reply_remove_attachment_description" msgid="7954075334095405429">"برداشتن پیوست"</string>
<string name="keyboard_shortcut_group_system" msgid="1583416273777875970">"سیستم"</string>
@@ -594,7 +598,8 @@
<string name="switch_bar_on" msgid="1770868129120096114">"روشن"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"خاموش"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"در دسترس نیست"</string>
- <string name="tile_disabled" msgid="373212051546573069">"غیرفعال"</string>
+ <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+ <skip />
<string name="nav_bar" msgid="4642708685386136807">"نوار پیمایش"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"طرحبندی"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"نوع دکمه منتهیالیه چپ"</string>
@@ -667,8 +672,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"وقتی تلفن درحال خنک شدن است، بعضی از ویژگیها محدود میشوند.\nبرای اطلاعات بیشتر ضربه بزنید"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"تلفنتان بهطور خودکار سعی میکند خنک شود. همچنان میتوانید از تلفنتان استفاده کنید، اما ممکن است کندتر عمل کند.\n\nوقتی تلفن خنک شد، عملکرد عادیاش از سرگرفته میشود."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"دیدن اقدامات محافظتی"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"جدا کردن شارژر از برق"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"مشکلی در شارژ کردن این دستگاه وجود دارد. آداپتور برق را از برق جدا کنید و مراقب باشید زیرا ممکن است کابل گرم باشد."</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"مشاهده مراحل احتیاط"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"میانبر چپ"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"میانبر راست"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index ce85d31..0888524 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Kasvoja ei voi tunnistaa. Käytä sormenjälkeä."</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"Kasvoja ei voi tunnistaa"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Käytä sormenjälkeä"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth yhdistetty."</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Akun varaustaso ei tiedossa."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Yhteys: <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -339,8 +341,7 @@
<string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<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="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Latautuu nopeasti • Täynnä <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> päästä"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Latautuu hitaasti • Täynnä <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> päästä"</string>
- <!-- no translation found for keyguard_indication_charging_time_dock (3149328898931741271) -->
- <skip />
+ <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="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Vaihda käyttäjää"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"alasvetovalikko"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Kaikki sovellukset ja tämän istunnon tiedot poistetaan."</string>
@@ -420,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Tekstitysten peitto"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"ota käyttöön"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"poista käytöstä"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"Ääni ja värinä"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Asetukset"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"Sovellus on kiinnitetty"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Pysyy näkyvissä, kunnes irrotat sen. Irrota painamalla pitkään Edellinen ja Viimeisimmät."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Pysyy näkyvissä, kunnes irrotat sen. Irrota painamalla pitkään Edellinen ja Aloitusnäyttö."</string>
@@ -595,7 +598,8 @@
<string name="switch_bar_on" msgid="1770868129120096114">"Päällä"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"Pois päältä"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"Ei käytettävissä"</string>
- <string name="tile_disabled" msgid="373212051546573069">"Ei käytössä"</string>
+ <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+ <skip />
<string name="nav_bar" msgid="4642708685386136807">"Navigointipalkki"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"Asettelu"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"Ylimääräinen vasen painiketyyppi"</string>
@@ -668,8 +672,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"Joidenkin ominaisuuksien käyttöä on rajoitettu puhelimen jäähtymisen aikana.\nLue lisää napauttamalla"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Puhelimesi yrittää automaattisesti jäähdyttää itsensä. Voit silti käyttää puhelinta, mutta se voi toimia hitaammin.\n\nKun puhelin on jäähtynyt, se toimii normaalisti."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Katso huoltovaiheet"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"Irrota laturi"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Laitetta ladattaessa tapahtui virhe. Irrota virtalähde varovasti – johto voi olla lämmin."</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Katso huoltovaiheet"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Vasen pikakuvake"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Oikea pikakuvake"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 286e2cf..c870c06 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Visage non reconnu. Utilisez plutôt l\'empreinte digitale."</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"Visage non reconnu"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Utiliser l\'empreinte digitale"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth connecté"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Pourcentage de la pile inconnu."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Connecté à : <xliff:g id="BLUETOOTH">%s</xliff:g>"</string>
@@ -202,7 +204,7 @@
<string name="accessibility_sensors_off_active" msgid="2619725434618911551">"Option « Capteurs désactivés » active"</string>
<string name="accessibility_clear_all" msgid="970525598287244592">"Supprimer toutes les notifications"</string>
<string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
- <string name="notification_group_overflow_description" msgid="7176322877233433278">"{count,plural, =1{# autre notification à l\'intérieur.}one{# autre notification à l\'intérieur.}other{# autres notifications à l\'intérieur.}}"</string>
+ <string name="notification_group_overflow_description" msgid="7176322877233433278">"{count,plural, =1{# autre notification à l\'intérieur.}one{# autre notification à l\'intérieur.}many{# d\'autres notifications à l\'intérieur.}other{# autres notifications à l\'intérieur.}}"</string>
<string name="accessibility_rotation_lock_on_landscape" msgid="936972553861524360">"L\'écran est verrouillé en mode paysage."</string>
<string name="accessibility_rotation_lock_on_portrait" msgid="2356633398683813837">"L\'écran est verrouillé en mode portrait."</string>
<string name="dessert_case" msgid="9104973640704357717">"Vitrine des desserts"</string>
@@ -250,7 +252,7 @@
<string name="quick_settings_hotspot_label" msgid="1199196300038363424">"Point d\'accès sans fil"</string>
<string name="quick_settings_hotspot_secondary_label_transient" msgid="7585604088079160564">"Activation en cours…"</string>
<string name="quick_settings_hotspot_secondary_label_data_saver_enabled" msgid="1280433136266439372">"Écon. données activé"</string>
- <string name="quick_settings_hotspot_secondary_label_num_devices" msgid="7536823087501239457">"{count,plural, =1{# appareil}one{# appareil}other{# appareils}}"</string>
+ <string name="quick_settings_hotspot_secondary_label_num_devices" msgid="7536823087501239457">"{count,plural, =1{# appareil}one{# appareil}many{# d\'appareils}other{# appareils}}"</string>
<string name="quick_settings_flashlight_label" msgid="4904634272006284185">"Lampe de poche"</string>
<string name="quick_settings_flashlight_camera_in_use" msgid="4820591564526512571">"L\'appareil photo est en cours d\'utilisation"</string>
<string name="quick_settings_cellular_detail_title" msgid="792977203299358893">"Données cellulaires"</string>
@@ -351,7 +353,7 @@
<string name="guest_notification_session_active" msgid="5567273684713471450">"Vous êtes en mode Invité"</string>
<string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Si vous ajoutez un nouvel utilisateur, vous quitterez le mode Invité, et toutes les applications et données de la session d\'invité en cours seront supprimées."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"Limite d\'utilisateurs atteinte"</string>
- <string name="user_limit_reached_message" msgid="1070703858915935796">"{count,plural, =1{Vous ne pouvez créer qu\'un seul utilisateur.}one{Vous pouvez ajouter jusqu\'à # utilisateur.}other{Vous pouvez ajouter jusqu\'à # utilisateurs.}}"</string>
+ <string name="user_limit_reached_message" msgid="1070703858915935796">"{count,plural, =1{Vous ne pouvez créer qu\'un seul utilisateur.}one{Vous pouvez ajouter jusqu\'à # utilisateur.}many{Vous pouvez ajouter jusqu\'à # d\'utilisateurs.}other{Vous pouvez ajouter jusqu\'à # utilisateurs.}}"</string>
<string name="user_remove_user_title" msgid="9124124694835811874">"Supprimer l\'utilisateur?"</string>
<string name="user_remove_user_message" msgid="6702834122128031833">"Toutes les applications et les données de cet utilisateur seront supprimées."</string>
<string name="user_remove_user_remove" msgid="8387386066949061256">"Supprimer"</string>
@@ -419,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Superposition de sous-titres"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"activer"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"désactiver"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"Son et vibration"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Paramètres"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"L\'application est épinglée"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Cet écran est épinglé jusqu\'à ce que vous annuliez l\'opération. Pour annuler l\'épinglage, maintenez le doigt sur « Retour » et « Aperçu »."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Cet écran est épinglé jusqu\'à ce que vous annuliez l\'opération. Pour annuler l\'épinglage, maintenez le doigt sur les touches Retour et Accueil."</string>
@@ -537,8 +541,8 @@
<string name="notification_menu_snooze_action" msgid="5415729610393475019">"Me rappeler"</string>
<string name="snooze_undo" msgid="2738844148845992103">"Annuler"</string>
<string name="snoozed_for_time" msgid="7586689374860469469">"Reporté pour <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
- <string name="snoozeHourOptions" msgid="2332819756222425558">"{count,plural, =1{# heure}=2{# heures}one{# heure}other{# heures}}"</string>
- <string name="snoozeMinuteOptions" msgid="2222082405822030979">"{count,plural, =1{# minute}one{# minute}other{# minutes}}"</string>
+ <string name="snoozeHourOptions" msgid="2332819756222425558">"{count,plural, =1{# heure}=2{# heures}one{# heure}many{# d\'heures}other{# heures}}"</string>
+ <string name="snoozeMinuteOptions" msgid="2222082405822030979">"{count,plural, =1{# minute}one{# minute}many{# de minutes}other{# minutes}}"</string>
<string name="battery_detail_switch_title" msgid="6940976502957380405">"Économiseur de pile"</string>
<string name="keyboard_key_button_template" msgid="8005673627272051429">"Bouton <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="3734400625170020657">"Accueil"</string>
@@ -594,7 +598,7 @@
<string name="switch_bar_on" msgid="1770868129120096114">"Activé"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"Désactivé"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"Non disponible"</string>
- <string name="tile_disabled" msgid="373212051546573069">"Désactivé"</string>
+ <string name="accessibility_tile_disabled_by_policy_action_description" msgid="6958422730461646926">"En savoir plus"</string>
<string name="nav_bar" msgid="4642708685386136807">"Barre de navigation"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"Disposition"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"Type de bouton gauche supplémentaire"</string>
@@ -667,8 +671,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"Certaines fonctionnalités sont limitées pendant que le téléphone refroidit.\nTouchez pour en savoir plus"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Votre téléphone va essayer de se refroidir automatiquement. Vous pouvez toujours l\'utiliser, mais il risque d\'être plus lent.\n\nUne fois refroidi, il fonctionnera normalement."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Afficher les étapes d\'entretien"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"Débranchez le chargeur"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Il y a un problème avec la recharge de cet appareil. Débranchez l\'adaptateur d\'alimentation, et faites attention, car le câble pourrait être chaud."</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Afficher les étapes d\'entretien"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Raccourci gauche"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Raccourci droit"</string>
@@ -762,7 +768,7 @@
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"basculer"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Commandes des appareils"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Sélectionnez l\'application pour laquelle ajouter des commandes"</string>
- <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# commande ajoutée.}one{# commande ajoutée.}other{# commandes ajoutées.}}"</string>
+ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# commande ajoutée.}one{# commande ajoutée.}many{# de commandes ajoutées.}other{# commandes ajoutées.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Supprimé"</string>
<string name="accessibility_control_favorite" msgid="8694362691985545985">"Ajouté aux favoris"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"Ajouté aux favoris, en position <xliff:g id="NUMBER">%d</xliff:g>"</string>
@@ -919,7 +925,7 @@
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Ajouter la tuile"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Ne pas ajouter de tuile"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Choisir l\'utilisateur"</string>
- <string name="fgs_manager_footer_label" msgid="8276763570622288231">"{count,plural, =1{# application est active}one{# application est active}other{# applications sont actives}}"</string>
+ <string name="fgs_manager_footer_label" msgid="8276763570622288231">"{count,plural, =1{# application est active}one{# application est active}many{# d\'applications sont actives}other{# applications sont actives}}"</string>
<string name="fgs_dot_content_description" msgid="2865071539464777240">"Nouvelle information"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Applications actives"</string>
<string name="fgs_manager_dialog_message" msgid="2670045017200730076">"Ces applications sont actives et s\'exécutent même lorsque vous ne les utilisez pas. Cela améliore leur fonctionnalité, mais peut également affecter l\'autonomie de la pile."</string>
@@ -949,7 +955,7 @@
<string name="dream_overlay_status_bar_camera_off" msgid="5273073778969890823">"L\'appareil photo est désactivé"</string>
<string name="dream_overlay_status_bar_mic_off" msgid="8366534415013819396">"Le micro est désactivé"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"L\'appareil photo et le micro sont désactivés"</string>
- <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notification}one{# notification}other{# notifications}}"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notification}one{# notification}many{# de notifications}other{# notifications}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Diffusion en cours…"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Arrêter la diffusion de <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 58ebeb9..0d9b186 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Visage non reconnu. Utilisez votre empreinte."</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"Visage non reconnu"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Utilisez empreinte digit."</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth connecté"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Pourcentage de la batterie inconnu."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Connecté à : <xliff:g id="BLUETOOTH">%s</xliff:g>"</string>
@@ -202,7 +204,7 @@
<string name="accessibility_sensors_off_active" msgid="2619725434618911551">"Option \"Capteurs désactivés\" active"</string>
<string name="accessibility_clear_all" msgid="970525598287244592">"Supprimer toutes les notifications"</string>
<string name="notification_group_overflow_indicator" msgid="7605120293801012648">"<xliff:g id="NUMBER">%s</xliff:g> autres"</string>
- <string name="notification_group_overflow_description" msgid="7176322877233433278">"{count,plural, =1{# autre notification dans le groupe.}one{# autre notification dans le groupe.}other{# autres notifications dans le groupe.}}"</string>
+ <string name="notification_group_overflow_description" msgid="7176322877233433278">"{count,plural, =1{# autre notification dans le groupe.}one{# autre notification dans le groupe.}many{# autres notifications dans le groupe.}other{# autres notifications dans le groupe.}}"</string>
<string name="accessibility_rotation_lock_on_landscape" msgid="936972553861524360">"L\'écran est verrouillé en mode paysage."</string>
<string name="accessibility_rotation_lock_on_portrait" msgid="2356633398683813837">"L\'écran est verrouillé en mode portrait."</string>
<string name="dessert_case" msgid="9104973640704357717">"Vitrine des desserts"</string>
@@ -250,7 +252,7 @@
<string name="quick_settings_hotspot_label" msgid="1199196300038363424">"Point d\'accès"</string>
<string name="quick_settings_hotspot_secondary_label_transient" msgid="7585604088079160564">"Activation…"</string>
<string name="quick_settings_hotspot_secondary_label_data_saver_enabled" msgid="1280433136266439372">"Écon. données activé"</string>
- <string name="quick_settings_hotspot_secondary_label_num_devices" msgid="7536823087501239457">"{count,plural, =1{# appareil}one{# appareil}other{# appareils}}"</string>
+ <string name="quick_settings_hotspot_secondary_label_num_devices" msgid="7536823087501239457">"{count,plural, =1{# appareil}one{# appareil}many{# appareils}other{# appareils}}"</string>
<string name="quick_settings_flashlight_label" msgid="4904634272006284185">"Lampe de poche"</string>
<string name="quick_settings_flashlight_camera_in_use" msgid="4820591564526512571">"Caméra en cours d\'utilisation"</string>
<string name="quick_settings_cellular_detail_title" msgid="792977203299358893">"Données mobiles"</string>
@@ -339,8 +341,7 @@
<string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • En charge • Chargé dans <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
<string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Recharge rapide • Chargé dans <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Recharge lente • Chargé dans <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
- <!-- no translation found for keyguard_indication_charging_time_dock (3149328898931741271) -->
- <skip />
+ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Recharge • Chargé dans <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Changer d\'utilisateur"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menu déroulant"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Toutes les applications et les données de cette session seront supprimées."</string>
@@ -352,7 +353,7 @@
<string name="guest_notification_session_active" msgid="5567273684713471450">"Vous êtes en mode Invité"</string>
<string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Si vous ajoutez un utilisateur, le mode Invité sera désactivé et toutes les applis et les données de la session Invité actuelle seront supprimées."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"Limite nombre utilisateurs atteinte"</string>
- <string name="user_limit_reached_message" msgid="1070703858915935796">"{count,plural, =1{Vous ne pouvez créer qu\'un seul utilisateur.}one{Vous pouvez ajouter # utilisateur.}other{Vous pouvez ajouter jusqu\'à # utilisateurs.}}"</string>
+ <string name="user_limit_reached_message" msgid="1070703858915935796">"{count,plural, =1{Vous ne pouvez créer qu\'un seul utilisateur.}one{Vous pouvez ajouter # utilisateur.}many{Vous pouvez ajouter jusqu\'à # utilisateurs.}other{Vous pouvez ajouter jusqu\'à # utilisateurs.}}"</string>
<string name="user_remove_user_title" msgid="9124124694835811874">"Supprimer l\'utilisateur ?"</string>
<string name="user_remove_user_message" msgid="6702834122128031833">"Toutes les applications et les données de cet utilisateur seront supprimées."</string>
<string name="user_remove_user_remove" msgid="8387386066949061256">"Supprimer"</string>
@@ -420,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Sous-titres en superposition"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"activer"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"désactiver"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"Son et vibreur"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Paramètres"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"L\'application est épinglée"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Elle restera visible jusqu\'à ce que vous la retiriez. Pour la retirer, appuyez de manière prolongée sur les boutons Retour et Aperçu."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Elle restera visible jusqu\'à ce que vous la retiriez. Pour la retirer, appuyez de manière prolongée sur les boutons Retour et Accueil."</string>
@@ -538,8 +541,8 @@
<string name="notification_menu_snooze_action" msgid="5415729610393475019">"M\'envoyer un rappel"</string>
<string name="snooze_undo" msgid="2738844148845992103">"Annuler"</string>
<string name="snoozed_for_time" msgid="7586689374860469469">"Répétée après <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
- <string name="snoozeHourOptions" msgid="2332819756222425558">"{count,plural, =1{# heure}=2{# heures}one{# heure}other{# heures}}"</string>
- <string name="snoozeMinuteOptions" msgid="2222082405822030979">"{count,plural, =1{# minute}one{# minute}other{# minutes}}"</string>
+ <string name="snoozeHourOptions" msgid="2332819756222425558">"{count,plural, =1{# heure}=2{# heures}one{# heure}many{# heures}other{# heures}}"</string>
+ <string name="snoozeMinuteOptions" msgid="2222082405822030979">"{count,plural, =1{# minute}one{# minute}many{# minutes}other{# minutes}}"</string>
<string name="battery_detail_switch_title" msgid="6940976502957380405">"Économiseur de batterie"</string>
<string name="keyboard_key_button_template" msgid="8005673627272051429">"Bouton <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="3734400625170020657">"Accueil"</string>
@@ -595,7 +598,8 @@
<string name="switch_bar_on" msgid="1770868129120096114">"Activé"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"Désactivé"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"Indisponible"</string>
- <string name="tile_disabled" msgid="373212051546573069">"Désactivé"</string>
+ <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+ <skip />
<string name="nav_bar" msgid="4642708685386136807">"Barre de navigation"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"Disposition"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"Type de bouton gauche supplémentaire"</string>
@@ -668,8 +672,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"Fonctionnalités limitées pendant le refroidissement du téléphone.\nAppuyer pour en savoir plus"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Votre téléphone va essayer de se refroidir automatiquement. Vous pouvez toujours l\'utiliser, mais il risque d\'être plus lent.\n\nUne fois refroidi, il fonctionnera normalement."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Afficher les étapes d\'entretien"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"Débrancher le chargeur"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Un problème est survenu lors de la recharge de cet appareil. Débranchez l\'adaptateur secteur en faisant attention, car le câble risque d\'être chaud."</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Afficher les étapes d\'entretien"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Raccourci gauche"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Raccourci droit"</string>
@@ -763,7 +769,7 @@
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"activer/désactiver"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Commandes des appareils"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Sélectionnez l\'appli pour laquelle ajouter des commandes"</string>
- <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# commande ajoutée.}one{# commande ajoutée.}other{# commandes ajoutées.}}"</string>
+ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# commande ajoutée.}one{# commande ajoutée.}many{# commandes ajoutées.}other{# commandes ajoutées.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Supprimé"</string>
<string name="accessibility_control_favorite" msgid="8694362691985545985">"Ajouté aux favoris"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"Ajouté aux favoris, en position <xliff:g id="NUMBER">%d</xliff:g>"</string>
@@ -920,7 +926,7 @@
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Ajouter le bloc"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Ne pas ajouter le bloc"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Choisir l\'utilisateur"</string>
- <string name="fgs_manager_footer_label" msgid="8276763570622288231">"{count,plural, =1{# appli est active}one{# appli est active}other{# applis sont actives}}"</string>
+ <string name="fgs_manager_footer_label" msgid="8276763570622288231">"{count,plural, =1{# appli est active}one{# appli est active}many{# applis sont actives}other{# applis sont actives}}"</string>
<string name="fgs_dot_content_description" msgid="2865071539464777240">"Nouvelles informations"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Applis actives"</string>
<string name="fgs_manager_dialog_message" msgid="2670045017200730076">"Ces applis sont actives et s\'exécutent même lorsque vous ne les utilisez pas. Cela améliore leur fonctionnement, mais peut également affecter l\'autonomie de la batterie."</string>
@@ -950,7 +956,7 @@
<string name="dream_overlay_status_bar_camera_off" msgid="5273073778969890823">"Caméra désactivée"</string>
<string name="dream_overlay_status_bar_mic_off" msgid="8366534415013819396">"Micro désactivé"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Appareil photo et micro désactivés"</string>
- <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notification}one{# notification}other{# notifications}}"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notification}one{# notification}many{# notifications}other{# notifications}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Diffusion…"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Arrêter la diffusion de <xliff:g id="APP_NAME">%1$s</xliff:g> ?"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index fbdd942..154e43f 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -161,6 +161,8 @@
<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 keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"Non se recoñeceu a cara"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Usa a impresión dixital"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth conectado"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Descoñécese a porcentaxe da batería."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Conectado a <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -339,8 +341,7 @@
<string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<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="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Cargando rapidamente • A carga completarase en <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Cargando lentamente • A carga completarase en <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
- <!-- no translation found for keyguard_indication_charging_time_dock (3149328898931741271) -->
- <skip />
+ <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="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Cambiar usuario"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menú despregable"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Eliminaranse todas as aplicacións e datos desta sesión."</string>
@@ -420,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Superposición de subtítulos"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"activa"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"desactiva"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"Son e vibración"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Configuración"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"A aplicación está fixada"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"A pantalla manterase visible ata que deixes de fixala. Para facelo, mantén premido Atrás e Visión xeral."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"A pantalla manterase visible ata que deixes de fixala. Para facelo, mantén premido Atrás e Inicio."</string>
@@ -595,7 +598,8 @@
<string name="switch_bar_on" msgid="1770868129120096114">"Activado"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"Desactivado"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"Non dispoñible"</string>
- <string name="tile_disabled" msgid="373212051546573069">"Desactivado"</string>
+ <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+ <skip />
<string name="nav_bar" msgid="4642708685386136807">"Barra de navegación"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"Deseño"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"Tipo de botón adicional á esquerda"</string>
@@ -668,8 +672,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"O uso dalgunhas funcións é limitado mentres o teléfono arrefría.\nToca para obter máis información"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"O teléfono tentará arrefriar automaticamente. Podes utilizalo, pero é probable que funcione máis lento.\n\nUnha vez que arrefríe, funcionará con normalidade."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Ver pasos de mantemento"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"Desconecta o cargador"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Produciuse un problema ao cargar este dispositivo. Desconecta o adaptador de corrente e ten coidado porque o cable pode estar quente."</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Ver pasos de mantemento"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Atallo á esquerda"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Atallo á dereita"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 9d2a786..9c547bf 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"ચહેરો ઓળખી શકતા નથી. તેને બદલે ફિંગરપ્રિન્ટ વાપરો."</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"ચહેરો ઓળખાતો નથી"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"તો ફિંગરપ્રિન્ટ વાપરો"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"બ્લૂટૂથ કનેક્ટ થયું."</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"બૅટરીની ટકાવારી અજાણ છે."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> થી કનેક્ટ થયાં."</string>
@@ -339,8 +341,7 @@
<string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ચાર્જ થઈ રહ્યું છે • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>માં ચાર્જ થઈ જશે"</string>
<string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ઝડપથી ચાર્જ થઈ રહ્યું છે • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>માં ચાર્જ થઈ જશે"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ધીમેથી ચાર્જ થઈ રહ્યું છે • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>માં ચાર્જ થઈ જશે"</string>
- <!-- no translation found for keyguard_indication_charging_time_dock (3149328898931741271) -->
- <skip />
+ <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="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"વપરાશકર્તા સ્વિચ કરો"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"પુલડાઉન મેનૂ"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"આ સત્રમાંની તમામ ઍપ અને ડેટા કાઢી નાખવામાં આવશે."</string>
@@ -420,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"કૅપ્શન ઓવરલે"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"ચાલુ કરો"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"બંધ કરો"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"સાઉન્ડ અને વાઇબ્રેશન"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"સેટિંગ"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"ઍપને પિન કરેલી છે"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"તમે જ્યાં સુધી અનપિન કરશો નહીં ત્યાં સુધી આ તેને વ્યૂમાં રાખે છે. અનપિન કરવા માટે પાછળ અને ઓવરવ્યૂને સ્પર્શ કરી રાખો."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"તમે જ્યાં સુધી અનપિન કરશો નહીં ત્યાં સુધી આ તેને વ્યૂમાં રાખે છે. અનપિન કરવા માટે પાછળ અને હોમને સ્પર્શ કરી રાખો."</string>
@@ -595,7 +598,7 @@
<string name="switch_bar_on" msgid="1770868129120096114">"ચાલુ"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"બંધ"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"ઉપલબ્ધ નથી"</string>
- <string name="tile_disabled" msgid="373212051546573069">"બંધ છે"</string>
+ <string name="accessibility_tile_disabled_by_policy_action_description" msgid="6958422730461646926">"વધુ જાણો"</string>
<string name="nav_bar" msgid="4642708685386136807">"નેવિગેશન બાર"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"લેઆઉટ"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"અતિરિક્ત ડાબો બટન પ્રકાર"</string>
@@ -668,8 +671,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"ફોન ઠંડો થાય ત્યાં સુધી અમુક સુવિધાઓ મર્યાદિત હોય છે.\nવધુ માહિતી માટે ટૅપ કરો"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"તમારો ફોન ઑટોમૅટિક રીતે ઠંડો થવાનો પ્રયાસ કરશે. તમે હજી પણ તમારા ફોનનો ઉપયોગ કરી શકો છો, પરંતુ તે કદાચ થોડો ધીમો ચાલે.\n\nતમારો ફોન ઠંડો થઈ જવા પર, તે સામાન્ય રીતે ચાલશે."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"સારસંભાળના પગલાં જુઓ"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"ચાર્જરને અનપ્લગ કરો"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"આ ડિવાઇસને ચાર્જ કરવામાં કોઈ સમસ્યા છે. પાવર અડૅપ્ટર અનપ્લગ કરો અને કાળજી લેજો કદાચ કેબલ થોડો ગરમ થયો હોઈ શકે છે."</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"સારસંભાળના પગલાં જુઓ"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"ડાબો શૉર્ટકટ"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"જમણો શૉર્ટકટ"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 0ad63d5..2808ec0 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"चेहरे की पहचान नहीं हुई. फ़िंगरप्रिंट इस्तेमाल करें."</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"चेहरे की पहचान नहीं हुई"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"फ़िंगरप्रिंट इस्तेमाल करें"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"ब्लूटूथ कनेक्ट किया गया."</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"इस बारे में जानकारी नहीं है कि अभी बैटरी कितने प्रतिशत चार्ज है."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> से कनेक्ट किया गया."</string>
@@ -419,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"कैप्शन ऊपर लगाएं"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"चालू करें"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"बंद करें"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"आवाज़ और वाइब्रेशन"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"सेटिंग"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"ऐप्लिकेशन पिन किया गया है"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"इससे वह तब तक दिखता रहता है, जब तक कि आप उसे अनपिन नहीं कर देते. अनपिन करने के लिए, \'वापस जाएं\' और \'खास जानकारी\' को दबाकर रखें."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"इससे वह तब तक दिखाई देती है जब तक आप उसे अनपिन नहीं कर देते. अनपिन करने के लिए, होम और वापस जाएं वाले बटन को दबाकर रखें."</string>
@@ -594,7 +598,8 @@
<string name="switch_bar_on" msgid="1770868129120096114">"चालू"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"बंद"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"उपलब्ध नहीं है"</string>
- <string name="tile_disabled" msgid="373212051546573069">"बंद है"</string>
+ <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+ <skip />
<string name="nav_bar" msgid="4642708685386136807">"नेविगेशन बार"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"लेआउट"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"कुछ और बाएं बटन के प्रकार"</string>
@@ -667,8 +672,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"फ़ोन के ठंडा होने तक कुछ सुविधाएं काम नहीं करतीं.\nज़्यादा जानकारी के लिए टैप करें"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"आपका फ़ोन अपने आप ठंडा होने की कोशिश करेगा. आप अब भी अपने फ़ोन का उपयोग कर सकते हैं, लेकिन हो सकता है कि यह धीमी गति से चले.\n\nठंडा हो जाने पर आपका फ़ोन सामान्य रूप से चलेगा."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"डिवाइस के रखरखाव के तरीके देखें"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"चार्जर निकालें"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"इस डिवाइस को चार्ज करने में समस्या हुई. पावर अडैप्टर का प्लग निकालें. ऐसा करते समय सावधानी बरतें क्योंकि तार गर्म हो सकता है."</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"प्रबंधन से जुड़े चरण देखें"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"बायां शॉर्टकट"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"दायां शॉर्टकट"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index ffa68d7..8d3e025 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Prepoznavanje lica nije uspjelo. Upotrijebite otisak prsta."</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"Lice nije prepoznato"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Upotrijebite otisak prsta"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth povezan."</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Postotak baterije nije poznat."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Spojen na <xliff:g id="BLUETOOTH">%s</xliff:g> ."</string>
@@ -419,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Sloj titlova"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"omogući"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"onemogući"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"Zvuk i vibracija"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Postavke"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"Aplikacija je prikvačena"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Zaslon će tako ostati u prvom planu dok ga ne otkvačite. Dodirnite i zadržite Natrag i Pregled da biste ga otkvačili."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Zaslon će tako ostati u prvom planu dok ga ne otkvačite. Dodirnite gumbe Natrag i Početna i zadržite pritisak da biste ga otkvačili."</string>
@@ -594,7 +598,8 @@
<string name="switch_bar_on" msgid="1770868129120096114">"Uključeno"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"Isključeno"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"Nedostupno"</string>
- <string name="tile_disabled" msgid="373212051546573069">"Onemogućeno"</string>
+ <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+ <skip />
<string name="nav_bar" msgid="4642708685386136807">"Navigacijska traka"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"Izgled"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"Vrsta dodatnog lijevog gumba"</string>
@@ -667,8 +672,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"Neke su značajke ograničene dok se telefon ne ohladi.\nDodirnite za više informacija"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Telefon će se automatski pokušati ohladiti. Možete ga nastaviti koristiti, no mogao bi raditi sporije.\n\nKad se ohladi, radit će normalno."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Pročitajte upute za održavanje"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"Iskopčajte punjač"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Pojavio se problem s punjenjem uređaja. Iskopčajte pretvarač napona i pazite jer se kabel može zagrijati."</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Pogledajte upute za održavanje"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Lijevi prečac"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Desni prečac"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 8c2002f..4694c9c 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Az arc nem felismerhető. Használjon ujjlenyomatot."</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"Az arc nem ismerhető fel"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Használjon ujjlenyomatot"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth csatlakoztatva."</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Az akkumulátor töltöttségi szintje ismeretlen."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Csatlakoztatva a következőhöz: <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -419,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Feliratok fedvény"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"engedélyezés"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"letiltás"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"Hang és rezgés"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Beállítások"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"Az alkalmazás ki van tűzve"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Megjelenítve tartja addig, amíg Ön fel nem oldja a rögzítést. A feloldáshoz tartsa lenyomva a Vissza és az Áttekintés lehetőséget."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Megjelenítve tartja addig, amíg Ön fel nem oldja a rögzítést. A feloldáshoz tartsa lenyomva a Vissza és a Kezdőképernyő elemet."</string>
@@ -594,7 +598,8 @@
<string name="switch_bar_on" msgid="1770868129120096114">"Be"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"Ki"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"Nem használható"</string>
- <string name="tile_disabled" msgid="373212051546573069">"Kikapcsolva"</string>
+ <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+ <skip />
<string name="nav_bar" msgid="4642708685386136807">"Navigációs sáv"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"Elrendezés"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"További bal oldali gombtípus"</string>
@@ -667,8 +672,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"Bizonyos funkciók korlátozottan működnek a telefon lehűlése közben.\nKoppintson, ha további információra van szüksége."</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"A telefon automatikusan megpróbál lehűlni. Továbbra is tudja használni a telefont, de elképzelhető, hogy működése lelassul.\n\nAmint a telefon lehűl, újra a szokásos módon működik majd."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Olvassa el a kímélő használat lépéseit"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"Húzza ki a töltőt"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Probléma adódott az eszköz töltése során. Húzza ki a hálózati adaptert. Vigyázzon, a kábel forró lehet."</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Olvassa el a megfelelő használat lépéseit"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Bal oldali parancsikon"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Jobb oldali parancsikon"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index c7936bc..c6f1ff1 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Դեմքը չի հաջողվում ճանաչել։ Օգտագործեք մատնահետքը։"</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"Դեմքը չի ճանաչվել"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Օգտագործեք մատնահետք"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth-ը միացված է:"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Մարտկոցի լիցքի մակարդակն անհայտ է։"</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Միացված է <xliff:g id="BLUETOOTH">%s</xliff:g>-ին:"</string>
@@ -339,8 +341,7 @@
<string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Լիցքավորում • Մնացել է <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
<string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Արագ լիցքավորում • Մնացել է <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Դանդաղ լիցքավորում • Մնացել է <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
- <!-- no translation found for keyguard_indication_charging_time_dock (3149328898931741271) -->
- <skip />
+ <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="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Անջատել օգտվողին"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"իջնող ընտրացանկ"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Այս աշխատաշրջանի բոլոր հավելվածներն ու տվյալները կջնջվեն:"</string>
@@ -420,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Ենթագրերի վրադրում"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"միացնել"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"անջատել"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"Ձայն և թրթռոց"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Կարգավորումներ"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"Հավելվածն ամրացված է"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Էկրանը կմնա տեսադաշտում, մինչև այն ապամրացնեք: Ապամրացնելու համար հպեք և պահեք Հետ և Համատեսք կոճակները:"</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Էկրանը կցուցադրվի այնքան ժամանակ, մինչև չեղարկեք ամրացումը: Չեղարկելու համար հպեք և պահեք «Հետ» և «Գլխավոր էկրան» կոճակները"</string>
@@ -595,7 +598,8 @@
<string name="switch_bar_on" msgid="1770868129120096114">"Միացված է"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"Անջատված է"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"Հասանելի չէ"</string>
- <string name="tile_disabled" msgid="373212051546573069">"Անջատված է"</string>
+ <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+ <skip />
<string name="nav_bar" msgid="4642708685386136807">"Նավիգացիայի գոտի"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"Դասավորություն"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"Լրացուցիչ ձախ կոճակի տեսակ"</string>
@@ -668,8 +672,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"Հովանալու ընթացքում հեռախոսի որոշ գործառույթներ սահմանափակ են։\nՀպեք՝ ավելին իմանալու համար։"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Ձեր հեռախոսն ավտոմատ կերպով կփորձի hովանալ: Կարող եք շարունակել օգտագործել հեռախոսը, սակայն հնարավոր է, որ այն ավելի դանդաղ աշխատի:\n\nՀովանալուց հետո հեռախոսը կաշխատի կանոնավոր կերպով:"</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Քայլեր գերտաքացման ահազանգի դեպքում"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"Անջատեք լիցքավորիչը հոսանքից"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Չհաջողվեց լիցքավորել սարքը: Անջատեք հոսանքի ադապտերը և ուշադիր եղեք՝ մալուխը կարող է տաքացած լինել:"</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Քայլեր գերտաքացման ահազանգի դեպքում"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Ձախ դյուրանցում"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Աջ դյուրանցում"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 882b3ea..87070cb 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Tidak dapat mengenali wajah. Gunakan sidik jari."</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"Tidak mengenali wajah"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Gunakan sidik jari"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth terhubung."</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Persentase baterai tidak diketahui."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Terhubung ke <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -419,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Overlay teks"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"aktifkan"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"nonaktifkan"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"Suara & getaran"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Setelan"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"Aplikasi disematkan"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Ini akan terus ditampilkan sampai Anda melepas sematan. Sentuh lama tombol Kembali dan Ringkasan untuk melepas sematan."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Ini akan terus ditampilkan sampai Anda melepas sematan. Sentuh lama tombol Kembali dan Beranda untuk melepas sematan."</string>
@@ -594,7 +598,8 @@
<string name="switch_bar_on" msgid="1770868129120096114">"Aktif"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"Nonaktif"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"Tidak tersedia"</string>
- <string name="tile_disabled" msgid="373212051546573069">"Nonaktif"</string>
+ <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+ <skip />
<string name="nav_bar" msgid="4642708685386136807">"Bilah navigasi"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"Tata Letak"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"Jenis tombol ekstra kiri"</string>
@@ -667,8 +672,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"Beberapa fitur dibatasi saat ponsel mendingin.\nKetuk untuk info selengkapnya"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Ponsel akan otomatis mencoba mendingin. Anda tetap dapat menggunakan ponsel, tetapi mungkin berjalan lebih lambat.\n\nSetelah dingin, ponsel akan berjalan seperti biasa."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Lihat langkah-langkah perawatan"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"Cabut pengisi daya"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Ada masalah saat mengisi daya perangkat ini. Cabut adaptor daya dan berhati-hatilah karena kabelnya mungkin panas."</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Lihat langkah-langkah perawatan"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Pintasan kiri"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Pintasan kanan"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 67ce960..8a7efd7 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Andlit þekkist ekki. Notaðu fingrafar í staðinn."</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"Andlit þekkist ekki"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Nota fingrafar í staðinn"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth tengt."</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Staða rafhlöðu óþekkt."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Tengt við <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -339,8 +341,7 @@
<string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<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="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Hraðhleðsla • Full hleðsla eftir <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Hæg hleðsla • Full hleðsla eftir <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
- <!-- no translation found for keyguard_indication_charging_time_dock (3149328898931741271) -->
- <skip />
+ <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="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Skipta um notanda"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"Fellivalmynd"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Öllum forritum og gögnum í þessari lotu verður eytt."</string>
@@ -420,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Yfirlögn myndatexta"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"virkja"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"slökkva"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"Hljóð og titringur"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Stillingar"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"Forrit er fest"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Þetta heldur þessu opnu þangað til þú losar það. Haltu fingri á „Til baka“ og „Yfirlit“ til að losa."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Þetta heldur þessu opnu þangað til það er losað. Haltu inni bakkhnappinum og heimahnappinum til að losa."</string>
@@ -595,7 +598,8 @@
<string name="switch_bar_on" msgid="1770868129120096114">"Kveikt"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"Slökkt"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"Ekki í boði"</string>
- <string name="tile_disabled" msgid="373212051546573069">"Slökkt"</string>
+ <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+ <skip />
<string name="nav_bar" msgid="4642708685386136807">"Yfirlitsstika"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"Útlit"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"Gerð aukahnapps til vinstri"</string>
@@ -668,8 +672,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"Sumir eiginleikar eru takmarkaðir meðan síminn kælir sig.\nÝttu til að fá frekari upplýsingar"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Síminn reynir sjálfkrafa að kæla sig. Þú getur enn notað símann en hann gæti verið hægvirkari.\n\nEftir að síminn hefur kælt sig niður virkar hann eðlilega."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Sjá varúðarskref"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"Taktu hleðslutækið úr sambandi"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Upp kom vandamál varðandi hleðslu tækisins. Taktu straumbreytinn úr sambandi og farðu varlega því snúran gæti verið heit."</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Sjá varúðarskref"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Flýtilykill til vinstri"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Flýtilykill til hægri"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index fbba420..5977914 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Impossibile riconoscere il volto. Usa l\'impronta."</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"Volto non riconosciuto"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Usa l\'impronta"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth collegato."</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Percentuale della batteria sconosciuta."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Connesso a <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -202,7 +204,7 @@
<string name="accessibility_sensors_off_active" msgid="2619725434618911551">"Opzione Sensori disattivati attiva"</string>
<string name="accessibility_clear_all" msgid="970525598287244592">"Cancella tutte le notifiche."</string>
<string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
- <string name="notification_group_overflow_description" msgid="7176322877233433278">"{count,plural, =1{# altra notifica nel gruppo.}other{Altre # notifiche nel gruppo.}}"</string>
+ <string name="notification_group_overflow_description" msgid="7176322877233433278">"{count,plural, =1{# altra notifica nel gruppo.}many{Altre # notifiche nel gruppo.}other{Altre # notifiche nel gruppo.}}"</string>
<string name="accessibility_rotation_lock_on_landscape" msgid="936972553861524360">"Lo schermo è bloccato in orientamento orizzontale."</string>
<string name="accessibility_rotation_lock_on_portrait" msgid="2356633398683813837">"Lo schermo è bloccato in orientamento verticale."</string>
<string name="dessert_case" msgid="9104973640704357717">"Vetrina di dolci"</string>
@@ -250,7 +252,7 @@
<string name="quick_settings_hotspot_label" msgid="1199196300038363424">"Hotspot"</string>
<string name="quick_settings_hotspot_secondary_label_transient" msgid="7585604088079160564">"Attivazione…"</string>
<string name="quick_settings_hotspot_secondary_label_data_saver_enabled" msgid="1280433136266439372">"Risp. dati attivo"</string>
- <string name="quick_settings_hotspot_secondary_label_num_devices" msgid="7536823087501239457">"{count,plural, =1{# dispositivo}other{# dispositivi}}"</string>
+ <string name="quick_settings_hotspot_secondary_label_num_devices" msgid="7536823087501239457">"{count,plural, =1{# dispositivo}many{# dispositivi}other{# dispositivi}}"</string>
<string name="quick_settings_flashlight_label" msgid="4904634272006284185">"Torcia"</string>
<string name="quick_settings_flashlight_camera_in_use" msgid="4820591564526512571">"Fotocamera in uso"</string>
<string name="quick_settings_cellular_detail_title" msgid="792977203299358893">"Dati mobili"</string>
@@ -339,8 +341,7 @@
<string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<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="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Ricarica veloce • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> alla ricarica completa"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Ricarica lenta • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> alla ricarica completa"</string>
- <!-- no translation found for keyguard_indication_charging_time_dock (3149328898931741271) -->
- <skip />
+ <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="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Cambio utente"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menu a discesa"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Tutte le app e i dati di questa sessione verranno eliminati."</string>
@@ -352,7 +353,7 @@
<string name="guest_notification_session_active" msgid="5567273684713471450">"Sei in modalità Ospite"</string>
<string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Se aggiungi un nuovo utente, la modalità Ospite viene disattivata e vengono eliminati tutti i dati e le app della sessione Ospite corrente."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"Limite di utenti raggiunto"</string>
- <string name="user_limit_reached_message" msgid="1070703858915935796">"{count,plural, =1{Può essere creato un solo utente.}other{Puoi aggiungere fino a # utenti.}}"</string>
+ <string name="user_limit_reached_message" msgid="1070703858915935796">"{count,plural, =1{Può essere creato un solo utente.}many{Puoi aggiungere fino a # utenti.}other{Puoi aggiungere fino a # utenti.}}"</string>
<string name="user_remove_user_title" msgid="9124124694835811874">"Rimuovere l\'utente?"</string>
<string name="user_remove_user_message" msgid="6702834122128031833">"Tutte le app e i dati di questo utente verranno eliminati."</string>
<string name="user_remove_user_remove" msgid="8387386066949061256">"Rimuovi"</string>
@@ -420,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Overlay sottotitoli"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"attiva"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"disattiva"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"Suoni e vibrazione"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Impostazioni"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"L\'app è bloccata sullo schermo"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"La schermata rimane visibile finché non viene sganciata. Per sganciarla, tieni premuto Indietro e Panoramica."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"La schermata rimane visibile finché non viene disattivato il blocco su schermo. Per disattivarlo, tocca e tieni premuto Indietro e Home."</string>
@@ -538,8 +541,8 @@
<string name="notification_menu_snooze_action" msgid="5415729610393475019">"Ricordamelo"</string>
<string name="snooze_undo" msgid="2738844148845992103">"Annulla"</string>
<string name="snoozed_for_time" msgid="7586689374860469469">"Posticipato di <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
- <string name="snoozeHourOptions" msgid="2332819756222425558">"{count,plural, =1{# ora}=2{# ore}other{# ore}}"</string>
- <string name="snoozeMinuteOptions" msgid="2222082405822030979">"{count,plural, =1{# minuto}other{# minuti}}"</string>
+ <string name="snoozeHourOptions" msgid="2332819756222425558">"{count,plural, =1{# ora}=2{# ore}many{# ore}other{# ore}}"</string>
+ <string name="snoozeMinuteOptions" msgid="2222082405822030979">"{count,plural, =1{# minuto}many{# minuti}other{# minuti}}"</string>
<string name="battery_detail_switch_title" msgid="6940976502957380405">"Risparmio energetico"</string>
<string name="keyboard_key_button_template" msgid="8005673627272051429">"Pulsante <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="3734400625170020657">"Home page"</string>
@@ -595,7 +598,8 @@
<string name="switch_bar_on" msgid="1770868129120096114">"On"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"Off"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"Non disponibile"</string>
- <string name="tile_disabled" msgid="373212051546573069">"Riquadro disattivato"</string>
+ <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+ <skip />
<string name="nav_bar" msgid="4642708685386136807">"Barra di navigazione"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"Layout"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"Tipo di pulsante extra sinistra"</string>
@@ -668,8 +672,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"Alcune funzionalità limitate durante il raffreddamento del telefono.\nTocca per ulteriori informazioni"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Il telefono cercherà automaticamente di raffreddarsi. Puoi comunque usarlo, ma potrebbe essere più lento.\n\nUna volta raffreddato, il telefono funzionerà normalmente."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Leggi le misure da adottare"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"Scollega il caricabatterie"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Si è verificato un problema durante la ricarica del dispositivo. Scollega l\'alimentatore e presta attenzione perché il cavo potrebbe essere caldo."</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Leggi le misure da adottare"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Scorciatoia sinistra"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Scorciatoia destra"</string>
@@ -763,7 +769,7 @@
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"attiva/disattiva"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Controllo dispositivi"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Scegli un\'app per aggiungere controlli"</string>
- <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# controllo aggiunto.}other{# controlli aggiunti.}}"</string>
+ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# controllo aggiunto.}many{# controlli aggiunti.}other{# controlli aggiunti.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Rimosso"</string>
<string name="accessibility_control_favorite" msgid="8694362691985545985">"Aggiunto ai preferiti"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"Preferito, posizione <xliff:g id="NUMBER">%d</xliff:g>"</string>
@@ -920,7 +926,7 @@
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Aggiungi riquadro"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Non aggiungerlo"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Seleziona utente"</string>
- <string name="fgs_manager_footer_label" msgid="8276763570622288231">"{count,plural, =1{C\'è # app attiva}other{Ci sono # app attive}}"</string>
+ <string name="fgs_manager_footer_label" msgid="8276763570622288231">"{count,plural, =1{C\'è # app attiva}many{Ci sono # app attive}other{Ci sono # app attive}}"</string>
<string name="fgs_dot_content_description" msgid="2865071539464777240">"Nuove informazioni"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"App attive"</string>
<string name="fgs_manager_dialog_message" msgid="2670045017200730076">"Queste app sono attive e in esecuzione, anche quando non le utilizzi. Questo migliora la loro funzionalità, ma influisce sulla durata della batteria."</string>
@@ -950,7 +956,7 @@
<string name="dream_overlay_status_bar_camera_off" msgid="5273073778969890823">"La fotocamera è disattivata"</string>
<string name="dream_overlay_status_bar_mic_off" msgid="8366534415013819396">"Il microfono è disattivato"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Fotocamera e microfono non attivi"</string>
- <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notifica}other{# notifiche}}"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notifica}many{# notifiche}other{# notifiche}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Trasmissione in corso…"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Vuoi interrompere la trasmissione dell\'app <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 42ed596..e5e37f5 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"לא ניתן לזהות את הפנים. יש להשתמש בטביעת אצבע במקום."</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"לא ניתן לזהות את הפנים"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"שימוש בטביעת אצבע במקום זאת"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth מחובר."</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"אחוז טעינת הסוללה לא ידוע."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"התבצע חיבור אל <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -419,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"שכבת-על לכיתוב"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"הפעלה"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"השבתה"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"צליל ורטט"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"הגדרות"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"האפליקציה מוצמדת"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"נשאר בתצוגה עד לביטול ההצמדה. יש ללחוץ לחיצה ארוכה על הלחצנים \'הקודם\' ו\'סקירה\' כדי לבטל את ההצמדה."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"נשאר בתצוגה עד לביטול ההצמדה. יש ללחוץ לחיצה ארוכה על הלחצנים \'הקודם\' ו\'דף הבית\' כדי לבטל את ההצמדה."</string>
@@ -594,7 +598,7 @@
<string name="switch_bar_on" msgid="1770868129120096114">"פועל"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"כבוי"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"לא זמין"</string>
- <string name="tile_disabled" msgid="373212051546573069">"מושבת"</string>
+ <string name="accessibility_tile_disabled_by_policy_action_description" msgid="6958422730461646926">"מידע נוסף"</string>
<string name="nav_bar" msgid="4642708685386136807">"סרגל הניווט"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"פריסה"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"סוג נוסף של לחצן שמאלי"</string>
@@ -667,8 +671,8 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"חלק מהתכונות מוגבלות כל עוד הטלפון מתקרר.\nיש להקיש כדי להציג מידע נוסף"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"קירור הטלפון ייעשה באופן אוטומטי. ניתן עדיין להשתמש בטלפון, אבל ייתכן שהוא יפעל לאט יותר.\n\nהטלפון יחזור לפעול כרגיל לאחר שיתקרר."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"לצפייה בשלבי הטיפול"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"יש לנתק את המטען"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"יש בעיה עם הטעינה של המכשיר הזה. צריך לנתק את מתאם המתח בזהירות כי הכבל עלול להיות חם."</string>
+ <string name="high_temp_alarm_title" msgid="8654754369605452169">"ניתוק המכשיר"</string>
+ <string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"המכשיר שלך מתחמם בקרבת יציאת הטעינה. אם המכשיר מחובר למטען או לאביזר בחיבור USB, צריך לנתק אותו בזהירות כיוון שגם הכבל עלול להיות חם."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"לצפייה בשלבי הטיפול"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"קיצור דרך שמאלי"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"קיצור דרך ימני"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index ad697f6..85fe976 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"顔を認識できません。指紋認証を使用してください。"</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"顔を認識できません"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"指紋認証をお使いください"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetoothに接続済み。"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"バッテリー残量は不明です。"</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g>に接続しました。"</string>
@@ -419,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"字幕のオーバーレイ"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"有効にする"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"無効にする"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"着信音とバイブレーション"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"設定"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"アプリは固定されています"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"固定を解除するまで画面が常に表示されるようになります。[戻る] と [最近] を同時に押し続けると固定が解除されます。"</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"固定を解除するまで画面が常に表示されるようになります。[戻る] と [ホーム] を同時に押し続けると固定が解除されます。"</string>
@@ -594,7 +598,8 @@
<string name="switch_bar_on" msgid="1770868129120096114">"ON"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"OFF"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"使用不可"</string>
- <string name="tile_disabled" msgid="373212051546573069">"無効"</string>
+ <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+ <skip />
<string name="nav_bar" msgid="4642708685386136807">"ナビゲーション バー"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"レイアウト"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"その他の左ボタンタイプ"</string>
@@ -667,8 +672,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"スマートフォンのクールダウン中は一部の機能が制限されます。\nタップして詳細を表示"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"スマートフォンは自動的にクールダウンを行います。その間もスマートフォンを使用できますが、動作が遅くなる可能性があります。\n\nクールダウンが完了すると、通常どおり動作します。"</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"取り扱いに関する手順をご覧ください"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"充電器を電源から外してください"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"このデバイスの充電中に問題が発生しました。電源アダプターを電源から外してください。ケーブルが熱くなっている可能性がありますのでご注意ください。"</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"取り扱いに関する手順をご覧ください"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"左ショートカット"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"右ショートカット"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 024384c..43c39b7 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"სახის ამოცნობა ვერ ხერხდება. სანაცვლოდ თითის ანაბეჭდი გამოიყენეთ."</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"სახის ამოცნობა შეუძლებ."</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"გამოიყენეთ თითის ანაბეჭდი"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth დაკავშირებულია."</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"ბატარეის პროცენტული მაჩვენებელი უცნობია."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"დაკავშირებულია <xliff:g id="BLUETOOTH">%s</xliff:g>-თან."</string>
@@ -419,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"სუბტიტრების გადაფარვა"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"ჩართვა"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"გამორთვა"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"ხმა და ვიბრაცია"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"პარამეტრები"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"აპი ჩამაგრებულია"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"ამით ის დარჩება ხედში ჩამაგრების მოხსნამდე. ჩამაგრების მოსახსნელად, ხანგრძლივად შეეხეთ „უკან და მიმოხილვა“-ს."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"ამით ის დარჩება ხედში ჩამაგრების მოხსნამდე. ჩამაგრების მოსახსნელად, ხანგრძლივად შეეხეთ „უკან მთავარ გვერდზე“-ს."</string>
@@ -594,7 +598,8 @@
<string name="switch_bar_on" msgid="1770868129120096114">"ჩართული"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"გამორთვა"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"მიუწვდომელი"</string>
- <string name="tile_disabled" msgid="373212051546573069">"გათიშულია"</string>
+ <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+ <skip />
<string name="nav_bar" msgid="4642708685386136807">"ნავიგაციის ზოლი"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"განლაგება"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"მარცხენა დამატებითი ღილაკის ტიპი"</string>
@@ -667,8 +672,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"ზოგიერთი ფუნქცია შეზღუდული იქნება, სანამ ტელეფონი გაგრილდება.\nშეეხეთ დამატებითი ინფორმაციის მისაღებად"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"თქვენი ტელეფონი გაგრილებას ავტომატურად შეეცდება. შეგიძლიათ გააგრძელოთ მისით სარგებლობა, თუმცა ტელეფონმა შეიძლება უფრო ნელა იმუშაოს.\n\nგაგრილების შემდგომ ის ჩვეულებრივად იმუშავებს."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"მისაღები ზომების გაცნობა"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"გამოაერთეთ დამტენი"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"ამ მოწყობილობის დატენა ვერ ხერხდება პრობლემის გამო. გამოაერთეთ ელკვების ადაპტერი და გამოიჩინეთ სიფრთხილე, რადგან კაბელი შეიძლებოდა გაცხელებულიყო."</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"მისაღები ზომების გაცნობა"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"მარცხენა მალსახმობი"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"მარჯვენა მალსახმობი"</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 08a498a..7b34273 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -161,6 +161,10 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Бет танылмады. Орнына саусақ ізін пайдаланыңыз."</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <!-- no translation found for keyguard_face_failed (9044619102286917151) -->
+ <skip />
+ <!-- no translation found for keyguard_suggest_fingerprint (8742015961962702960) -->
+ <skip />
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth қосылған."</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Батарея зарядының мөлшері белгісіз."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> қосылған."</string>
@@ -339,8 +343,7 @@
<string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Зарядталуда • Толуына <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> қалды."</string>
<string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Жылдам зарядталуда • Толуына <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> қалды."</string>
<string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Баяу зарядталуда • Толуына <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> қалды."</string>
- <!-- no translation found for keyguard_indication_charging_time_dock (3149328898931741271) -->
- <skip />
+ <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="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Пайдаланушыны ауыстыру"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"ашылмалы мәзір"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Осы сеанстағы барлық қолданбалар мен деректер жойылады."</string>
@@ -420,6 +423,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Субтитр қою"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"қосу"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"өшіру"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"Дыбыс және діріл"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Параметрлер"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"Қолданба бекітілді"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Өзіңіз босатқаша ашық тұрады. Босату үшін \"Артқа\" және \"Шолу\" түймелерін басып тұрыңыз."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Өзіңіз босатқаша ашық тұрады. Босату үшін \"Артқа\" және \"Негізгі бет\" түймелерін басып тұрыңыз"</string>
@@ -595,7 +600,8 @@
<string name="switch_bar_on" msgid="1770868129120096114">"Қосулы"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"Өшірулі"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"Қолжетімді емес"</string>
- <string name="tile_disabled" msgid="373212051546573069">"Өшірілген"</string>
+ <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+ <skip />
<string name="nav_bar" msgid="4642708685386136807">"Шарлау тақтасы"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"Формат"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"Қосымша сол жақ түйме түрі"</string>
@@ -668,8 +674,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"Телефон толық суығанға дейін, кейбір функциялардың жұмысы шектеледі.\nТолығырақ ақпарат үшін түртіңіз."</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Телефон автоматты түрде суи бастайды. Оны пайдалана бере аласыз, бірақ ол баяуырақ жұмыс істеуі мүмкін.\n\nТелефон суығаннан кейін, оның жұмысы қалпына келеді."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Пайдалану нұсқаулығын қараңыз"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"Зарядтағышты ажыратыңыз"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Құрылғыны зарядтау кезінде ақау шықты. Қуат адаптерін ажыратыңыз. Кабель ыстық болуы мүмкін, абай болыңыз."</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Пайдалану нұсқаулығын қараңыз"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Сол жақ таңбаша"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Оң жақ таңбаша"</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 4241f8b1..727207c 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"មិនអាចសម្គាល់មុខបានទេ។ សូមប្រើស្នាមម្រាមដៃជំនួសវិញ។"</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"មិនអាចសម្គាល់មុខបានទេ"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"ប្រើស្នាមម្រាមដៃជំនួសវិញ"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"បានតភ្ជាប់ប៊្លូធូស។"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"មិនដឹងអំពីភាគរយថ្មទេ។"</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"បានភ្ជាប់ទៅ <xliff:g id="BLUETOOTH">%s</xliff:g> ។"</string>
@@ -339,8 +341,7 @@
<string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • កំពុងសាកថ្ម • ពេញក្នុងរយៈពេល <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
<string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • កំពុងសាកថ្មយ៉ាងឆាប់រហ័ស • ពេញក្នុងរយៈពេល <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • កំពុងសាកថ្មយឺត • ពេញក្នុងរយៈពេល <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
- <!-- no translation found for keyguard_indication_charging_time_dock (3149328898931741271) -->
- <skip />
+ <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="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ប្ដូរអ្នកប្រើ"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"ម៉ឺនុយទាញចុះ"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"កម្មវិធី និងទិន្នន័យទាំងអស់ក្នុងវគ្គនេះនឹងត្រូវលុប។"</string>
@@ -420,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"ការដាក់ត្រួតគ្នាលើអក្សររត់"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"បើក"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"បិទ"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"សំឡេង និងការញ័រ"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"ការកំណត់"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"កម្មវិធីត្រូវបានខ្ទាស់"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"វានឹងនៅតែបង្ហាញ រហូតទាល់តែអ្នកដកការដៅ។ សូមសង្កត់ប៊ូតុងថយក្រោយ និងប៊ូតុងទិដ្ឋភាពរួមឲ្យជាប់ ដើម្បីដកការដៅ។"</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"វានឹងនៅតែបង្ហាញ រហូតទាល់តែអ្នកដកការដៅ។ សូមចុចប៊ូតុងថយក្រោយ និងប៊ូតុងទំព័រដើមឱ្យជាប់ ដើម្បីដកការដៅ។"</string>
@@ -595,7 +598,8 @@
<string name="switch_bar_on" msgid="1770868129120096114">"បើក"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"បិទ"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"មិនអាចប្រើបាន"</string>
- <string name="tile_disabled" msgid="373212051546573069">"បានបិទ"</string>
+ <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+ <skip />
<string name="nav_bar" msgid="4642708685386136807">"របាររុករក"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"ប្លង់"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"ប្រភេទប៊ូតុងខាងឆ្វេងបន្ថែម"</string>
@@ -668,8 +672,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"មុខងារមួយចំនួននឹងមិនអាចប្រើបានពេញលេញនោះទេ ខណៈពេលដែលទូរសព្ទកំពុងបញ្ចុះកម្ដៅ។\nសូមចុចដើម្បីទទួលបានព័ត៌មានបន្ថែម"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"ទូរសព្ទរបស់អ្នកនឹងព្យាយាមបញ្ចុះកម្តៅដោយស្វ័យប្រវត្តិ។ អ្នកនៅតែអាចប្រើទូរសព្ទរបស់អ្នកបានដដែល ប៉ុន្តែវានឹងដំណើរការយឺតជាងមុន។\n\nបន្ទាប់ពីទូរសព្ទរបស់អ្នកត្រជាក់ជាងមុនហើយ វានឹងដំណើរការដូចធម្មតា។"</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"មើលជំហានថែទាំ"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"ផ្ដាច់ឆ្នាំងសាក"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"មានបញ្ហាក្នុងការសាកថ្មឧបករណ៍នេះ។ សូមផ្ដាច់ឆ្នាំងសាក ហើយប្រុងប្រយ័ត្ន ដោយសារខ្សែអាចមានកម្ដៅក្ដៅ។"</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"មើលជំហានថែទាំ"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"ផ្លូវកាត់ខាងឆ្វេង"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"ផ្លូវកាត់ខាងស្តាំ"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 55435fc..4f9a7c2 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"ಮುಖ ಗುರುತಿಸಲಾಗುತ್ತಿಲ್ಲ ಬದಲಿಗೆ ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಬಳಸಿ."</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"ಮುಖ ಗುರುತಿಸಲಾಗುತ್ತಿಲ್ಲ"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"ಬದಲಿಗೆ ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಬಳಸಿ"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"ಬ್ಲೂಟೂತ್ ಸಂಪರ್ಕಗೊಂಡಿದೆ."</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"ಬ್ಯಾಟರಿ ಶೇಕಡಾವಾರು ತಿಳಿದಿಲ್ಲ."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> ಗೆ ಸಂಪರ್ಕಪಡಿಸಲಾಗಿದೆ."</string>
@@ -419,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"ಶೀರ್ಷಿಕೆಗಳ ಓವರ್ಲೇ"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"ಧ್ವನಿ & ವೈಬ್ರೇಷನ್"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"ಸೆಟ್ಟಿಂಗ್ಗಳು"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"ಆ್ಯಪ್ ಅನ್ನು ಪಿನ್ ಮಾಡಲಾಗಿದೆ"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"ನೀವು ಅನ್ಪಿನ್ ಮಾಡುವವರೆಗೆ ಅದನ್ನು ವೀಕ್ಷಣೆಯಲ್ಲಿಡುತ್ತದೆ. ಸ್ಪರ್ಶಿಸಿ ಮತ್ತು ಹಿಡಿದುಕೊಳ್ಳಿ ಹಾಗೂ ಅನ್ಪಿನ್ ಮಾಡಲು ಅವಲೋಕಿಸಿ."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"ನೀವು ಅನ್ಪಿನ್ ಮಾಡುವವರೆಗೆ ಅದನ್ನು ವೀಕ್ಷಣೆಯಲ್ಲಿಡುತ್ತದೆ. ಸ್ಪರ್ಶಿಸಿ ಮತ್ತು ಹಿಡಿದುಕೊಳ್ಳಿ ಹಾಗೂ ಅನ್ಪಿನ್ ಮಾಡಲು ಮುಖಪುಟಕ್ಕೆ ಹಿಂತಿರುಗಿ."</string>
@@ -594,7 +598,8 @@
<string name="switch_bar_on" msgid="1770868129120096114">"ಆನ್"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"ಆಫ್"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"ಲಭ್ಯವಿಲ್ಲ"</string>
- <string name="tile_disabled" msgid="373212051546573069">"ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string>
+ <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+ <skip />
<string name="nav_bar" msgid="4642708685386136807">"ನ್ಯಾವಿಗೇಷನ್ ಬಾರ್"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"ಲೇಔಟ್"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"ಹೆಚ್ಚುವರಿ ಎಡ ಬಟನ್ ವಿಧ"</string>
@@ -667,8 +672,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"ಫೋನ್ ತಣ್ಣಗಾಗುವವರೆಗೂ ಕೆಲವು ವೈಶಿಷ್ಟ್ಯಗಳನ್ನು ಸೀಮಿತಗೊಳಿಸಲಾಗುತ್ತದೆ\nಇನ್ನಷ್ಟು ಮಾಹಿತಿಗಾಗಿ ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"ನಿಮ್ಮ ಫೋನ್ ಸ್ವಯಂಚಾಲಿತವಾಗಿ ತಣ್ಣಗಾಗಲು ಪ್ರಯತ್ನಿಸುತ್ತದೆ. ನಿಮ್ಮ ಫೋನ್ ಅನ್ನು ನೀವು ಈಗಲೂ ಬಳಸಬಹುದಾಗಿರುತ್ತದೆ, ಆದರೆ ಇದು ನಿಧಾನವಾಗಿರಬಹುದು.\n\nಒಮ್ಮೆ ನಿಮ್ಮ ಫೋನ್ ತಣ್ಣಗಾದ ನಂತರ ಇದು ಸಾಮಾನ್ಯ ರೀತಿಯಲ್ಲಿ ಕಾರ್ಯನಿರ್ವಹಿಸುತ್ತದೆ."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"ಕಾಳಜಿಯ ಹಂತಗಳನ್ನು ವೀಕ್ಷಿಸಿ"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"ಚಾರ್ಜರ್ ಅನ್ಪ್ಲಗ್ ಮಾಡಿ"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"ಈ ಸಾಧನವನ್ನು ಚಾರ್ಜ್ ಮಾಡುತ್ತಿರುವಾಗ ಸಮಸ್ಯೆ ಎದುರಾಗಿದೆ. ಪವರ್ ಅಡಾಪ್ಟರ್ ಅನ್ನು ಅನ್ಪ್ಲಗ್ ಮಾಡಿ ಮತ್ತು ಕೇಬಲ್ ಬೆಚ್ಚಗಿರಬೇಕೆಂದು ಜಾಗ್ರತೆ ವಹಿಸಿ."</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"ಕಾಳಜಿ ಹಂತಗಳನ್ನು ನೋಡಿ"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"ಎಡ ಶಾರ್ಟ್ಕಟ್"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"ಬಲ ಶಾರ್ಟ್ಕಟ್"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index ebdf775..e8578df 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"얼굴을 인식할 수 없습니다. 대신 지문을 사용하세요."</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"얼굴을 인식할 수 없습니다."</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"대신 지문을 사용하세요."</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"블루투스가 연결되었습니다."</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"배터리 잔량을 알 수 없습니다."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g>에 연결되었습니다."</string>
@@ -281,7 +283,7 @@
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"시작"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"중지"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"한 손 사용 모드"</string>
- <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"기기 마이크를 차단 해제하시겠습니까?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"기기 마이크를 &#173;차단 해제하시겠습니까?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"기기 카메라를 차단 해제하시겠습니까?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"기기 카메라 및 마이크를 차단 해제하시겠습니까?"</string>
<string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"마이크를 사용할 수 있는 모든 앱 및 서비스에 대해 액세스가 차단 해제됩니다."</string>
@@ -339,8 +341,7 @@
<string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • 충전 중 • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> 후 충전 완료"</string>
<string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • 고속 충전 중 • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> 후 충전 완료"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • 저속 충전 중 • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> 후 충전 완료"</string>
- <!-- no translation found for keyguard_indication_charging_time_dock (3149328898931741271) -->
- <skip />
+ <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="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"사용자 전환"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"풀다운 메뉴"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"이 세션에 있는 모든 앱과 데이터가 삭제됩니다."</string>
@@ -420,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"캡션 오버레이"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"사용"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"사용 중지"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"소리 및 진동"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"설정"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"앱 고정됨"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"고정 해제할 때까지 계속 표시됩니다. 고정 해제하려면 뒤로 및 최근 사용을 길게 터치하세요."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"고정 해제할 때까지 계속 표시됩니다. 고정 해제하려면 뒤로 및 홈을 길게 터치하세요."</string>
@@ -595,7 +598,8 @@
<string name="switch_bar_on" msgid="1770868129120096114">"사용"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"사용 안함"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"사용할 수 없음"</string>
- <string name="tile_disabled" msgid="373212051546573069">"사용 안함"</string>
+ <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+ <skip />
<string name="nav_bar" msgid="4642708685386136807">"탐색 메뉴"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"레이아웃"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"추가 왼쪽 버튼 유형"</string>
@@ -668,8 +672,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"휴대전화 온도를 낮추는 동안 일부 기능이 제한됩니다.\n자세히 알아보려면 탭하세요."</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"휴대전화 온도를 자동으로 낮추려고 시도합니다. 휴대전화를 계속 사용할 수는 있지만 작동이 느려질 수도 있습니다.\n\n휴대전화 온도가 낮아지면 정상적으로 작동됩니다."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"해결 방법 확인하기"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"충전기를 연결 해제하세요"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"기기를 충전하는 중에 문제가 발생했습니다. 케이블이 뜨거울 수 있으므로 주의하여 전원 어댑터를 분리하세요."</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"취해야 할 조치 확인"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"왼쪽 바로가기"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"오른쪽 바로가기"</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index 23062bf..13229f8 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Жүз таанылбай жатат. Манжа изин колдонуңуз."</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"Жүз таанылбай жатат"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Манжа изин колдонуңуз"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth байланышта"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Батарея кубатынын деңгээли белгисиз."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> менен туташкан."</string>
@@ -419,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Коштомо жазуулардын үстүнө коюу"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"иштетүү"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"өчүрүү"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"Үн жана дирилдөө"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Параметрлер"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"Колдонмо кадалды"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Ал бошотулмайынча көрүнө берет. Бошотуу үчүн \"Артка\" жана \"Назар\" баскычтарын басып, кармап туруңуз."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Ал бошотулмайынча көрүнө берет. Бошотуу үчүн, \"Артка\" жана \"Башкы бет\" баскычтарын басып, кармап туруңуз."</string>
@@ -594,7 +598,8 @@
<string name="switch_bar_on" msgid="1770868129120096114">"Күйүк"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"Өчүк"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"Жеткиликсиз"</string>
- <string name="tile_disabled" msgid="373212051546573069">"Өчүрүлгөн"</string>
+ <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+ <skip />
<string name="nav_bar" msgid="4642708685386136807">"Чабыттоо тилкеси"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"Калып"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"Сол жактагы кошумча баскычтын түрү"</string>
@@ -667,8 +672,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"Телефон сууганча айрым элементтердин иши чектелген.\nКеңири маалымат алуу үчүн таптап коюңуз"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Телефонуңуз автоматтык түрдө сууйт. Аны колдоно берсеңиз болот, бирок ал жайыраак иштеп калат.\n\nТелефонуңуз суугандан кийин адаттагыдай эле иштеп баштайт."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Тейлөө кадамдарын көрүңүз"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"Кубаттагычты сууруңуз"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Бул түзмөктү кубаттоодо маселе келип чыкты. Кабель ысып кетиши мүмкүн, андыктан кубаттагыч адаптерин сууруп коюңуз."</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Тейлөө кадамдарын көрүңүз"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Сол жактагы кыска жол"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Оң жактагы кыска жол"</string>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 7d8ddfd..6deda73 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"ບໍ່ສາມາດຈຳແນກໜ້າໄດ້. ກະລຸນາໃຊ້ລາຍນິ້ວມືແທນ."</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"ບໍ່ສາມາດຈຳແນກໃບໜ້າໄດ້"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"ກະລຸນາໃຊ້ລາຍນິ້ວມືແທນ"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"ເຊື່ອມຕໍ່ Bluetooth ແລ້ວ."</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"ບໍ່ຮູ້ເປີເຊັນແບັດເຕີຣີ."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"ເຊື່ອມຕໍ່ຫາ <xliff:g id="BLUETOOTH">%s</xliff:g> ແລ້ວ."</string>
@@ -339,8 +341,7 @@
<string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ກຳລັງສາກໄຟ • ຈະເຕັມໃນອີກ <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
<string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ກຳລັງສາກໄຟແບບໄວ • ຈະເຕັມໃນອີກ <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ກຳລັງສາກໄຟແບບຊ້າ • ຈະເຕັມໃນອີກ <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
- <!-- no translation found for keyguard_indication_charging_time_dock (3149328898931741271) -->
- <skip />
+ <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="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ສະຫຼັບຜູ້ໃຊ້"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"ເມນູແບບດຶງລົງ"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ແອັບຯແລະຂໍ້ມູນທັງໝົດໃນເຊດຊັນນີ້ຈະຖືກລຶບອອກ."</string>
@@ -420,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"ຄຳບັນຍາຍແບບວາງທັບ"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"ເປີດນຳໃຊ້"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"ປິດນຳໃຊ້"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"ສຽງ ແລະ ການສັ່ນເຕືອນ"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"ການຕັ້ງຄ່າ"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"ແອັບຖືກປັກໝຸດແລ້ວ"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"ນີ້ຈະສະແດງມັນໃນໜ້າຈໍຈົນກວ່າທ່ານຈະເຊົາປັກມຸດ. ໃຫ້ແຕະປຸ່ມກັບຄືນ ແລະ ປຸ່ມພາບຮວມຄ້າງໄວ້ເພື່ອຍົກເລີກການປັກມຸດ."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"ນີ້ຈະສະແດງມັນໃນໜ້າຈໍຈົນກວ່າທ່ານຈະເຊົາປັກໝຸດ. ໃຫ້ແຕະປຸ່ມກັບຄືນ ແລະ ປຸ່ມພາບຮວມຄ້າງໄວ້ເພື່ອຍົກເລີກການປັກໝຸດ."</string>
@@ -595,7 +598,8 @@
<string name="switch_bar_on" msgid="1770868129120096114">"ເປີດ"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"ປິດ"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"ບໍ່ສາມາດໃຊ້ໄດ້"</string>
- <string name="tile_disabled" msgid="373212051546573069">"ປິດການນຳໃຊ້ແລ້ວ"</string>
+ <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+ <skip />
<string name="nav_bar" msgid="4642708685386136807">"ແຖບນຳທາງ"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"ຮູບແບບ"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"ປະເພດປຸ່ມຊ້າຍພິເສດ"</string>
@@ -668,8 +672,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"ຄຸນສົມບັດບາງຢ່າງຖືກຈຳກັດໄວ້ໃນເວລາຫຼຸດອຸນຫະພູມຂອງໂທລະສັບ.\nແຕະເພື່ອເບິ່ງຂໍ້ມູນເພີ່ມເຕີມ"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"ໂທລະສັບຂອງທ່ານຈະພະຍາຍາມລົດອຸນຫະພູມລົງ. ທ່ານຍັງຄົງສາມາດໃຊ້ໂທລະສັບຂອງທ່ານໄດ້ຢູ່, ແຕ່ມັນຈະເຮັດວຽກຊ້າລົງ.\n\nເມື່ອໂທລະສັບຂອງທ່ານບໍ່ຮ້ອນຫຼາຍແລ້ວ, ມັນຈະກັບມາເຮັດວຽກຕາມປົກກະຕິ."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"ເບິ່ງຂັ້ນຕອນການເບິ່ງແຍງ"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"ຖອດສາຍສາກອອກ"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"ເກີດບັນຫາໃນການສາກໄຟອຸປະກອນນີ້. ກະລຸນາຖອດສາຍສາກອອກ ແລະ ລະວັງເນື່ອງຈາກສາຍອາດຈະຍັງອຸ່ນຢູ່."</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"ເບິ່ງຂັ້ນຕອນການເບິ່ງແຍງ"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"ປຸ່ມລັດຊ້າຍ"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"ປຸ່ມລັດຂວາ"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 6f18f90..b7fe724a 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Veidas neatpažintas. Naudokite kontrolinį kodą."</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"Veidas neatpažintas"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Naudoti piršto antspaudą"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"„Bluetooth“ prijungtas."</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Akumuliatoriaus energija procentais nežinoma."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Prisijungta prie „<xliff:g id="BLUETOOTH">%s</xliff:g>“."</string>
@@ -419,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Subtitrų perdanga"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"įgalinti"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"išjungti"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"Garsas ir vibravimas"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Nustatymai"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"Programa prisegta"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Tai bus rodoma, kol atsegsite. Palieskite ir palaikykite „Atgal“ ir „Apžvalga“, kad atsegtumėte."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Tai bus rodoma, kol atsegsite. Palieskite ir palaikykite „Atgal“ ir „Pagrindinis ekranas“, kad atsegtumėte."</string>
@@ -594,7 +598,8 @@
<string name="switch_bar_on" msgid="1770868129120096114">"Įjungta"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"Išjungta"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"Nepasiekiama"</string>
- <string name="tile_disabled" msgid="373212051546573069">"Išjungta"</string>
+ <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+ <skip />
<string name="nav_bar" msgid="4642708685386136807">"Naršymo juosta"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"Išdėstymas"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"Papildomo mygtuko kairėje tipas"</string>
@@ -667,8 +672,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"Kai kurios funkcijos gali neveikti, kol telefonas vėsta.\nPalietę gausite daugiau informacijos"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Telefonas automatiškai bandys atvėsti. Telefoną vis tiek galėsite naudoti, tačiau jis gali veikti lėčiau.\n\nKai telefonas atvės, jis veiks įprastai."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Žr. priežiūros veiksmus"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"Atjunkite kroviklį"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Įkraunant šį įrenginį iškilo problema. Atjunkite maitinimo adapterį. Būkite atsargūs, nes laidas gali būti įkaitęs."</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Žr. priežiūros veiksmus"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Spartusis klavišas kairėje"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Spartusis klavišas dešinėje"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 7e70908..01b8905 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Nevar atpazīt seju. Lietojiet pirksta nospiedumu."</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"Nevar atpazīt seju"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Lietot pirksta nospiedumu"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth savienojums ir izveidots."</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Akumulatora uzlādes līmenis procentos nav zināms."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Ir izveidots savienojum ar <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -339,8 +341,7 @@
<string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<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="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Ātrā uzlāde • Laiks līdz pilnai uzlādei: <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Lēnā uzlāde • Laiks līdz pilnai uzlādei: <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
- <!-- no translation found for keyguard_indication_charging_time_dock (3149328898931741271) -->
- <skip />
+ <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="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Mainīt lietotāju"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"novelkamā izvēlne"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Tiks dzēstas visas šīs sesijas lietotnes un dati."</string>
@@ -420,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Subtitri pārklājas"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"iespējot"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"atspējot"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"Skaņa un vibrācija"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Iestatījumi"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"Lietotne ir piesprausta"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Šādi tas būs redzams līdz brīdim, kad to atspraudīsiet. Lai atspraustu, pieskarieties pogām Atpakaļ un Pārskats un turiet tās."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Šādi tas būs redzams līdz brīdim, kad to atspraudīsiet. Lai atspraustu, pieskarieties pogām “Atpakaļ” un “Sākums” un turiet tās."</string>
@@ -595,7 +598,8 @@
<string name="switch_bar_on" msgid="1770868129120096114">"Ieslēgts"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"Izslēgts"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"Nav pieejams"</string>
- <string name="tile_disabled" msgid="373212051546573069">"Atspējots"</string>
+ <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+ <skip />
<string name="nav_bar" msgid="4642708685386136807">"Navigācijas josla"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"Izkārtojums"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"Kreisās puses papildu pogas veids"</string>
@@ -668,8 +672,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"Dažas funkcijas ir ierobežotas, kamēr notiek tālruņa atdzišana.\nPieskarieties, lai uzzinātu vairāk."</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Jūsu tālrunis automātiski mēģinās atdzist. Jūs joprojām varat izmantot tālruni, taču tas, iespējams, darbosies lēnāk.\n\nTiklīdz tālrunis būs atdzisis, tas darbosies normāli."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Skatīt apkopes norādījumus"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"Lādētāja atvienošana"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Uzlādējot šo ierīci, radās problēma. Atvienojiet strāvas adapteri. Esiet uzmanīgs — vads var būt uzsilis."</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Skatīt apkopes norādījumus"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Saīsne kreisajā pusē"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Saīsne labajā pusē"</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index f5b45f0..0c16e90 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Не се препознава ликот. Користете отпечаток."</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"Не се препознава ликот"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Користи отпечаток"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth е поврзан."</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Процентот на батеријата е непознат."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Поврзано со <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -339,8 +341,7 @@
<string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Се полни • Полна по <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
<string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Се полни брзо • Полна по <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Се полни бавно • Полна по <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
- <!-- no translation found for keyguard_indication_charging_time_dock (3149328898931741271) -->
- <skip />
+ <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="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Промени го корисникот"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"паѓачко мени"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Сите апликации и податоци во сесијата ќе се избришат."</string>
@@ -420,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Преклопување титли"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"овозможи"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"оневозможи"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"Звук и вибрации"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Поставки"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"Апликацијата е закачена"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Ќе се гледа сѐ додека не го откачите. Допрете и држете „Назад“ и „Краток преглед“ за откачување."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Ќе се гледа сѐ додека не го откачите. Допрете и задржете „Назад“ и „Почетен екран“ за откачување."</string>
@@ -595,7 +598,7 @@
<string name="switch_bar_on" msgid="1770868129120096114">"Вклучено"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"Исклучено"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"Недостапно"</string>
- <string name="tile_disabled" msgid="373212051546573069">"Оневозможено"</string>
+ <string name="accessibility_tile_disabled_by_policy_action_description" msgid="6958422730461646926">"дознајте повеќе"</string>
<string name="nav_bar" msgid="4642708685386136807">"Лента за навигација"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"Распоред"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"Тип дополнително лево копче"</string>
@@ -668,8 +671,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"Некои функции се ограничени додека телефонот се лади.\nДопрете за повеќе информации"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Телефонот автоматски ќе се обиде да се олади. Вие сепак ќе може да го користите, но тој може да работи побавно.\n\nОткако ќе се олади, ќе работи нормално."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Прикажи ги чекорите за грижа за уредот"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"Исклучете го полначот"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Има проблем со полнењето на уредов. Исклучете го адаптерот за напојување и внимавајте зошто кабелот може да е топол."</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Прикажи ги чекорите за грижа за уредот"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Лева кратенка"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Десна кратенка"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 6f18659..deae99f 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"മുഖം തിരിച്ചറിയാനായില്ല. പകരം ഫിംഗർപ്രിന്റ് ഉപയോഗിക്കൂ."</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"മുഖം തിരിച്ചറിയാനാകുന്നില്ല"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"പകരം ഫിംഗർപ്രിന്റ് ഉപയോഗിക്കൂ"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"ബ്ലൂടൂത്ത് കണക്റ്റുചെയ്തു."</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"ബാറ്ററി ശതമാനം അജ്ഞാതമാണ്."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> എന്നതിലേക്ക് കണക്റ്റുചെയ്തു."</string>
@@ -419,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"അടിക്കുറിപ്പുകൾ മുകളിൽ വയ്ക്കുക"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"പ്രവർത്തനക്ഷമമാക്കുക"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"പ്രവർത്തനരഹിതമാക്കുക"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"ശബ്ദവും വൈബ്രേഷനും"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"ക്രമീകരണം"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"ആപ്പ് പിൻ ചെയ്തു"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"നിങ്ങൾ അൺപിൻ ചെയ്യുന്നതുവരെ ഇത് കാണുന്ന വിധത്തിൽ നിലനിർത്തും. അൺപിൻ ചെയ്യാൻ \'തിരികെ\', \'ചുരുക്കവിവരണം\' എന്നിവ സ്പർശിച്ച് പിടിക്കുക."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"നിങ്ങൾ അൺപിൻ ചെയ്യുന്നതുവരെ ഇത് കാണുന്ന വിധത്തിൽ നിലനിർത്തും. അൺപിൻ ചെയ്യാൻ \'തിരികെ പോവുക\', \'ഹോം\' ബട്ടണുകൾ സ്പർശിച്ച് പിടിക്കുക."</string>
@@ -594,7 +598,8 @@
<string name="switch_bar_on" msgid="1770868129120096114">"ഓൺ"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"ഓഫ്"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"ലഭ്യമല്ല"</string>
- <string name="tile_disabled" msgid="373212051546573069">"പ്രവർത്തനരഹിതമാക്കി"</string>
+ <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+ <skip />
<string name="nav_bar" msgid="4642708685386136807">"നാവിഗേഷൻ ബാർ"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"ലേഔട്ട്"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"അധിക ഇടത് ബട്ടൺ തരം"</string>
@@ -667,8 +672,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"ഫോൺ തണുത്തുകൊണ്ടിരിക്കുമ്പോൾ ചില ഫീച്ചറുകൾ പരിമിതപ്പെടുത്തപ്പെടും.\nകൂടുതൽ വിവരങ്ങൾക്ക് ടാപ്പ് ചെയ്യുക"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"നിങ്ങളുടെ ഫോൺ സ്വയമേവ തണുക്കാൻ ശ്രമിക്കും. നിങ്ങൾക്ക് അപ്പോഴും ഫോൺ ഉപയോഗിക്കാമെങ്കിലും പ്രവർത്തനം മന്ദഗതിയിലായിരിക്കും.\n\nതണുത്തുകഴിഞ്ഞാൽ, ഫോൺ സാധാരണ ഗതിയിൽ പ്രവർത്തിക്കും."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"പരിപാലന നിർദ്ദേശങ്ങൾ കാണുക"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"ചാർജർ അൺപ്ലഗ് ചെയ്യുക"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"ഈ ഉപകരണം ചാർജ് ചെയ്യുന്നതിൽ തടസ്സമുണ്ട്. പവർ അഡാപ്റ്റർ അൺപ്ലഗ് ചെയ്യുക, കേബിളിന് ചൂടുണ്ടായിരിക്കുമെന്നതിനാൽ ശ്രദ്ധിക്കണം."</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"മുൻകരുതൽ നടപടികൾ കാണുക"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"ഇടത് കുറുക്കുവഴി"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"വലത് കുറുക്കുവഴി"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 4d12bb7..565c5e9 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Царай таних боломжгүй. Оронд нь хурууны хээ ашигла"</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"Царайг танихгүй байна"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Оронд нь хурууны хээ ашиглах"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth холбогдсон."</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Батарейн хувь тодорхойгүй байна."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g>-тай холбогдсон."</string>
@@ -419,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Давхарласан хадмал"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"идэвхжүүлэх"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"идэвхгүй болгох"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"Дуу, чичиргээ"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Тохиргоо"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"Аппыг бэхэлсэн"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Таныг тогтоосныг болиулах хүртэл үүнийг харуулна. Тогтоосныг болиулахын тулд Буцах, Тоймыг дараад хүлээнэ үү."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Таныг тогтоосныг болиулах хүртэл үүнийг харуулсан хэвээр байна. Тогтоосныг болиулахын тулд Буцах, Нүүр хуудас товчлуурыг дараад хүлээнэ үү."</string>
@@ -594,7 +598,7 @@
<string name="switch_bar_on" msgid="1770868129120096114">"Идэвхтэй"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"Идэвхгүй"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"Боломжгүй"</string>
- <string name="tile_disabled" msgid="373212051546573069">"Идэвхгүй болгосон"</string>
+ <string name="accessibility_tile_disabled_by_policy_action_description" msgid="6958422730461646926">"нэмэлт мэдээлэл авах"</string>
<string name="nav_bar" msgid="4642708685386136807">"Навигацын самбар"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"Бүдүүвч"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"Нэмэлт зүүн товчлуураар шивэх"</string>
@@ -667,8 +671,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"Утсыг хөрөх үед зарим онцлогийг хязгаарлана.\nДэлгэрэнгүй мэдээлэл авах бол товшино уу"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Таны утас автоматаар хөрөх болно. Та утсаа ашиглаж болох хэдий ч удаан ажиллаж болзошгүй.\n\nТаны утас хөрсний дараагаар хэвийн ажиллана."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Хянамж болгоомжийн алхмыг харах"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"Цэнэглэгчийг салгана уу"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Энэ төхөөрөмжийг цэнэглэхэд асуудал гарлаа. Тэжээлийн залгуурыг салгана уу. Кабель халсан байж болзошгүй тул болгоомжтой байгаарай."</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Хянамж болгоомжийн алхмыг харна уу"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Зүүн товчлол"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Баруун товчлол"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 3a7c740..e31aa19 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"चेहरा ओळखू शकत नाही. त्याऐवजी फिंगरप्रिंट वापरा."</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"चेहरा ओळखू शकत नाही"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"त्याऐवजी फिंगरप्रिंट वापरा"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"ब्लूटूथ कनेक्ट केले."</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"बॅटरीच्या चार्जिंगची टक्केवारी माहित नाही."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> शी कनेक्ट केले."</string>
@@ -419,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"कॅप्शन ओव्हरले करा"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"सुरू करा"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"बंद करा"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"आवाज आणि व्हायब्रेशन"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"सेटिंग्ज"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"ॲप पिन केले आहे"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"तुम्ही अनपिन करेर्यंत हे यास दृश्यामध्ये ठेवते. अनपिन करण्यासाठी परत आणि विहंगावलोकनास स्पर्श करा आणि धरून ठेवा."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"तुम्ही अनपिन करेर्यंत हे त्याला दृश्यामध्ये ठेवते. अनपिन करण्यासाठी मागे आणि होम वर स्पर्श करा आणि धरून ठेवा."</string>
@@ -594,7 +598,8 @@
<string name="switch_bar_on" msgid="1770868129120096114">"सुरू"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"बंद"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"उपलब्ध नाही"</string>
- <string name="tile_disabled" msgid="373212051546573069">"बंद केली"</string>
+ <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+ <skip />
<string name="nav_bar" msgid="4642708685386136807">"नॅव्हिगेशन बार"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"लेआउट"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"अतिरिक्त डाव्या बटणाचा प्रकार"</string>
@@ -667,8 +672,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"फोन थंड होईपर्यंत काही वैशिष्ट्ये मर्यादित केली.\nअधिक माहितीसाठी टॅप करा"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"तुमचा फोन स्वयंचलितपणे थंड होईल. तुम्ही अद्यापही तुमचा फोन वापरू शकता परंतु तो कदाचित धीमेपणे कार्य करेल.\n\nतुमचा फोन एकदा थंड झाला की, तो सामान्यपणे कार्य करेल."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"काय काळजी घ्यावी ते पहा"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"चार्जर अनप्लग करा"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"हे डिव्हाइस चार्ज करताना समस्या आहे. पॉवर अडॅप्टर अनप्लग करा आणि शक्य तेवढी काळजी घ्या कदाचित केबल गरम असू शकते."</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"काय काळजी घ्यावी ते पहा"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"डावा शॉर्टकट"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"उजवा शॉर्टकट"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 9554fbe..42e7e8a19 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Tidak mengenali wajah. Gunakan cap jari."</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"Tak dapat mengecam wajah"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Gunakan cap jari"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth disambungkan."</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Peratusan kuasa bateri tidak diketahui."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Disambungkan kepada <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -339,8 +341,7 @@
<string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<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="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Mengecas dengan cepat • Penuh dalam masa <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Mengecas dengan perlahan • Penuh dalam masa <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
- <!-- no translation found for keyguard_indication_charging_time_dock (3149328898931741271) -->
- <skip />
+ <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="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Tukar pengguna"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menu tarik turun"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Semua apl dan data dalam sesi ini akan dipadam."</string>
@@ -420,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Tindanan kapsyen"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"dayakan"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"lumpuhkan"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"Bunyi & getaran"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Tetapan"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"Apl telah disemat"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Tindakan ini memastikan skrin kelihatan sehingga anda menyahsemat. Sentuh & tahan Kembali dan Ikhtisar untuk menyahsemat."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Tindakan ini memastikan skrin kelihatan sehingga anda menyahsemat. Sentuh & tahan Kembali dan Skrin Utama untuk menyahsemat."</string>
@@ -595,7 +598,8 @@
<string name="switch_bar_on" msgid="1770868129120096114">"Hidup"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"Mati"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"Tidak tersedia"</string>
- <string name="tile_disabled" msgid="373212051546573069">"Dilumpuhkan"</string>
+ <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+ <skip />
<string name="nav_bar" msgid="4642708685386136807">"Bar navigasi"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"Reka letak"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"Jenis butang kiri tambahan"</string>
@@ -668,8 +672,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"Sesetengah ciri adalah terhad semasa telefon menyejuk.\nKetik untuk mendapatkan maklumat lanjut"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Telefon anda akan cuba menyejuk secara automatik. Anda masih dapat menggunakan telefon itu tetapi telefon tersebut mungkin berjalan lebih perlahan.\n\nSetelah telefon anda sejuk, telefon itu akan berjalan seperti biasa."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Lihat langkah penjagaan"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"Cabut palam pengejas"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Terdapat isu semasa mengecas peranti ini. Cabut palam penyesuai kuasa. Berhati-hati kerana kabel mungkin hangat."</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Lihat langkah penjagaan"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Pintasan kiri"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Pintasan kanan"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 4170404..00727d6 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"မျက်နှာကို မမှတ်မိပါ။ လက်ဗွေကို အစားထိုးသုံးပါ။"</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"မျက်နှာကို မမှတ်မိပါ"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"လက်ဗွေကို အစားထိုးသုံးပါ"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"ဘလူးတုသ်ချိတ်ဆက်ထားမှု"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"ဘက်ထရီရာခိုင်နှုန်းကို မသိပါ။"</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g>သို့ ချိတ်ဆက်ထား"</string>
@@ -419,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"စာတန်းများ ထပ်ပိုးရန်"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"ဖွင့်ရန်"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"ပိတ်ရန်"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"အသံနှင့် တုန်ခါမှု"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"ဆက်တင်များ"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"အက်ပ်ကို ပင်ထိုးထားသည်"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"သင်ပင်မဖြုတ်မခြင်း ၎င်းကို ပြသထားပါမည်။ ပင်ဖြုတ်ရန် Back နှင့် Overview ကို ထိ၍ဖိထားပါ။"</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"သင်က ပင်မဖြုတ်မခြင်း ၎င်းကို ပြသထားပါမည်။ ပင်ဖြုတ်ရန် \'နောက်သို့\' နှင့် \'ပင်မ\' ခလုတ်တို့ကို တို့၍ဖိထားပါ။"</string>
@@ -569,7 +573,7 @@
<string name="notif_inline_reply_remove_attachment_description" msgid="7954075334095405429">"ပူးတွဲပါဖိုင်ကို ဖယ်ရှားရန်"</string>
<string name="keyboard_shortcut_group_system" msgid="1583416273777875970">"စနစ်"</string>
<string name="keyboard_shortcut_group_system_home" msgid="7465138628692109907">"ပင်မ"</string>
- <string name="keyboard_shortcut_group_system_recents" msgid="8628108256824616927">"လတ်တလော"</string>
+ <string name="keyboard_shortcut_group_system_recents" msgid="8628108256824616927">"မကြာသေးမီက"</string>
<string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"နောက်သို့"</string>
<string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"အကြောင်းကြားချက်များ"</string>
<string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"ကီးဘုတ် ဖြတ်လမ်းများ"</string>
@@ -594,7 +598,8 @@
<string name="switch_bar_on" msgid="1770868129120096114">"ဖွင့်"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"ပိတ်"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"မရနိုင်ပါ"</string>
- <string name="tile_disabled" msgid="373212051546573069">"ပိတ်ထားသည်"</string>
+ <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+ <skip />
<string name="nav_bar" msgid="4642708685386136807">"ရွှေ့လျားရန်ဘားတန်း"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"အပြင်အဆင်"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"လက်ဝဲခလုတ် အမျိုးအစားအပို"</string>
@@ -667,8 +672,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"ဖုန်းကို အေးအောင်ပြုလုပ်နေစဉ်တွင် အချို့ဝန်ဆောင်မှုများကို ကန့်သတ်ထားပါသည်။\nနောက်ထပ်အချက်အလက်များအတွက် တို့ပါ"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"သင့်ဖုန်းသည် အလိုအလျောက် ပြန်အေးသွားပါလိမ့်မည်။ ဖုန်းကို အသုံးပြုနိုင်ပါသေးသည် သို့သော် ပိုနှေးနိုင်ပါသည်။\n\nသင့်ဖုန်း အေးသွားသည်နှင့် ပုံမှန်အတိုင်း ပြန်အလုပ်လုပ်ပါလိမ့်မည်။"</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"ဂရုပြုစရာ အဆင့်များ ကြည့်ရန်"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"အားသွင်းကိရိယာ ပလပ်ဖြုတ်ပါ"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"ဤစက်ပစ္စည်းကို အားသွင်းရာတွင် ပြဿနာရှိနေသည်။ ပါဝါ ကြားခံကိရိယာကို ပလပ်ဖြုတ်ပါ။ ကေဘယ်ကြိုး ပူနွေးနေနိုင်သဖြင့် သတိထားပါ။"</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"ဂရုပြုစရာ အဆင့်များ ကြည့်ရန်"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"လက်ဝဲ ဖြတ်လမ်းလင့်ခ်"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"လက်ယာ ဖြတ်လမ်းလင့်ခ်"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 2fb7c6f..c41f2f6 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Ansiktet gjenkjennes ikke. Bruk fingeravtrykk."</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"Ansiktet gjenkjennes ikke"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Bruk fingeravtrykk"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth er tilkoblet."</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Batteriprosenten er ukjent."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Koblet til <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -419,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Overlegg med teksting"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"aktivér"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"deaktiver"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"Lyd og vibrering"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Innstillinger"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"Appen er festet"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Gjør at den vises til du løsner den. Trykk og hold inne Tilbake og Oversikt for å løsne den."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Gjør at den vises til du løsner den. Trykk og hold inne Tilbake og Startside for å løsne den."</string>
@@ -594,7 +598,8 @@
<string name="switch_bar_on" msgid="1770868129120096114">"På"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"Av"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"Utilgjengelig"</string>
- <string name="tile_disabled" msgid="373212051546573069">"Slått av"</string>
+ <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+ <skip />
<string name="nav_bar" msgid="4642708685386136807">"Navigasjonsrad"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"Oppsett"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"Ekstra venstre-knapptype"</string>
@@ -667,8 +672,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"Enkelte funksjoner er begrenset mens telefonen kjøles ned.\nTrykk for å se mer informasjon"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Telefonen din kommer til å prøve å kjøle seg ned automatisk. Du kan fremdeles bruke telefonen, men den kjører muligens saktere.\n\nTelefonen kommer til å kjøre som normalt, når den har kjølt seg ned."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Se vedlikeholdstrinnene"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"Koble fra laderen"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Det oppsto et problem med lading av enheten. Koble fra strømadapteren, og vær forsiktig, kabelen kan være varm."</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Se vedlikeholdstrinnene"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Venstre hurtigtast"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Høyre hurtigtast"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 03a18f8..36bcaf7 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"अनुहार पहिचान गर्न सकिएन। बरु फिंगरप्रिन्ट प्रयोग गर्नुहोस्।"</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"अनुहार पहिचान गर्न सकिएन"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"बरु फिंगरप्रिन्ट प्रयोग गर्नुहोस्"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"ब्लुटुथ जडान भयो।"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"ब्याट्रीमा कति प्रतिशत चार्ज छ भन्ने कुराको जानाकरी छैन।"</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> मा जडित।"</string>
@@ -419,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"क्याप्सनको ओभरले"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"सक्षम पार्नुहोस्"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"असक्षम पार्नुहोस्"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"साउन्ड तथा भाइब्रेसन"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"सेटिङ"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"एप पिन गरिएको छ"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"तपाईंले अनपिन नगरेसम्म यसले त्यसलाई दृश्यमा कायम राख्छ। अनपिन गर्न पछाडि र परिदृश्य बटनलाई टच एण्ड होल्ड गर्नुहोस्।"</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"तपाईंले अनपिन नगरेसम्म यसले त्यसलाई दृश्यमा कायम राख्छ। अनपिन गर्न पछाडि र गृह नामक बटनहरूलाई टच एण्ड होल्ड गर्नुहोस्।"</string>
@@ -594,7 +598,8 @@
<string name="switch_bar_on" msgid="1770868129120096114">"अन छ"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"अफ छ"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"उपलब्ध छैन"</string>
- <string name="tile_disabled" msgid="373212051546573069">"अफ गरियो"</string>
+ <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+ <skip />
<string name="nav_bar" msgid="4642708685386136807">"नेभिगेशन पट्टी"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"लेआउट"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"अतिरिक्त बायाँतिरको बटनको प्रकार"</string>
@@ -667,8 +672,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"फोन नचिस्सिँदासम्म केही सुविधाहरू उपलब्ध हुने छैनन्।\nथप जानकारीका लागि ट्याप गर्नुहोस्"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"तपाईंको फोन स्वतः चिसो हुने प्रयास गर्ने छ। तपाईं अझै पनि आफ्नो फोनको प्रयोग गर्न सक्नुहुन्छ तर त्यो अझ ढिलो चल्न सक्छ।\n\nचिसो भएपछि तपाईंको फोन सामान्य गतिमा चल्नेछ।"</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"डिभाइसको हेरचाह गर्ने तरिका हेर्नुहोस्"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"चार्जर अनप्लग गर्नुहोस्"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"यो डिभाइस चार्ज गर्दा कुनै समस्या भयो। पावर एडाप्टर अनप्लग गर्नुहोस् र केबल तातो हुन सक्ने भएकाले ध्यान दिनुहोस्।"</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"हेरचाहसम्बन्धी चरणहरू हेर्नुहोस्"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"बायाँतिरको सर्टकट"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"दायाँतिरको सर्टकट"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index c1fca3e..da55ac3 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Gezicht niet herkend. Gebruik je vingerafdruk."</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"Gezicht niet herkend"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Vingerafdruk gebruiken"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth-verbinding ingesteld."</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Batterijpercentage onbekend."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Verbonden met <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -419,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Ondertitelingsoverlay"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"aanzetten"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"uitzetten"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"Geluid en trillen"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Instellingen"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"App is vastgezet"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Het scherm blijft zichtbaar totdat je het losmaakt. Tik op Terug en Overzicht en houd deze vast om het scherm los te maken."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Het scherm blijft zichtbaar totdat je het losmaakt. Tik op Terug en Home en houd deze vast om het scherm los te maken."</string>
@@ -594,7 +598,7 @@
<string name="switch_bar_on" msgid="1770868129120096114">"Aan"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"Uit"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"Niet beschikbaar"</string>
- <string name="tile_disabled" msgid="373212051546573069">"Uitgezet"</string>
+ <string name="accessibility_tile_disabled_by_policy_action_description" msgid="6958422730461646926">"meer informatie"</string>
<string name="nav_bar" msgid="4642708685386136807">"Navigatiebalk"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"Lay-out"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"Extra knoptype links"</string>
@@ -667,8 +671,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"Bepaalde functies zijn beperkt terwijl de telefoon afkoelt.\nTik voor meer informatie"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Je telefoon probeert automatisch af te koelen. Je kunt je telefoon nog steeds gebruiken, maar deze kan langzamer werken.\n\nZodra de telefoon is afgekoeld, werkt deze weer normaal."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Onderhoudsstappen bekijken"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"Oplader loskoppelen"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Er is een probleem met het opladen van dit apparaat. Koppel de voedingsadapter los. Wees voorzichtig, want de kabel kan warm zijn."</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Onderhoudsstappen bekijken"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Snelkoppeling links"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Snelkoppeling rechts"</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index ab15dbe..5b7ad0e 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"ଫେସ୍ ଚିହ୍ନଟ କରିହେବ ନାହିଁ। ଟିପଚିହ୍ନ ବ୍ୟବହାର କରନ୍ତୁ।"</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"ଫେସ ଚିହ୍ନଟ ହୋଇପାରିବ ନାହିଁ"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"ଟିପଚିହ୍ନ ବ୍ୟବହାର କରନ୍ତୁ"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"ବ୍ଲୁଟୂଥ୍ ସଂଯୋଗ କରାଯାଇଛି।"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"ବ୍ୟାଟେରୀ ଶତକଡ଼ା ଅଜଣା ଅଟେ।"</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> ସହ ସଂଯୁକ୍ତ"</string>
@@ -419,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"କ୍ୟାପ୍ସନ୍ର ଓଭର୍ଲେ"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"ସକ୍ଷମ କରନ୍ତୁ"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"ଅକ୍ଷମ କରନ୍ତୁ"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"ସାଉଣ୍ଡ ଓ ଭାଇବ୍ରେସନ"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"ସେଟିଂସ"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"ଆପକୁ ପିନ୍ କରାଯାଇଛି"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"ଆପଣ ଅନପିନ୍ ନକରିବା ପର୍ଯ୍ୟନ୍ତ ଏହା ଦେଖାଉଥିବ। ଅନପିନ୍ କରିବାକୁ ସ୍ପର୍ଶ କରି ଧରିରଖନ୍ତୁ ଓ ଦେଖନ୍ତୁ।"</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"ଆପଣ ଅନପିନ୍ ନକରିବା ପର୍ଯ୍ୟନ୍ତ ଏହା ଦେଖାଉଥିବ। ଅନପିନ୍ କରିବା ପାଇଁ ହୋମ ଓ ବ୍ୟାକ ବଟନକୁ ଦବାଇ ଧରନ୍ତୁ।"</string>
@@ -594,7 +598,8 @@
<string name="switch_bar_on" msgid="1770868129120096114">"ଚାଲୁ ଅଛି"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"ବନ୍ଦ ଅଛି"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"ଅନୁପଲବ୍ଧ"</string>
- <string name="tile_disabled" msgid="373212051546573069">"ଅକ୍ଷମ କରାଯାଇଛି"</string>
+ <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+ <skip />
<string name="nav_bar" msgid="4642708685386136807">"ନାଭିଗେଶନ୍ ବାର୍"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"ଲେଆଉଟ୍"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"ସମ୍ପୂର୍ଣ୍ଣ ବାମ ବଟନ୍ ପ୍ରକାର"</string>
@@ -667,8 +672,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"ଫୋନ୍ ଥଣ୍ଡା ହେବା ସମୟରେ କିଛି ଫିଚର୍ ଠିକ ଭାବେ କାମ କରିନଥାଏ।\nଅଧିକ ସୂଚନା ପାଇଁ ଟାପ୍ କରନ୍ତୁ"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"ଆପଣଙ୍କ ଫୋନ୍ ସ୍ୱଚାଳିତ ଭାବେ ଥଣ୍ଡା ହେବାକୁ ଚେଷ୍ଟା କରିବ। ଆପଣ ତଥାପି ନିଜ ଫୋନ୍ ବ୍ୟବହାର କରିପାରିବେ, କିନ୍ତୁ ଏହା ଧୀରେ ଚାଲିପାରେ।\n\nଆପଣଙ୍କ ଫୋନ୍ ଥଣ୍ଡା ହୋଇଯିବାପରେ, ଏହା ସାମାନ୍ୟ ଭାବେ ଚାଲିବ।"</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"ଯତ୍ନ ନେବା ପାଇଁ ଷ୍ଟେପଗୁଡ଼ିକ ଦେଖନ୍ତୁ"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"ଚାର୍ଜର୍ ଅନ୍ପ୍ଲଗ୍ କରନ୍ତୁ"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"ଏହି ଡିଭାଇସ୍ ଚାର୍ଜ କରିବାରେ ଗୋଟିଏ ସମସ୍ୟା ଅଛି। ଯେହେତୁ କେବଳ ଗରମ ହୋଇଯାଇପାରେ, ତେଣୁ ପାୱାର୍ ଆଡପ୍ଟର୍ ଅନ୍ପ୍ଲଗ୍ କରନ୍ତୁ ଏବଂ ଯତ୍ନ ନିଅନ୍ତୁ।"</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"ସେବା ସମ୍ବନ୍ଧିତ ଷ୍ଟେପ୍ଗୁଡ଼ିକ ଦେଖନ୍ତୁ"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"ବାମ ଶର୍ଟକଟ୍"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"ଡାହାଣ ଶର୍ଟକଟ୍"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index e0eaa29..93c6618 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"ਚਿਹਰਾ ਨਹੀਂ ਪਛਾਣ ਸਕਦੇ। ਇਸਦੀ ਬਜਾਏ ਫਿੰਗਰਪ੍ਰਿੰਟ ਵਰਤੋ।"</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"ਚਿਹਰੇ ਦੀ ਪਛਾਣ ਨਹੀਂ ਹੋਈ"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"ਇਸਦੀ ਬਜਾਏ ਫਿੰਗਰਪ੍ਰਿੰਟ ਵਰਤੋ"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth ਕਨੈਕਟ ਕੀਤੀ।"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"ਬੈਟਰੀ ਪ੍ਰਤੀਸ਼ਤ ਅਗਿਆਤ ਹੈ।"</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਕੀਤਾ।"</string>
@@ -339,8 +341,7 @@
<string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ਚਾਰਜ ਹੋ ਰਿਹਾ ਹੈ • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> ਵਿੱਚ ਪੂਰਾ ਚਾਰਜ ਹੋਵੇਗਾ"</string>
<string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ਤੇਜ਼ ਚਾਰਜ ਹੋ ਰਿਹਾ ਹੈ • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> ਵਿੱਚ ਪੂਰਾ ਚਾਰਜ ਹੋਵੇਗਾ"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ਹੌਲੀ ਚਾਰਜ ਹੋ ਰਿਹਾ ਹੈ • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> ਵਿੱਚ ਪੂਰਾ ਚਾਰਜ ਹੋਵੇਗਾ"</string>
- <!-- no translation found for keyguard_indication_charging_time_dock (3149328898931741271) -->
- <skip />
+ <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="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ਵਰਤੋਂਕਾਰ ਸਵਿੱਚ ਕਰੋ"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"ਪੁੱਲਡਾਊਨ ਮੀਨੂ"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ਇਸ ਸੈਸ਼ਨ ਵਿਚਲੀਆਂ ਸਾਰੀਆਂ ਐਪਾਂ ਅਤੇ ਡਾਟਾ ਨੂੰ ਮਿਟਾ ਦਿੱਤਾ ਜਾਏਗਾ।"</string>
@@ -420,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"ਸੁਰਖੀਆਂ ਓਵਰਲੇ"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"ਚਾਲੂ ਕਰੋ"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"ਬੰਦ ਕਰੋ"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"ਧੁਨੀ ਅਤੇ ਥਰਥਰਾਹਟ"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"ਸੈਟਿੰਗਾਂ"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"ਐਪ ਨੂੰ ਪਿੰਨ ਕੀਤਾ ਗਿਆ ਹੈ"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"ਇਹ ਇਸ ਨੂੰ ਤਦ ਤੱਕ ਦ੍ਰਿਸ਼ ਵਿੱਚ ਰੱਖਦਾ ਹੈ ਜਦ ਤੱਕ ਤੁਸੀਂ ਅਨਪਿੰਨ ਨਹੀਂ ਕਰਦੇ। ਅਨਪਿੰਨ ਕਰਨ ਲਈ \'ਪਿੱਛੇ\' ਅਤੇ \'ਰੂਪ-ਰੇਖਾ\' ਨੂੰ ਸਪੱਰਸ਼ ਕਰੋ ਅਤੇ ਦਬਾ ਕੇ ਰੱਖੋ।"</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"ਤੁਹਾਡੇ ਵੱਲੋਂ ਅਨਪਿੰਨ ਕੀਤੇ ਜਾਣ ਤੱਕ ਇਸਨੂੰ ਦਿਖਾਇਆ ਜਾਂਦਾ ਹੈ। ਅਨਪਿੰਨ ਕਰਨ ਲਈ \'ਪਿੱਛੇ\' ਅਤੇ \'ਹੋਮ\' ਨੂੰ ਸਪਰਸ਼ ਕਰਕੇ ਰੱਖੋ।"</string>
@@ -595,7 +598,8 @@
<string name="switch_bar_on" msgid="1770868129120096114">"ਚਾਲੂ"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"ਬੰਦ"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"ਅਣਉਪਲਬਧ"</string>
- <string name="tile_disabled" msgid="373212051546573069">"ਬੰਦ ਹੈ"</string>
+ <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+ <skip />
<string name="nav_bar" msgid="4642708685386136807">"ਨੈਵੀਗੇਸ਼ਨ ਵਾਲੀ ਪੱਟੀ"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"ਖਾਕਾ"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"ਵਧੇਰੇ ਖੱਬੇ ਬਟਨ ਕਿਸਮ"</string>
@@ -668,8 +672,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"ਫ਼ੋਨ ਦੇ ਠੰਡਾ ਹੋਣ ਦੇ ਦੌਰਾਨ ਕੁਝ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਸੀਮਤ ਹੁੰਦੀਆਂ ਹਨ।\nਵਧੇਰੇ ਜਾਣਕਾਰੀ ਲਈ ਟੈਪ ਕਰੋ"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"ਤੁਹਾਡਾ ਫ਼ੋਨ ਸਵੈਚਲਿਤ ਰੂਪ ਵਿੱਚ ਠੰਡਾ ਹੋਣ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰੇਗਾ। ਤੁਸੀਂ ਹਾਲੇ ਵੀ ਆਪਣੇ ਫ਼ੋਨ ਨੂੰ ਵਰਤ ਸਕਦੇ ਹੋ, ਪਰੰਤੂ ਹੋ ਸਕਦਾ ਹੈ ਕਿ ਇਹ ਵਧੇਰੇ ਹੌਲੀ ਚੱਲੇ।\n\nਇੱਕ ਵਾਰ ਠੰਡਾ ਹੋਣ ਤੋਂ ਬਾਅਦ ਤੁਹਾਡਾ ਫ਼ੋਨ ਸਧਾਰਨ ਤੌਰ \'ਤੇ ਚੱਲੇਗਾ।"</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"ਦੇਖਭਾਲ ਦੇ ਪੜਾਅ ਦੇਖੋ"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"ਚਾਰਜਰ ਨੂੰ ਕੱਢੋ"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"ਇਸ ਡੀਵਾਈਸ ਨੂੰ ਚਾਰਜ ਕਰਨ ਵਿੱਚ ਕੋਈ ਸਮੱਸਿਆ ਆ ਗਈ ਹੈ। ਪਾਵਰ ਅਡਾਪਟਰ ਨੂੰ ਕੱਢੋ ਅਤੇ ਧਿਆਨ ਰੱਖੋ ਸ਼ਾਇਦ ਕੇਬਲ ਗਰਮ ਹੋਵੇ।"</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"ਦੇਖਭਾਲ ਦੇ ਪੜਾਅ ਦੇਖੋ"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"ਖੱਬਾ ਸ਼ਾਰਟਕੱਟ"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"ਸੱਜਾ ਸ਼ਾਰਟਕੱਟ"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 8d2f40d..91a4dea 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Nie rozpoznaję twarzy. Użyj odcisku palca."</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"Nie można rozpoznać twarzy"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Użyj odcisku palca"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth połączony."</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Poziom naładowania baterii jest nieznany."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Połączono z <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -339,11 +341,9 @@
<string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<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="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Szybkie ładowanie • Pełne naładowanie za <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Wolne ładowanie • Pełne naładowanie za <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
- <!-- no translation found for keyguard_indication_charging_time_dock (3149328898931741271) -->
- <skip />
+ <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="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Przełącz użytkownika"</string>
- <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
- <skip />
+ <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menu"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Wszystkie aplikacje i dane w tej sesji zostaną usunięte."</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Witaj ponownie, Gościu!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Chcesz kontynuować sesję?"</string>
@@ -421,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Nakładka z napisami"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"włącz"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"wyłącz"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"Dźwięk i wibracje"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Ustawienia"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"Aplikacja jest przypięta"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Ekran będzie widoczny, dopóki go nie odepniesz. Aby to zrobić, kliknij i przytrzymaj Wstecz oraz Przegląd."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Ekran będzie widoczny, dopóki go nie odepniesz. Aby to zrobić, naciśnij i przytrzymaj Wstecz oraz Ekran główny."</string>
@@ -596,7 +598,8 @@
<string name="switch_bar_on" msgid="1770868129120096114">"Włączono"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"Wyłączono"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"Niedostępne"</string>
- <string name="tile_disabled" msgid="373212051546573069">"Wyłączono"</string>
+ <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+ <skip />
<string name="nav_bar" msgid="4642708685386136807">"Pasek nawigacji"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"Układ"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"Typ dodatkowego lewego przycisku"</string>
@@ -669,8 +672,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"Podczas obniżania temperatury telefonu niektóre funkcje są ograniczone\nKliknij, by dowiedzieć się więcej"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Telefon automatycznie podejmie próbę obniżenia temperatury. Możesz go wciąż używać, ale telefon może działać wolniej.\n\nGdy temperatura się obniży, telefon będzie działał normalnie."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Zobacz instrukcję postępowania"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"Odłącz ładowarkę"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Podczas ładowania tego urządzenia wystąpił błąd. Odłącz zasilacz, zwracając uwagę na kabel, który może być gorący."</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Zobacz instrukcję postępowania"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Lewy skrót"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Prawy skrót"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index e97f31f..d6b7eeb 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -161,6 +161,8 @@
<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 keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"Rosto não reconhecido"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Use a impressão digital"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth conectado."</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Porcentagem da bateria desconhecida."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Conectado a <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -202,7 +204,7 @@
<string name="accessibility_sensors_off_active" msgid="2619725434618911551">"A opção \"Sensores desativados\" está ativa"</string>
<string name="accessibility_clear_all" msgid="970525598287244592">"Limpar todas as notificações."</string>
<string name="notification_group_overflow_indicator" msgid="7605120293801012648">"Mais <xliff:g id="NUMBER">%s</xliff:g>"</string>
- <string name="notification_group_overflow_description" msgid="7176322877233433278">"{count,plural, =1{Mais # notificação no grupo.}one{Mais # notificação no grupo.}other{Mais # notificações no grupo.}}"</string>
+ <string name="notification_group_overflow_description" msgid="7176322877233433278">"{count,plural, =1{Mais # notificação no grupo.}one{Mais # notificação no grupo.}many{Mais # de notificações no grupo.}other{Mais # notificações no grupo.}}"</string>
<string name="accessibility_rotation_lock_on_landscape" msgid="936972553861524360">"A tela está bloqueada na orientação paisagem."</string>
<string name="accessibility_rotation_lock_on_portrait" msgid="2356633398683813837">"A tela está bloqueada na orientação retrato."</string>
<string name="dessert_case" msgid="9104973640704357717">"Mostruário de sobremesas"</string>
@@ -250,7 +252,7 @@
<string name="quick_settings_hotspot_label" msgid="1199196300038363424">"Ponto de acesso"</string>
<string name="quick_settings_hotspot_secondary_label_transient" msgid="7585604088079160564">"Ativando…"</string>
<string name="quick_settings_hotspot_secondary_label_data_saver_enabled" msgid="1280433136266439372">"Economia de dados ativada"</string>
- <string name="quick_settings_hotspot_secondary_label_num_devices" msgid="7536823087501239457">"{count,plural, =1{# dispositivo}one{# dispositivo}other{# dispositivos}}"</string>
+ <string name="quick_settings_hotspot_secondary_label_num_devices" msgid="7536823087501239457">"{count,plural, =1{# dispositivo}one{# dispositivo}many{# de dispositivos}other{# dispositivos}}"</string>
<string name="quick_settings_flashlight_label" msgid="4904634272006284185">"Lanterna"</string>
<string name="quick_settings_flashlight_camera_in_use" msgid="4820591564526512571">"Câmera em uso"</string>
<string name="quick_settings_cellular_detail_title" msgid="792977203299358893">"Dados móveis"</string>
@@ -351,7 +353,7 @@
<string name="guest_notification_session_active" msgid="5567273684713471450">"Você está no modo visitante"</string>
<string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Ao adicionar um novo usuário, o dispositivo vai sair do modo visitante e excluir todos os apps e dados da Sessão de visitante atual."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"Limite de usuários atingido"</string>
- <string name="user_limit_reached_message" msgid="1070703858915935796">"{count,plural, =1{Você só pode criar 1 usuário.}one{Você pode adicionar até # usuário.}other{Você pode adicionar até # usuários.}}"</string>
+ <string name="user_limit_reached_message" msgid="1070703858915935796">"{count,plural, =1{Você só pode criar 1 usuário.}one{Você pode adicionar até # usuário.}many{Você pode adicionar até # de usuários.}other{Você pode adicionar até # usuários.}}"</string>
<string name="user_remove_user_title" msgid="9124124694835811874">"Remover usuário?"</string>
<string name="user_remove_user_message" msgid="6702834122128031833">"Todos os apps e dados deste usuário serão excluídos."</string>
<string name="user_remove_user_remove" msgid="8387386066949061256">"Remover"</string>
@@ -419,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Sobreposição de legendas"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"ativar"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"desativar"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"Som e vibração"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Configurações"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"O app está fixado"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Ela é mantida à vista até que seja liberada. Toque em Voltar e em Visão geral e mantenha essas opções pressionadas para liberar."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Ela é mantida à vista até que seja liberada. Toque em Voltar e em Início e mantenha essas opções pressionadas para liberar."</string>
@@ -537,8 +541,8 @@
<string name="notification_menu_snooze_action" msgid="5415729610393475019">"Lembrete"</string>
<string name="snooze_undo" msgid="2738844148845992103">"Desfazer"</string>
<string name="snoozed_for_time" msgid="7586689374860469469">"Adiada para <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
- <string name="snoozeHourOptions" msgid="2332819756222425558">"{count,plural, =1{# hora}=2{# horas}one{# hora}other{# horas}}"</string>
- <string name="snoozeMinuteOptions" msgid="2222082405822030979">"{count,plural, =1{# minuto}one{# minuto}other{# minuto}}"</string>
+ <string name="snoozeHourOptions" msgid="2332819756222425558">"{count,plural, =1{# hora}=2{# horas}one{# hora}many{# de horas}other{# horas}}"</string>
+ <string name="snoozeMinuteOptions" msgid="2222082405822030979">"{count,plural, =1{# minuto}one{# minuto}many{# de minutos}other{# minuto}}"</string>
<string name="battery_detail_switch_title" msgid="6940976502957380405">"Economia de bateria"</string>
<string name="keyboard_key_button_template" msgid="8005673627272051429">"Botão <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="3734400625170020657">"Home"</string>
@@ -594,7 +598,8 @@
<string name="switch_bar_on" msgid="1770868129120096114">"Ativado"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"Desativado"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"Indisponível"</string>
- <string name="tile_disabled" msgid="373212051546573069">"Desativado"</string>
+ <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+ <skip />
<string name="nav_bar" msgid="4642708685386136807">"Barra de navegação"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"Layout"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"Tipo de botão esquerdo extra"</string>
@@ -667,8 +672,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"Alguns recursos ficam limitados enquanto o smartphone é resfriado.\nToque para saber mais"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Seu smartphone tentará se resfriar automaticamente. Você ainda poderá usá-lo, mas talvez ele fique mais lento.\n\nQuando o smartphone estiver resfriado, ele voltará ao normal."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Ver etapas de cuidado"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"Desconecte o carregador"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Ocorreu um problema com o carregamento deste dispositivo. Desconecte o adaptador de energia com cuidado, já que o cabo pode estar quente."</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Ver etapas de cuidado"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Atalho à esquerda"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Atalho à direita"</string>
@@ -762,7 +769,7 @@
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"alternar"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Controles do dispositivo"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Escolha um app para adicionar controles"</string>
- <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# controle adicionado.}one{# controle adicionado.}other{# controles adicionados.}}"</string>
+ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# controle adicionado.}one{# controle adicionado.}many{# de controles adicionados.}other{# controles adicionados.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Removido"</string>
<string name="accessibility_control_favorite" msgid="8694362691985545985">"Adicionado como favorito"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"Adicionado como favorito (posição <xliff:g id="NUMBER">%d</xliff:g>)"</string>
@@ -919,7 +926,7 @@
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Adicionar bloco"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Não adicionar bloco"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Selecionar usuário"</string>
- <string name="fgs_manager_footer_label" msgid="8276763570622288231">"{count,plural, =1{# app está ativo}one{# apps está ativo}other{# apps estão ativos}}"</string>
+ <string name="fgs_manager_footer_label" msgid="8276763570622288231">"{count,plural, =1{# app está ativo}one{# apps está ativo}many{# de apps estão ativos}other{# apps estão ativos}}"</string>
<string name="fgs_dot_content_description" msgid="2865071539464777240">"Nova informação"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Apps ativos"</string>
<string name="fgs_manager_dialog_message" msgid="2670045017200730076">"Esses apps ficam ativos e em execução mesmo quando não estão em uso. Isso melhora a funcionalidade deles, mas também pode afetar a duração da bateria."</string>
@@ -949,7 +956,7 @@
<string name="dream_overlay_status_bar_camera_off" msgid="5273073778969890823">"A câmera está desativada"</string>
<string name="dream_overlay_status_bar_mic_off" msgid="8366534415013819396">"O microfone está desativado"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"A câmera e o microfone estão desativados"</string>
- <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notificação}one{# notificação}other{# notificações}}"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notificação}one{# notificação}many{# notificações}other{# notificações}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Transmitindo"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Interromper a transmissão do app <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index edab9f1..0718fef 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Impos. reconh. rosto. Utilize a impressão digital."</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"Imposs. reconhecer rosto"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Usar impressão digital"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth ligado."</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Percentagem da bateria desconhecida."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Ligado a <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -202,7 +204,7 @@
<string name="accessibility_sensors_off_active" msgid="2619725434618911551">"Sensores desativados ativo"</string>
<string name="accessibility_clear_all" msgid="970525598287244592">"Limpar todas as notificações."</string>
<string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
- <string name="notification_group_overflow_description" msgid="7176322877233433278">"{count,plural, =1{Mais # notificação no grupo.}other{Mais # notificações no grupo.}}"</string>
+ <string name="notification_group_overflow_description" msgid="7176322877233433278">"{count,plural, =1{Mais # notificação no grupo.}many{Mais # notificações no grupo.}other{Mais # notificações no grupo.}}"</string>
<string name="accessibility_rotation_lock_on_landscape" msgid="936972553861524360">"O ecrã está bloqueado na orientação horizontal."</string>
<string name="accessibility_rotation_lock_on_portrait" msgid="2356633398683813837">"O ecrã está bloqueado na orientação vertical."</string>
<string name="dessert_case" msgid="9104973640704357717">"Vitrina de sobremesas"</string>
@@ -250,7 +252,7 @@
<string name="quick_settings_hotspot_label" msgid="1199196300038363424">"Zona Wi-Fi"</string>
<string name="quick_settings_hotspot_secondary_label_transient" msgid="7585604088079160564">"A ativar..."</string>
<string name="quick_settings_hotspot_secondary_label_data_saver_enabled" msgid="1280433136266439372">"Poup. dados ativada"</string>
- <string name="quick_settings_hotspot_secondary_label_num_devices" msgid="7536823087501239457">"{count,plural, =1{# dispositivo}other{# dispositivos}}"</string>
+ <string name="quick_settings_hotspot_secondary_label_num_devices" msgid="7536823087501239457">"{count,plural, =1{# dispositivo}many{# dispositivos}other{# dispositivos}}"</string>
<string name="quick_settings_flashlight_label" msgid="4904634272006284185">"Lanterna"</string>
<string name="quick_settings_flashlight_camera_in_use" msgid="4820591564526512571">"Câmara em utilização"</string>
<string name="quick_settings_cellular_detail_title" msgid="792977203299358893">"Dados móveis"</string>
@@ -351,7 +353,7 @@
<string name="guest_notification_session_active" msgid="5567273684713471450">"Está no modo convidado"</string>
<string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Ao adicionar um novo utilizador, o modo convidado é fechado e todas as apps e dados da sessão de convidado atual são eliminados."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"Limite de utilizadores alcançado"</string>
- <string name="user_limit_reached_message" msgid="1070703858915935796">"{count,plural, =1{Só é possível criar um utilizador.}other{É possível adicionar até # utilizadores.}}"</string>
+ <string name="user_limit_reached_message" msgid="1070703858915935796">"{count,plural, =1{Só é possível criar um utilizador.}many{É possível adicionar até # utilizadores.}other{É possível adicionar até # utilizadores.}}"</string>
<string name="user_remove_user_title" msgid="9124124694835811874">"Remover o utilizador?"</string>
<string name="user_remove_user_message" msgid="6702834122128031833">"Serão eliminados todos os dados e todas as aplicações deste utilizador."</string>
<string name="user_remove_user_remove" msgid="8387386066949061256">"Remover"</string>
@@ -419,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Sobreposição de legendas"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"ativar"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"desativar"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"Som e vibração"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Definições"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"A app está fixada"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Esta opção mantém o item visível até o soltar. Toque sem soltar em Anterior e em Vista geral para soltar."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Esta opção mantém o item visível até o soltar. Toque sem soltar em Anterior e em Página inicial para soltar."</string>
@@ -537,8 +541,8 @@
<string name="notification_menu_snooze_action" msgid="5415729610393475019">"Lembrar-me"</string>
<string name="snooze_undo" msgid="2738844148845992103">"Anular"</string>
<string name="snoozed_for_time" msgid="7586689374860469469">"Suspensa por <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
- <string name="snoozeHourOptions" msgid="2332819756222425558">"{count,plural, =1{# hora}=2{# horas}other{# horas}}"</string>
- <string name="snoozeMinuteOptions" msgid="2222082405822030979">"{count,plural, =1{# minuto}other{# minutos}}"</string>
+ <string name="snoozeHourOptions" msgid="2332819756222425558">"{count,plural, =1{# hora}=2{# horas}many{# horas}other{# horas}}"</string>
+ <string name="snoozeMinuteOptions" msgid="2222082405822030979">"{count,plural, =1{# minuto}many{# minutos}other{# minutos}}"</string>
<string name="battery_detail_switch_title" msgid="6940976502957380405">"Poupança de bateria"</string>
<string name="keyboard_key_button_template" msgid="8005673627272051429">"Botão <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="3734400625170020657">"Início"</string>
@@ -594,7 +598,8 @@
<string name="switch_bar_on" msgid="1770868129120096114">"Ativado"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"Desativado"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"Indisponível"</string>
- <string name="tile_disabled" msgid="373212051546573069">"Desativado"</string>
+ <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+ <skip />
<string name="nav_bar" msgid="4642708685386136807">"Barra de navegação"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"Esquema"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"Tipo de botão esquerdo adicional"</string>
@@ -667,8 +672,8 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"Algumas funcionalidades são limitadas enquanto o telemóvel arrefece.\nToque para obter mais informações."</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"O telemóvel tenta arrefecer automaticamente. Pode continuar a utilizá-lo, mas este poderá funcionar mais lentamente.\n\nAssim que o telemóvel tiver arrefecido, funcionará normalmente."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Veja os passos de manutenção"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"Desligar o carregador"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Ocorreu um problema ao carregar este dispositivo. Desligue o transformador e tenha cuidado porque o cabo pode estar quente."</string>
+ <string name="high_temp_alarm_title" msgid="8654754369605452169">"Desligue o dispositivo"</string>
+ <string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"O dispositivo está a ficar quente perto da porta de carregamento. Se estiver ligado a um carregador ou um acessório USB, desligue-o e tenha cuidado, uma vez que o cabo também pode estar quente."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Ver os passos a ter em consideração"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Atalho esquerdo"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Atalho direito"</string>
@@ -762,7 +767,7 @@
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"ativar/desativar"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Controlos de dispositivos"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Escolha uma app para adicionar controlos"</string>
- <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# controlo adicionado.}other{# controlos adicionados.}}"</string>
+ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# controlo adicionado.}many{# controlos adicionados.}other{# controlos adicionados.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Removido"</string>
<string name="accessibility_control_favorite" msgid="8694362691985545985">"Adicionado aos favoritos"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"Adicionados aos favoritos, posição <xliff:g id="NUMBER">%d</xliff:g>"</string>
@@ -919,7 +924,7 @@
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Adicionar mosaico"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Não adicion. mosaico"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Selecione utilizador"</string>
- <string name="fgs_manager_footer_label" msgid="8276763570622288231">"{count,plural, =1{# app está ativa}other{# apps estão ativas}}"</string>
+ <string name="fgs_manager_footer_label" msgid="8276763570622288231">"{count,plural, =1{# app está ativa}many{# apps estão ativas}other{# apps estão ativas}}"</string>
<string name="fgs_dot_content_description" msgid="2865071539464777240">"Novas informações"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Apps ativas"</string>
<string name="fgs_manager_dialog_message" msgid="2670045017200730076">"Estas apps estão ativas e a funcionar, mesmo quando não as está a usar. Isto melhora a sua funcionalidade, mas também afeta a autonomia da bateria."</string>
@@ -949,7 +954,7 @@
<string name="dream_overlay_status_bar_camera_off" msgid="5273073778969890823">"A câmara está desativada"</string>
<string name="dream_overlay_status_bar_mic_off" msgid="8366534415013819396">"O microfone está desativado"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"A câmara e o microfone estão desativados"</string>
- <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notificação}other{# notificações}}"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notificação}many{# notificações}other{# notificações}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"A transmitir"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Interromper a transmissão da app <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index e97f31f..d6b7eeb 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -161,6 +161,8 @@
<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 keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"Rosto não reconhecido"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Use a impressão digital"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth conectado."</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Porcentagem da bateria desconhecida."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Conectado a <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -202,7 +204,7 @@
<string name="accessibility_sensors_off_active" msgid="2619725434618911551">"A opção \"Sensores desativados\" está ativa"</string>
<string name="accessibility_clear_all" msgid="970525598287244592">"Limpar todas as notificações."</string>
<string name="notification_group_overflow_indicator" msgid="7605120293801012648">"Mais <xliff:g id="NUMBER">%s</xliff:g>"</string>
- <string name="notification_group_overflow_description" msgid="7176322877233433278">"{count,plural, =1{Mais # notificação no grupo.}one{Mais # notificação no grupo.}other{Mais # notificações no grupo.}}"</string>
+ <string name="notification_group_overflow_description" msgid="7176322877233433278">"{count,plural, =1{Mais # notificação no grupo.}one{Mais # notificação no grupo.}many{Mais # de notificações no grupo.}other{Mais # notificações no grupo.}}"</string>
<string name="accessibility_rotation_lock_on_landscape" msgid="936972553861524360">"A tela está bloqueada na orientação paisagem."</string>
<string name="accessibility_rotation_lock_on_portrait" msgid="2356633398683813837">"A tela está bloqueada na orientação retrato."</string>
<string name="dessert_case" msgid="9104973640704357717">"Mostruário de sobremesas"</string>
@@ -250,7 +252,7 @@
<string name="quick_settings_hotspot_label" msgid="1199196300038363424">"Ponto de acesso"</string>
<string name="quick_settings_hotspot_secondary_label_transient" msgid="7585604088079160564">"Ativando…"</string>
<string name="quick_settings_hotspot_secondary_label_data_saver_enabled" msgid="1280433136266439372">"Economia de dados ativada"</string>
- <string name="quick_settings_hotspot_secondary_label_num_devices" msgid="7536823087501239457">"{count,plural, =1{# dispositivo}one{# dispositivo}other{# dispositivos}}"</string>
+ <string name="quick_settings_hotspot_secondary_label_num_devices" msgid="7536823087501239457">"{count,plural, =1{# dispositivo}one{# dispositivo}many{# de dispositivos}other{# dispositivos}}"</string>
<string name="quick_settings_flashlight_label" msgid="4904634272006284185">"Lanterna"</string>
<string name="quick_settings_flashlight_camera_in_use" msgid="4820591564526512571">"Câmera em uso"</string>
<string name="quick_settings_cellular_detail_title" msgid="792977203299358893">"Dados móveis"</string>
@@ -351,7 +353,7 @@
<string name="guest_notification_session_active" msgid="5567273684713471450">"Você está no modo visitante"</string>
<string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Ao adicionar um novo usuário, o dispositivo vai sair do modo visitante e excluir todos os apps e dados da Sessão de visitante atual."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"Limite de usuários atingido"</string>
- <string name="user_limit_reached_message" msgid="1070703858915935796">"{count,plural, =1{Você só pode criar 1 usuário.}one{Você pode adicionar até # usuário.}other{Você pode adicionar até # usuários.}}"</string>
+ <string name="user_limit_reached_message" msgid="1070703858915935796">"{count,plural, =1{Você só pode criar 1 usuário.}one{Você pode adicionar até # usuário.}many{Você pode adicionar até # de usuários.}other{Você pode adicionar até # usuários.}}"</string>
<string name="user_remove_user_title" msgid="9124124694835811874">"Remover usuário?"</string>
<string name="user_remove_user_message" msgid="6702834122128031833">"Todos os apps e dados deste usuário serão excluídos."</string>
<string name="user_remove_user_remove" msgid="8387386066949061256">"Remover"</string>
@@ -419,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Sobreposição de legendas"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"ativar"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"desativar"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"Som e vibração"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Configurações"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"O app está fixado"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Ela é mantida à vista até que seja liberada. Toque em Voltar e em Visão geral e mantenha essas opções pressionadas para liberar."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Ela é mantida à vista até que seja liberada. Toque em Voltar e em Início e mantenha essas opções pressionadas para liberar."</string>
@@ -537,8 +541,8 @@
<string name="notification_menu_snooze_action" msgid="5415729610393475019">"Lembrete"</string>
<string name="snooze_undo" msgid="2738844148845992103">"Desfazer"</string>
<string name="snoozed_for_time" msgid="7586689374860469469">"Adiada para <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
- <string name="snoozeHourOptions" msgid="2332819756222425558">"{count,plural, =1{# hora}=2{# horas}one{# hora}other{# horas}}"</string>
- <string name="snoozeMinuteOptions" msgid="2222082405822030979">"{count,plural, =1{# minuto}one{# minuto}other{# minuto}}"</string>
+ <string name="snoozeHourOptions" msgid="2332819756222425558">"{count,plural, =1{# hora}=2{# horas}one{# hora}many{# de horas}other{# horas}}"</string>
+ <string name="snoozeMinuteOptions" msgid="2222082405822030979">"{count,plural, =1{# minuto}one{# minuto}many{# de minutos}other{# minuto}}"</string>
<string name="battery_detail_switch_title" msgid="6940976502957380405">"Economia de bateria"</string>
<string name="keyboard_key_button_template" msgid="8005673627272051429">"Botão <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="3734400625170020657">"Home"</string>
@@ -594,7 +598,8 @@
<string name="switch_bar_on" msgid="1770868129120096114">"Ativado"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"Desativado"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"Indisponível"</string>
- <string name="tile_disabled" msgid="373212051546573069">"Desativado"</string>
+ <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+ <skip />
<string name="nav_bar" msgid="4642708685386136807">"Barra de navegação"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"Layout"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"Tipo de botão esquerdo extra"</string>
@@ -667,8 +672,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"Alguns recursos ficam limitados enquanto o smartphone é resfriado.\nToque para saber mais"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Seu smartphone tentará se resfriar automaticamente. Você ainda poderá usá-lo, mas talvez ele fique mais lento.\n\nQuando o smartphone estiver resfriado, ele voltará ao normal."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Ver etapas de cuidado"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"Desconecte o carregador"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Ocorreu um problema com o carregamento deste dispositivo. Desconecte o adaptador de energia com cuidado, já que o cabo pode estar quente."</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Ver etapas de cuidado"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Atalho à esquerda"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Atalho à direita"</string>
@@ -762,7 +769,7 @@
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"alternar"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Controles do dispositivo"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Escolha um app para adicionar controles"</string>
- <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# controle adicionado.}one{# controle adicionado.}other{# controles adicionados.}}"</string>
+ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# controle adicionado.}one{# controle adicionado.}many{# de controles adicionados.}other{# controles adicionados.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Removido"</string>
<string name="accessibility_control_favorite" msgid="8694362691985545985">"Adicionado como favorito"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"Adicionado como favorito (posição <xliff:g id="NUMBER">%d</xliff:g>)"</string>
@@ -919,7 +926,7 @@
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Adicionar bloco"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Não adicionar bloco"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Selecionar usuário"</string>
- <string name="fgs_manager_footer_label" msgid="8276763570622288231">"{count,plural, =1{# app está ativo}one{# apps está ativo}other{# apps estão ativos}}"</string>
+ <string name="fgs_manager_footer_label" msgid="8276763570622288231">"{count,plural, =1{# app está ativo}one{# apps está ativo}many{# de apps estão ativos}other{# apps estão ativos}}"</string>
<string name="fgs_dot_content_description" msgid="2865071539464777240">"Nova informação"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Apps ativos"</string>
<string name="fgs_manager_dialog_message" msgid="2670045017200730076">"Esses apps ficam ativos e em execução mesmo quando não estão em uso. Isso melhora a funcionalidade deles, mas também pode afetar a duração da bateria."</string>
@@ -949,7 +956,7 @@
<string name="dream_overlay_status_bar_camera_off" msgid="5273073778969890823">"A câmera está desativada"</string>
<string name="dream_overlay_status_bar_mic_off" msgid="8366534415013819396">"O microfone está desativado"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"A câmera e o microfone estão desativados"</string>
- <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notificação}one{# notificação}other{# notificações}}"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notificação}one{# notificação}many{# notificações}other{# notificações}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Transmitindo"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Interromper a transmissão do app <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 9cb9bb2..eb45a4c 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Chipul nu a fost recunoscut. Folosiți amprenta."</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"Chip nerecunoscut"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Folosește amprenta"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Conectat prin Bluetooth."</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Procentajul bateriei este necunoscut."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Conectat la <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -419,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Suprapunere pe subtitrări"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"activați"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"dezactivați"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"Sunete și vibrații"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Setări"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"Aplicația este fixată"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Astfel rămâne afișat până anulați fixarea. Atingeți lung opțiunile Înapoi și Recente pentru a anula fixarea."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Astfel rămâne afișat până anulați fixarea. Atingeți lung opțiunile Înapoi și Acasă pentru a anula fixarea."</string>
@@ -594,7 +598,8 @@
<string name="switch_bar_on" msgid="1770868129120096114">"Activat"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"Dezactivați"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"Indisponibil"</string>
- <string name="tile_disabled" msgid="373212051546573069">"Dezactivat"</string>
+ <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+ <skip />
<string name="nav_bar" msgid="4642708685386136807">"Bară de navigare"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"Aspect"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"Tip de buton din extrema stângă"</string>
@@ -667,8 +672,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"Anumite funcții sunt limitate în timp ce telefonul se răcește.\nAtingeți pentru mai multe informații"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Telefonul va încerca automat să se răcească. Puteți folosi telefonul în continuare, dar este posibil să funcționeze mai lent.\n\nDupă ce se răcește, telefonul va funcționa normal."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Vedeți pașii pentru îngrijire"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"Deconectați încărcătorul"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Există o problemă la încărcarea acestui dispozitiv. Deconectați adaptorul de curent și aveți grijă, deoarece cablul poate fi cald."</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Vedeți pașii pentru îngrijire"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Comanda rapidă din stânga"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Comanda rapidă din dreapta"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 70940d2..e3dc3c2 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Не удалось распознать лицо. Используйте отпечаток."</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"Лицо не распознано."</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Используйте отпечаток."</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth-соединение установлено."</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Уровень заряда батареи в процентах неизвестен."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g>: подключено."</string>
@@ -339,8 +341,7 @@
<string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Зарядка • Осталось <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
<string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Быстрая зарядка • Осталось <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Медленная зарядка • Осталось <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
- <!-- no translation found for keyguard_indication_charging_time_dock (3149328898931741271) -->
- <skip />
+ <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="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Сменить пользователя."</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"раскрывающееся меню"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Все приложения и данные этого профиля будут удалены."</string>
@@ -420,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Наложение субтитров"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"включить"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"отключить"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"Звук и вибрация"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Открыть настройки"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"Приложение закреплено"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Приложение останется активным, пока вы не отмените блокировку, нажав и удерживая кнопки \"Назад\" и \"Обзор\"."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Приложение останется активным, пока вы не отмените блокировку, нажав и удерживая кнопки \"Назад\" и \"Главный экран\"."</string>
@@ -595,7 +598,8 @@
<string name="switch_bar_on" msgid="1770868129120096114">"Вкл."</string>
<string name="switch_bar_off" msgid="5669805115416379556">"Откл."</string>
<string name="tile_unavailable" msgid="3095879009136616920">"Недоступно"</string>
- <string name="tile_disabled" msgid="373212051546573069">"Отключено"</string>
+ <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+ <skip />
<string name="nav_bar" msgid="4642708685386136807">"Панель навигации"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"Расположение кнопок"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"Дополнительный тип кнопки \"Влево\""</string>
@@ -668,8 +672,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"Пока телефон не остынет, некоторые функции могут быть недоступны.\nНажмите, чтобы получить дополнительную информацию"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Ваш телефон остынет автоматически.\n\nОбратите внимание, что до тех пор он может работать медленнее, чем обычно."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Подробнее о действиях при перегреве…"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"Отключите зарядное устройство"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Во время зарядки возникла проблема. Отключите адаптер питания. Будьте осторожны, кабель может быть горячим."</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Подробнее о действиях при перегреве…"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Ярлык слева"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Ярлык справа"</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index a726b00..d91d7f1 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"මුහුණ හැඳිනිය නොහැක. ඒ වෙනුවට ඇඟිලි සලකුණ භාවිත ක."</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"මුහුණ හඳුනා ගත නොහැක"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"ඒ වෙනුවට ඇඟිලි සලකුණ භාවිත කරන්න"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"බ්ලූටූත් සම්බන්ධිතයි."</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"බැටරි ප්රතිශතය නොදනී."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> වෙත සම්බන්ධ කරන ලදි."</string>
@@ -339,8 +341,7 @@
<string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ආරෝපණය වෙමින් • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>කින් සම්පූර්ණ වේ"</string>
<string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • වේගයෙන් ආරෝපණය වෙමින් • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>කින් සම්පූර්ණ වේ"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • සෙමින් ආරෝපණය වෙමින් • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>කින් සම්පූර්ණ වේ"</string>
- <!-- no translation found for keyguard_indication_charging_time_dock (3149328898931741271) -->
- <skip />
+ <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="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"පරිශීලක මාරුව"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"නිපතන මෙනුව"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"මෙම සැසියේ සියළුම යෙදුම් සහ දත්ත මකාවී."</string>
@@ -420,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"සිරස්තල උඩැතිරිය"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"සබල කරන්න"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"අබල කරන්න"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"ශබ්ද සහ කම්පනය"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"සැකසීම්"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"යෙදුම අමුණා ඇත"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"මෙය ඔබ ගලවන තෙක් එය දසුන තුළ තබයි. ගැලවීමට දළ විශ්ලේෂණය ස්පර්ශ කර ආපසු අල්ලාගෙන සිටින්න."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"මෙය ඔබ ගලවන තෙක් එය දසුන තුළ තබයි. ගැලවීමට මුල් පිටුව ස්පර්ශ කර අල්ලාගෙන සිටින්න."</string>
@@ -595,7 +598,8 @@
<string name="switch_bar_on" msgid="1770868129120096114">"ක්රියාත්මකයි"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"ක්රියාවිරහිතයි"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"ලබා ගත නොහැකිය"</string>
- <string name="tile_disabled" msgid="373212051546573069">"අබලයි"</string>
+ <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+ <skip />
<string name="nav_bar" msgid="4642708685386136807">"සංචලන තීරුව"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"පිරිසැලසුම"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"අමතර වම් බොත්තම් වර්ගය"</string>
@@ -668,8 +672,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"දුරකථනය සිසිල් වන අතරතුර සමහර විශේෂාංග සීමිත විය හැකිය.\nතව තතු සඳහා තට්ටු කරන්න"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"ඔබගේ දුරකථනය ස්වයංක්රියව සිසිල් වීමට උත්සාහ කරනු ඇත. ඔබට තවම ඔබේ දුරකථනය භාවිත කළ හැකිය, නමුත් එය සෙමින් ධාවනය විය හැකිය.\n\nඔබේ දුරකථනය සිසිල් වූ පසු, එය සාමාන්ය ලෙස ධාවනය වනු ඇත."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"රැකවරණ පියවර බලන්න"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"චාජරය පේනුවෙන් ඉවත් කරන්න"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"මෙම උපාංගය ආරෝපණ කිරීමේ ගැටලුවක් තිබේ බල ඇඩැප්ටරය ගලවා කේබලය උණුසුම් විය හැකි බැවින් පරෙස්සම් වන්න."</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"රැකවරණ පියවර බලන්න"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"වම් කෙටි මග"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"දකුණු කෙටි මග"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index e35968b..ffcf250 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Tvár sa nedá rozpoznať. Použite odtlačok prsta."</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"Tvár sa nedá rozpoznať"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Používať radšej odtlačok"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth pripojené."</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Percento batérie nie je známe."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Pripojené k zariadeniu <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -419,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Prekrytie titulkov"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"povoliť"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"zakázať"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"Zvuk a vibrácie"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Nastavenia"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"Aplikácia je pripnutá"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Obsah bude pripnutý v zobrazení, dokým ho neuvoľníte. Uvoľníte ho stlačením a podržaním tlačidiel Späť a Prehľad."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Obsah bude pripnutý v zobrazení, dokým ho neuvoľníte. Uvoľníte ho pridržaním tlačidiel Späť a Domov."</string>
@@ -594,7 +598,7 @@
<string name="switch_bar_on" msgid="1770868129120096114">"Zapnuté"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"Vypnuté"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"Nedostupné"</string>
- <string name="tile_disabled" msgid="373212051546573069">"Deaktivované"</string>
+ <string name="accessibility_tile_disabled_by_policy_action_description" msgid="6958422730461646926">"ďalšie informácie"</string>
<string name="nav_bar" msgid="4642708685386136807">"Navigačný panel"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"Rozloženie"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"Dodatočný typ ľavého tlačidla"</string>
@@ -667,8 +671,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"Niektoré funkcie budú obmedzené, dokým neklesne teplota telefónu.\nViac sa dozviete po klepnutí."</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Váš telefón sa automaticky pokúsi schladiť. Môžete ho naďalej používať, ale môže fungovať pomalšie.\n\nPo poklese teploty bude telefón fungovať ako normálne."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Zobraziť opatrenia"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"Odpojte nabíjačku"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Vyskytol sa problém s nabíjaním tohto zariadenia. Odpojte nabíjačku a postupujte opatrne, pretože kábel môže byť horúci."</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Zobraziť opatrenia"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Ľavá skratka"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Pravá skratka"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index ce67761..6bae40c 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Obraza ni mogoče prepoznati. Uporabite prstni odtis."</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"Obraz ni bil prepoznan."</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Uporabite prstni odtis."</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Povezava Bluetooth vzpostavljena."</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Neznan odstotek napolnjenosti baterije."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Povezava vzpostavljena z: <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -339,8 +341,7 @@
<string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Polnjenje • Napolnjeno čez <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
<string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Hitro polnjenje • Napolnjeno čez <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Počasno polnjenje • Napolnjeno čez <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
- <!-- no translation found for keyguard_indication_charging_time_dock (3149328898931741271) -->
- <skip />
+ <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="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Preklop med uporabniki"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"spustni meni"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Vse aplikacije in podatki v tej seji bodo izbrisani."</string>
@@ -420,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Prekrivni podnapisi"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"omogoči"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"onemogoči"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"Zvok in vibriranje"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Nastavitve"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"Aplikacija je pripeta"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"S tem ostane vidna, dokler je ne odpnete. Če jo želite odpeti, hkrati pridržite gumba za nazaj in pregled."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"S tem ostane vidna, dokler je ne odpnete. Če jo želite odpeti, hkrati pridržite gumba za nazaj in za začetni zaslon."</string>
@@ -595,7 +598,8 @@
<string name="switch_bar_on" msgid="1770868129120096114">"Vklopljeno"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"Izklopljeno"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"Ni na voljo"</string>
- <string name="tile_disabled" msgid="373212051546573069">"Onemogočeno"</string>
+ <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+ <skip />
<string name="nav_bar" msgid="4642708685386136807">"Vrstica za krmarjenje"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"Postavitev"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"Vrsta dodatnega levega gumba"</string>
@@ -668,8 +672,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"Nekatere funkcije bodo med ohlajanjem telefona omejene.\nDotaknite se za več informacij"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Telefon se bo samodejno poskusil ohladiti. Še naprej ga lahko uporabljate, vendar bo morda deloval počasneje.\n\nKo se telefon ohladi, bo zopet deloval kot običajno."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Oglejte si navodila za ukrepanje"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"Odklopite polnilnik"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Pri polnjenju te naprave je prišlo do težave. Previdno odklopite napajalnik, ker se je kabel morda segrel."</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Oglejte si navodila za ukrepanje"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Leva bližnjica"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Desna bližnjica"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index de8c603..de0cf9f 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -161,6 +161,8 @@
<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 keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"Fytyra nuk mund të njihet"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Përdor më mirë gjurmën e gishtit"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Pajisja është lidhur me \"bluetooth\"."</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Përqindja e baterisë e panjohur."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Lidhur me <xliff:g id="BLUETOOTH">%s</xliff:g>"</string>
@@ -339,8 +341,7 @@
<string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<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="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Po karikohet shpejt • Plot për <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Po karikohet ngadalë • Plot për <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
- <!-- no translation found for keyguard_indication_charging_time_dock (3149328898931741271) -->
- <skip />
+ <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="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Ndërro përdorues"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menyja me tërheqje poshtë"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Të gjitha aplikacionet dhe të dhënat në këtë sesion do të fshihen."</string>
@@ -420,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Mbivendosja e titrave"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"aktivizo"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"çaktivizo"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"Tingulli dhe dridhjet"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Cilësimet"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"Aplikacioni është i gozhduar"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Kjo e ruan në pamje deri sa ta heqësh nga gozhdimi. Prek dhe mbaj të shtypur \"Prapa\" dhe \"Përmbledhje\" për ta hequr nga gozhdimi."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Kjo e ruan në pamje deri sa ta heqësh nga gozhdimi. Prek dhe mbaj të shtypur \"Prapa\" dhe \"Kreu\" për ta hequr nga gozhdimi."</string>
@@ -595,7 +598,8 @@
<string name="switch_bar_on" msgid="1770868129120096114">"Aktiv"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"Joaktiv"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"Nuk ofrohet"</string>
- <string name="tile_disabled" msgid="373212051546573069">"Joaktiv"</string>
+ <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+ <skip />
<string name="nav_bar" msgid="4642708685386136807">"Shiriti i navigimit"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"Struktura"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"Lloji i butonit shtesë majtas"</string>
@@ -668,8 +672,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"Disa veçori janë të kufizuara kur telefoni është duke u ftohur.\nTrokit për më shumë informacione"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Telefoni yt do të përpiqet automatikisht që të ftohet. Mund ta përdorësh përsëri telefonin, por ai mund të punojë më ngadalë.\n\nPasi telefoni të jetë ftohur, ai do të punojë si normalisht."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Shiko hapat për kujdesin"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"Shkëput karikuesin"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Ka një problem me karikimin e kësaj pajisjeje. Hiqe spinën dhe trego kujdes pasi kablloja mund të jetë e ngrohtë."</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Shiko hapat për kujdesin"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Shkurtorja majtas"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Shkurtorja djathtas"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 1f00f1f..4e8d4ea 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Лице није препознато. Користите отисак прста."</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"Лице није препознато"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Користите отисак прста"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth је прикључен."</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Проценат напуњености батерије није познат."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Повезани сте са <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -419,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Преклапање титлова"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"омогућите"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"онемогућите"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"Звук и вибрирање"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Подешавања"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"Апликација је закачена"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"На овај начин се ово стално приказује док га не откачите. Додирните и задржите Назад и Преглед да бисте га откачили."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"На овај начин се ово стално приказује док га не откачите. Додирните и задржите Назад и Почетна да бисте га откачили."</string>
@@ -594,7 +598,8 @@
<string name="switch_bar_on" msgid="1770868129120096114">"Укључено"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"Искључено"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"Недоступно"</string>
- <string name="tile_disabled" msgid="373212051546573069">"Онемогућено"</string>
+ <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+ <skip />
<string name="nav_bar" msgid="4642708685386136807">"Трака за навигацију"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"Распоред"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"Додатни тип левог дугмета"</string>
@@ -667,8 +672,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"Неке функције су ограничене док се телефон не охлади.\nДодирните за више информација"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Телефон ће аутоматски покушати да се охлади. И даље ћете моћи да користите телефон, али ће спорије реаговати.\n\nКада се телефон охлади, нормално ће радити."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Погледајте упозорења"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"Искључите пуњач из струје"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Дошло је до проблема са пуњењем овог уређаја. Искључите адаптер из напајања и будите пажљиви јер кабл може да буде топао."</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Погледајте упозорења"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Лева пречица"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Десна пречица"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 02e8a3a..19edaee 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Ansiktet kändes inte igen. Använd fingeravtryck."</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"Ansiktet kändes inte igen"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Använd fingeravtryck"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth ansluten."</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Okänd batterinivå."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Ansluten till <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -339,8 +341,7 @@
<string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Laddas • Fulladdat om <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
<string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Laddas snabbt • Fulladdat om <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Laddas långsamt • Fulladdat om <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
- <!-- no translation found for keyguard_indication_charging_time_dock (3149328898931741271) -->
- <skip />
+ <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="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Byt användare"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"rullgardinsmeny"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alla appar och data i denna session kommer att raderas."</string>
@@ -420,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Överlagring av textning"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"aktivera"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"inaktivera"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"Ljud och vibration"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Inställningar"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"Appen har fästs"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Skärmen visas tills du lossar den. Tryck länge på Tillbaka och Översikt om du vill lossa skärmen."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Skärmen visas tills du lossar den. Tryck länge på Tillbaka och Startsida om du vill lossa skärmen."</string>
@@ -595,7 +598,8 @@
<string name="switch_bar_on" msgid="1770868129120096114">"På"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"Av"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"Inte tillgängligt"</string>
- <string name="tile_disabled" msgid="373212051546573069">"Inaktiverat"</string>
+ <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+ <skip />
<string name="nav_bar" msgid="4642708685386136807">"Navigeringsfält"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"Layout"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"Knapptyp för extra vänster"</string>
@@ -668,8 +672,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"Vissa funktioner är begränsade medan telefonen svalnar.\nTryck för mer information"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Mobilen försöker svalna automatiskt. Du kan fortfarande använda mobilen, men den kan vara långsammare än vanligt.\n\nMobilen fungerar som vanligt när den har svalnat."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Visa alla skötselråd"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"Koppla ur laddaren"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Det går inte att ladda denna enhet. Koppla ur nätadaptern, men var försiktig eftersom kabeln kan vara varm."</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Visa alla skötselråd"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Vänster genväg"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Höger genväg"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 4f3ed0b..7305d58 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Imeshindwa kutambua uso. Tumia alama ya kidole."</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"Imeshindwa kutambua uso"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Badala yake, tumia alama ya kidole"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth imeunganishwa."</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Asilimia ya betri haijulikani."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Imeunganishwa kwenye <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -339,8 +341,7 @@
<string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<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="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Inachaji kwa kasi • Itajaa baada ya <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Inachaji polepole • Itajaa baada ya <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
- <!-- no translation found for keyguard_indication_charging_time_dock (3149328898931741271) -->
- <skip />
+ <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="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Badili mtumiaji"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menyu ya kuvuta chini"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Data na programu zote katika kipindi hiki zitafutwa."</string>
@@ -420,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Kuwekelea manukuu"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"washa"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"zima"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"Sauti na mtetemo"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Mipangilio"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"Programu imebandikwa"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Hali hii huifanya ionekane hadi utakapoibandua. Gusa na ushikilie kipengele cha Nyuma na Muhtasari ili ubandue."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Hali hii huifanya ionekane hadi utakapoibandua. Gusa na ushikilie kitufe cha kurudisha Nyuma na cha Mwanzo kwa pamoja ili ubandue."</string>
@@ -595,7 +598,8 @@
<string name="switch_bar_on" msgid="1770868129120096114">"Imewashwa"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"Imezimwa"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"Hakipatikani"</string>
- <string name="tile_disabled" msgid="373212051546573069">"Imezimwa"</string>
+ <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+ <skip />
<string name="nav_bar" msgid="4642708685386136807">"Sehemu ya viungo muhimu"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"Mpangilio"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"Aina ya kitufe cha kushoto cha ziada"</string>
@@ -668,8 +672,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"Baadhi ya vipengele havitatumika kwenye simu wakati inapoa.\nGusa ili upate maelezo zaidi"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Simu yako itajaribu kupoa kiotomatiki. Bado unaweza kutumia simu yako, lakini huenda ikafanya kazi polepole. \n\nPindi simu yako itakapopoa, itaendelea kufanya kazi kama kawaida."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Angalia hatua za utunzaji"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"Chomoa chaja"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Kuna tatizo la kuchaji kifaa hiki. Chomoa adapta ya nishati na uwe mwangalifu, huenda kebo ni moto."</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Angalia hatua za ulinzi"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Njia ya mkato ya kushoto"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Njia ya mkato ya kulia"</string>
diff --git a/packages/SystemUI/res/values-sw600dp-land/dimens.xml b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
index d638c9d..f4d4824 100644
--- a/packages/SystemUI/res/values-sw600dp-land/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
@@ -49,54 +49,29 @@
<dimen name="status_view_margin_horizontal">8dp</dimen>
- <!-- Distance that the full shade transition takes in order to complete by tapping on a button
- like "expand". -->
+ <!-- Lockscreen shade transition values -->
<dimen name="lockscreen_shade_transition_by_tap_distance">200dp</dimen>
-
- <!-- Distance that the full shade transition takes in order to complete. -->
<dimen name="lockscreen_shade_full_transition_distance">200dp</dimen>
-
- <!-- Distance that the full shade transition takes in order for media to fully transition to
- the shade -->
- <dimen name="lockscreen_shade_media_transition_distance">200dp</dimen>
-
- <!-- Distance that the full shade transition takes in order for scrim to fully transition to
- the shade (in alpha) -->
+ <!-- Media transition distance = qs delay + qs distance -->
+ <dimen name="lockscreen_shade_media_transition_distance">129.28dp</dimen>
<dimen name="lockscreen_shade_scrim_transition_distance">80dp</dimen>
-
<!-- The notifications scrim transition should start when the other scrims' transition is at
95%. -->
<dimen name="lockscreen_shade_notifications_scrim_transition_delay">76dp</dimen>
-
<!-- The notifications scrim transition duration is 66.6% of the duration of the other scrims'
- transition. -->
+ transition. -->
<dimen name="lockscreen_shade_notifications_scrim_transition_distance">53.28dp</dimen>
-
- <!-- Distance that the full shade transition takes in order for the keyguard content on
- NotificationPanelViewController to fully fade (e.g. Clock & Smartspace) -->
<dimen name="lockscreen_shade_npvc_keyguard_content_alpha_transition_distance">80dp</dimen>
-
- <!-- Distance that the full shade transition takes in order for the notification shell to fully
- expand. -->
<dimen name="lockscreen_shade_notif_shelf_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen>
-
- <!-- Distance that the full shade transition takes in order for the Quick Settings to fully
- fade and expand. -->
- <dimen name="lockscreen_shade_qs_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen>
-
- <!-- Distance that the full shade transition takes in order for depth of the wallpaper to fully
- change.
- On split-shade, there should be no depth effect, so setting the value to 0. -->
+ <dimen name="lockscreen_shade_qs_transition_distance">@dimen/lockscreen_shade_notifications_scrim_transition_distance</dimen>
+ <dimen name="lockscreen_shade_qs_transition_delay">@dimen/lockscreen_shade_notifications_scrim_transition_delay</dimen>
+ <dimen name="lockscreen_shade_qs_squish_transition_distance">@dimen/lockscreen_shade_qs_transition_distance</dimen>
+ <!-- On split-shade, the QS squish transition should start from half height. -->
+ <item name="lockscreen_shade_qs_squish_start_fraction" type="dimen" format="float" >0.5</item>
+ <!-- On split-shade, there should be no depth effect, so setting the value to 0. -->
<dimen name="lockscreen_shade_depth_controller_transition_distance">0dp</dimen>
-
- <!-- Distance that the full shade transition takes in order for the UDFPS Keyguard View to fully
- fade. -->
<dimen name="lockscreen_shade_udfps_keyguard_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen>
-
- <!-- Used for StatusBar to know that a transition is in progress. At the moment it only checks
- whether the progress is > 0, therefore this value is not very important. -->
<dimen name="lockscreen_shade_status_bar_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen>
-
<dimen name="lockscreen_shade_keyguard_transition_distance">@dimen/lockscreen_shade_media_transition_distance</dimen>
<!-- Roughly the same distance as media on LS to media on QS. We will translate by this value
diff --git a/packages/SystemUI/res/values-sw600dp/config.xml b/packages/SystemUI/res/values-sw600dp/config.xml
index c0071cb..80628f9 100644
--- a/packages/SystemUI/res/values-sw600dp/config.xml
+++ b/packages/SystemUI/res/values-sw600dp/config.xml
@@ -35,9 +35,6 @@
<!-- How many lines to show in the security footer -->
<integer name="qs_security_footer_maxLines">1</integer>
- <!-- Determines whether to allow the nav bar handle to be forced to be opaque. -->
- <bool name="allow_force_nav_bar_handle_opaque">false</bool>
-
<bool name="config_use_large_screen_shade_header">true</bool>
<!-- Whether to show the side fps hint while on bouncer -->
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index 008299b..a587e5a 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -73,4 +73,24 @@
<dimen name="large_dialog_width">472dp</dimen>
<dimen name="large_screen_shade_header_height">42dp</dimen>
+
+ <!-- Lockscreen shade transition values -->
+ <dimen name="lockscreen_shade_transition_by_tap_distance">200dp</dimen>
+ <dimen name="lockscreen_shade_full_transition_distance">80dp</dimen>
+ <dimen name="lockscreen_shade_media_transition_distance">120dp</dimen>
+ <dimen name="lockscreen_shade_scrim_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen>
+ <dimen name="lockscreen_shade_notifications_scrim_transition_delay">@dimen/lockscreen_shade_scrim_transition_distance</dimen>
+ <dimen name="lockscreen_shade_notifications_scrim_transition_distance">@dimen/lockscreen_shade_scrim_transition_distance</dimen>
+ <dimen name="lockscreen_shade_npvc_keyguard_content_alpha_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen>
+ <dimen name="lockscreen_shade_notif_shelf_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen>
+ <dimen name="lockscreen_shade_qs_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen>
+ <dimen name="lockscreen_shade_qs_transition_delay">@dimen/lockscreen_shade_scrim_transition_distance</dimen>
+ <dimen name="lockscreen_shade_qs_squish_transition_distance">@dimen/lockscreen_shade_qs_transition_distance</dimen>
+ <!-- On large screen portrait, the QS squish transition should start from half height. -->
+ <item name="lockscreen_shade_qs_squish_start_fraction" type="dimen" format="float" >0.5</item>
+ <dimen name="lockscreen_shade_depth_controller_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen>
+ <dimen name="lockscreen_shade_udfps_keyguard_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen>
+ <dimen name="lockscreen_shade_status_bar_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen>
+ <dimen name="lockscreen_shade_keyguard_transition_distance">@dimen/lockscreen_shade_media_transition_distance</dimen>
+
</resources>
diff --git a/packages/SystemUI/res/values-sw720dp-port/dimens.xml b/packages/SystemUI/res/values-sw720dp-port/dimens.xml
index a0bf072..3d8da8a 100644
--- a/packages/SystemUI/res/values-sw720dp-port/dimens.xml
+++ b/packages/SystemUI/res/values-sw720dp-port/dimens.xml
@@ -23,7 +23,7 @@
<dimen name="status_view_margin_horizontal">124dp</dimen>
<dimen name="keyguard_clock_top_margin">80dp</dimen>
<dimen name="keyguard_status_view_bottom_margin">80dp</dimen>
- <dimen name="bouncer_user_switcher_y_trans">90dp</dimen>
+ <dimen name="bouncer_user_switcher_y_trans">200dp</dimen>
<dimen name="large_screen_shade_header_left_padding">24dp</dimen>
<dimen name="qqs_layout_padding_bottom">40dp</dimen>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index d02ae8d..cd1704a 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"முகத்தை அடையாளம் காண முடியவில்லை. கைரேகையைப் பயன்படுத்தவும்."</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"முகத்தை கண்டறிய இயலவில்லை"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"கைரேகையை உபயோகிக்கவும்"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"புளூடூத் இணைக்கப்பட்டது."</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"பேட்டரி சதவீதம் தெரியவில்லை."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g>க்கு இணைக்கப்பட்டது."</string>
@@ -419,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"மேலடுக்கப்பட்ட வசனங்கள்"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"இயக்கும்"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"முடக்கும்"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"ஒலி & அதிர்வு"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"அமைப்புகள்"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"ஆப்ஸ் பின் செய்யப்பட்டது"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"பொருத்தியதை அகற்றும் வரை இதைக் காட்சியில் வைக்கும். அகற்ற, முந்தையது மற்றும் மேலோட்டப் பார்வையைத் தொட்டுப் பிடிக்கவும்."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"இதற்கான பின்னை அகற்றும் வரை, இந்தப் பயன்முறை செயல்பாட்டிலேயே இருக்கும். அகற்றுவதற்கு, முந்தையது மற்றும் முகப்பு பட்டன்களைத் தொட்டுப் பிடிக்கவும்."</string>
@@ -594,7 +598,8 @@
<string name="switch_bar_on" msgid="1770868129120096114">"ஆன்"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"ஆஃப்"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"இல்லை"</string>
- <string name="tile_disabled" msgid="373212051546573069">"முடக்கப்பட்டது"</string>
+ <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+ <skip />
<string name="nav_bar" msgid="4642708685386136807">"வழிசெலுத்தல் பட்டி"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"தளவமைப்பு"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"கூடுதல் இடப்புற பட்டன் வகை"</string>
@@ -667,8 +672,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"மொபைலின் வெப்ப அளவு குறையும் வரை சில அம்சங்களைப் பயன்படுத்த முடியாது.\nமேலும் தகவலுக்கு தட்டவும்"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"உங்கள் மொபைலின் வெப்ப அளவு தானாகவே குறையும். தொடர்ந்து நீங்கள் மொபைலைப் பயன்படுத்தலாம், ஆனால் அதன் வேகம் குறைவாக இருக்கக்கூடும்.\n\nமொபைலின் வெப்ப அளவு குறைந்தவுடன், அது இயல்பு நிலையில் இயங்கும்."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"மேலும் விவரங்களுக்கு இதைப் பார்க்கவும்"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"சார்ஜரைத் துண்டிக்கவும்"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"இந்தச் சாதனத்தைச் சார்ஜ் செய்வதில் சிக்கல் உள்ளது. பவர் அடாப்டரைத் துண்டிக்கவும், கேபிள் சூடாக இருக்கக்கூடும் என்பதால் கவனமாகக் கையாளவும்."</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"மேலும் விவரங்களுக்கு இதைப் பார்க்கவும்"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"இடப்புற ஷார்ட்கட்"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"வலப்புற ஷார்ட்கட்"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index d3252ce..898f008 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"ముఖం గుర్తించలేము. బదులుగా వేలిముద్ర ఉపయోగించండి."</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"ముఖం గుర్తించడం కుదరలేదు"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"బదులుగా వేలిముద్రను ఉపయోగించండి"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"బ్లూటూత్ కనెక్ట్ చేయబడింది."</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"బ్యాటరీ శాతం తెలియదు."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g>కి కనెక్ట్ చేయబడింది."</string>
@@ -419,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"క్యాప్షన్లు ఓవర్లే"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"ప్రారంభించు"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"నిలిపివేయండి"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"సౌండ్ & వైబ్రేషన్"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"సెట్టింగ్లు"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"యాప్ పిన్ చేయబడి ఉంది"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"దీని వలన మీరు అన్పిన్ చేసే వరకు ఇది వీక్షణలో ఉంచబడుతుంది. అన్పిన్ చేయడానికి వెనుకకు మరియు స్థూలదృష్టి తాకి & అలాగే పట్టుకోండి."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"దీని వలన మీరు అన్పిన్ చేసే వరకు ఇది వీక్షణలో ఉంచబడుతుంది. అన్పిన్ చేయడానికి వెనుకకు మరియు హోమ్ని తాకి & అలాగే పట్టుకోండి."</string>
@@ -594,7 +598,7 @@
<string name="switch_bar_on" msgid="1770868129120096114">"ఆన్"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"ఆఫ్ చేయి"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"అందుబాటులో లేదు"</string>
- <string name="tile_disabled" msgid="373212051546573069">"డిజేబుల్ చేయబడింది"</string>
+ <string name="accessibility_tile_disabled_by_policy_action_description" msgid="6958422730461646926">"మరింత తెలుసుకోండి"</string>
<string name="nav_bar" msgid="4642708685386136807">"నావిగేషన్ బార్"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"లేఅవుట్"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"అత్యంత ఎడమ వైపు ఉన్న బటన్ రకం"</string>
@@ -667,8 +671,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"ఫోన్ను చల్లబరిచే క్రమంలో కొన్ని ఫీచర్లు పరిమితం చేయబడ్డాయి.\nమరింత సమాచారం కోసం ట్యాప్ చేయండి"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"మీ ఫోన్ ఆటోమేటిక్గా చల్లబడటానికి ప్రయత్నిస్తుంది. మీరు ఇప్పటికీ మీ ఫోన్ను ఉపయోగించవచ్చు, కానీ దాని పనితీరు నెమ్మదిగా ఉండవచ్చు.\n\nమీ ఫోన్ చల్లబడిన తర్వాత, అది సాధారణ రీతిలో పని చేస్తుంది."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"తీసుకోవాల్సిన జాగ్రత్తలు ఏమిటో చూడండి"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"ప్లగ్ నుండి ఛార్జర్ తీసివేయండి"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"ఈ పరికరాన్ని ఛార్జ్ చేయడంలో సమస్య ఉంది. పవర్ అడాప్టర్ను ప్లగ్ నుండి తీసివేసి, కేబుల్ ఏమైనా వేడిగా అయితే తగిన జాగ్రత్తలు తీసుకోండి."</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"తీసుకోవాల్సిన జాగ్రత్తలు ఏమిటో చూడండి"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"ఎడమవైపు షార్ట్కట్"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"కుడివైపు షార్ట్కట్"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index d827425..9b837d1 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"ไม่รู้จักใบหน้า ใช้ลายนิ้วมือแทน"</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"ไม่รู้จักใบหน้า"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"ใช้ลายนิ้วมือแทน"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"เชื่อมต่อบลูทูธแล้ว"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"ไม่ทราบเปอร์เซ็นต์แบตเตอรี่"</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"เชื่อมต่อกับ <xliff:g id="BLUETOOTH">%s</xliff:g> แล้ว"</string>
@@ -419,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"การวางซ้อนคำบรรยายภาพ"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"เปิดใช้"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"ปิดใช้"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"เสียงและการสั่น"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"การตั้งค่า"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"ปักหมุดแอปอยู่"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"การดำเนินการนี้จะแสดงหน้าจอนี้ไว้เสมอจนกว่าคุณจะเลิกปักหมุด แตะ \"กลับ\" และ \"ภาพรวม\" ค้างไว้เพื่อเลิกปักหมุด"</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"การดำเนินการนี้จะแสดงหน้าจอนี้ไว้เสมอจนกว่าคุณจะเลิกปักหมุด แตะ \"กลับ\" และ \"หน้าแรก\" ค้างไว้เพื่อเลิกปักหมุด"</string>
@@ -594,7 +598,8 @@
<string name="switch_bar_on" msgid="1770868129120096114">"เปิด"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"ปิด"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"ไม่พร้อมใช้งาน"</string>
- <string name="tile_disabled" msgid="373212051546573069">"ปิดใช้"</string>
+ <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+ <skip />
<string name="nav_bar" msgid="4642708685386136807">"แถบนำทาง"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"การจัดวาง"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"ประเภทปุ่มทางซ้ายเพิ่มเติม"</string>
@@ -667,8 +672,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"ฟีเจอร์บางอย่างจะใช้งานได้จำกัดขณะโทรศัพท์เย็นลง\nแตะเพื่อดูข้อมูลเพิ่มเติม"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"โทรศัพท์จะพยายามลดอุณหภูมิลงโดยอัตโนมัติ คุณยังสามารถใช้โทรศัพท์ได้ แต่โทรศัพท์อาจทำงานช้าลง\n\nโทรศัพท์จะทำงานตามปกติเมื่อเย็นลงแล้ว"</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"ดูขั้นตอนในการดูแลรักษา"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"ถอดปลั๊กที่ชาร์จ"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"พบปัญหาในการชาร์จอุปกรณ์นี้ ถอดปลั๊กอะแดปเตอร์ด้วยความระมัดระวังเพราะสายอาจร้อน"</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"ดูขั้นตอนในการดูแลรักษา"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"ทางลัดทางซ้าย"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"ทางลัดทางขวา"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index a5668ed..fb21124 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Hindi makilala ang mukha. Gumamit ng fingerprint."</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"Hindi makilala ang mukha"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Gumamit ng fingerprint"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Nakakonekta ang Bluetooth."</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Hindi alam ang porsyento ng baterya."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Nakakonekta sa <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -419,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Overlay ng mga caption"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"i-enable"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"i-disable"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"Tunog at pag-vibrate"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Mga Setting"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"Naka-pin ang app"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Pinapanatili nitong nakikita ito hanggang sa mag-unpin ka. Pindutin nang matagal ang Bumalik at Overview upang mag-unpin."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Pinapanatili nitong nakikita ito hanggang sa mag-unpin ka. Pindutin nang matagal ang Bumalik at Home upang mag-unpin."</string>
@@ -594,7 +598,8 @@
<string name="switch_bar_on" msgid="1770868129120096114">"I-on"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"I-off"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"Hindi available"</string>
- <string name="tile_disabled" msgid="373212051546573069">"Naka-disable"</string>
+ <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+ <skip />
<string name="nav_bar" msgid="4642708685386136807">"Navigation bar"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"Layout"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"Uri ng extra na button ng kaliwa"</string>
@@ -667,8 +672,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"Limitado ang ilang feature habang nagku-cool down ang telepono.\nMag-tap para sa higit pang impormasyon"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Awtomatikong susubukan ng iyong telepono na mag-cool down. Magagamit mo pa rin ang iyong telepono, ngunit maaaring mas mabagal ang paggana nito.\n\nKapag nakapag-cool down na ang iyong telepono, gagana na ito nang normal."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Tingnan ang mga hakbang sa pangangalaga"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"Hugutin ang charger"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"May isyu sa pag-charge ng device na ito. Hugutin ang power adapter at mag-ingat dahil maaaring mainit ang cable."</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Tingnan ang mga hakbang sa pangangalaga"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Kaliwang shortcut"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Kanang shortcut"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 8cf482d..767d4a5 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Yüz tanınamadı. Bunun yerine parmak izi kullanın."</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"Yüz tanınamadı"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Bunun yerine parmak izi kullanın"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth bağlandı."</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Pil yüzdesi bilinmiyor."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> ile bağlı."</string>
@@ -339,8 +341,7 @@
<string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<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="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Hızlı şarj oluyor • Dolmasına <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> kaldı"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Yavaş şarj oluyor • Dolmasına <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> kaldı"</string>
- <!-- no translation found for keyguard_indication_charging_time_dock (3149328898931741271) -->
- <skip />
+ <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="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Kullanıcı değiştirme"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"açılır menü"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Bu oturumdaki tüm uygulamalar ve veriler silinecek."</string>
@@ -420,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Altyazı yer paylaşımı"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"etkinleştir"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"devre dışı bırak"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"Ses ve titreşim"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Ayarlar"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"Uygulama sabitlendi"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Bu işlem, siz sabitlemeyi kaldırana kadar ekranı görünür durumda tutar. Sabitlemeyi kaldırmak için Geri\'ye ve Genel Bakış\'a dokunup basılı tutun."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Bu işlem, siz sabitlemeyi kaldırana kadar ekranı görünür durumda tutar. Sabitlemeyi kaldırmak için Geri\'ye ve Ana sayfaya dokunup basılı tutun."</string>
@@ -576,7 +579,7 @@
<string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"Klavye Kısayolları"</string>
<string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Klavye düzenini değiştir"</string>
<string name="keyboard_shortcut_group_applications" msgid="7386239431100651266">"Uygulamalar"</string>
- <string name="keyboard_shortcut_group_applications_assist" msgid="771606231466098742">"Asist"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="771606231466098742">"Asistan"</string>
<string name="keyboard_shortcut_group_applications_browser" msgid="2776211137869809251">"Tarayıcı"</string>
<string name="keyboard_shortcut_group_applications_contacts" msgid="2807268086386201060">"Kişiler"</string>
<string name="keyboard_shortcut_group_applications_email" msgid="7852376788894975192">"E-posta"</string>
@@ -595,7 +598,8 @@
<string name="switch_bar_on" msgid="1770868129120096114">"Açık"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"Kapalı"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"Kullanılamıyor"</string>
- <string name="tile_disabled" msgid="373212051546573069">"Devre dışı bırakıldı"</string>
+ <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+ <skip />
<string name="nav_bar" msgid="4642708685386136807">"Gezinme çubuğu"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"Düzen"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"Ekstra sol düğme türü"</string>
@@ -668,8 +672,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"Telefon soğurken bazı özellikler sınırlı olarak kullanılabilir.\nDaha fazla bilgi için dokunun"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Telefonunuz otomatik olarak soğumaya çalışacak. Bu sırada telefonunuzu kullanmaya devam edebilirsiniz ancak uygulamalar daha yavaş çalışabilir.\n\nTelefonunuz soğuduktan sonra normal şekilde çalışacaktır."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Bakımla ilgili adımlara bakın"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"Şarj cihazını çıkarın"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Bu cihaz şarj edilirken bir sorun oluştu. Güç adaptörünün fişini çekin. Kablo sıcak olabileceğinden fişi çekerken dikkatli olun."</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Bakımla ilgili adımlara bakın"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Sol kısayol"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Sağ kısayol"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 4dfde84..e1202dc 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Обличчя не розпізнано. Скористайтеся відбитком пальця."</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"Обличчя не розпізнано"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Скористайтеся відбитком"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth під’єднано."</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Відсоток заряду акумулятора невідомий."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Підключено до <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -339,8 +341,7 @@
<string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Заряджання • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> до повного заряду"</string>
<string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Швидке заряджання • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> до повного заряду"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Повільне заряджання • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> до повного заряду"</string>
- <!-- no translation found for keyguard_indication_charging_time_dock (3149328898931741271) -->
- <skip />
+ <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="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Змінити користувача"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"спадне меню"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Усі додатки й дані з цього сеансу буде видалено."</string>
@@ -420,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Накласти субтитри"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"увімкнути"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"вимкнути"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"Звук і вібрація"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Налаштування"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"Додаток закріплено"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Ви постійно бачитимете екран, доки не відкріпите його. Щоб відкріпити екран, натисніть і втримуйте кнопки \"Назад\" та \"Огляд\"."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Ви бачитимете цей екран, доки не відкріпите його. Для цього натисніть і утримуйте кнопки \"Назад\" та \"Головний екран\"."</string>
@@ -595,7 +598,8 @@
<string name="switch_bar_on" msgid="1770868129120096114">"Увімкнено"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"Вимкнено"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"Недоступно"</string>
- <string name="tile_disabled" msgid="373212051546573069">"Вимкнено"</string>
+ <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+ <skip />
<string name="nav_bar" msgid="4642708685386136807">"Панель навігації"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"Макет"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"Додатковий тип кнопки ліворуч"</string>
@@ -668,8 +672,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"Під час охолодження деякі функції обмежуються.\nНатисніть, щоб дізнатися більше"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Ваш телефон охолоджуватиметься автоматично. Ви можете далі користуватися телефоном, але він може працювати повільніше.\n\nКоли телефон охолоне, він працюватиме належним чином."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Переглянути запобіжні заходи"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"Відключіть зарядний пристрій"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Виникла проблема із заряджанням пристрою. Відключіть адаптер живлення, однак будьте обережні, оскільки кабель може бути гарячим."</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Переглянути застереження"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Комбінація клавіш ліворуч"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Комбінація клавіш праворуч"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index a2754ef..dca8f12 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"چہرے کی شناخت نہیں ہو سکی۔ اس کے بجائے فنگر پرنٹ استعمال کریں۔"</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"چہرے کی پہچان نہیں ہو سکی"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"اس کے بجائے فنگر پرنٹ استعمال کریں"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"بلوٹوتھ مربوط ہے۔"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"بیٹری کی فیصد نامعلوم ہے۔"</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> سے منسلک ہیں۔"</string>
@@ -419,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"کیپشنز کا اوورلے"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"فعال کریں"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"غیر فعال کریں"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"آواز اور وائبریشن"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"ترتیبات"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"ایپ کو پن کر دیا گیا ہے"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"اس سے یہ اس وقت تک منظر میں رہتی ہے جب تک آپ اس سے پن ہٹا نہیں دیتے۔ پن ہٹانے کیلئے پیچھے اور مجموعی جائزہ کے بٹنز کو ٹچ کریں اور دبائے رکھیں۔"</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"اس سے یہ اس وقت تک منظر میں رہتی ہے جب تک آپ اس سے پن نہیں ہٹا دیتے۔ پن ہٹانے کیلئے \"پیچھے\" اور \"ہوم\" بٹنز کو ٹچ کریں اور دبائے رکھیں۔"</string>
@@ -594,7 +598,8 @@
<string name="switch_bar_on" msgid="1770868129120096114">"آن"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"آف"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"غیر دستیاب ہے"</string>
- <string name="tile_disabled" msgid="373212051546573069">"غیر فعال ہے"</string>
+ <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+ <skip />
<string name="nav_bar" msgid="4642708685386136807">"نیویگیشن بار"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"لے آؤٹ"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"بائيں جانب کی اضافی بٹن کی قسم"</string>
@@ -667,8 +672,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"فون کے ٹھنڈے ہو جانے تک کچھ خصوصیات محدود ہیں۔\nمزید معلومات کیلئے تھپتھپائیں"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"آپ کا فون خودکار طور پر ٹھنڈا ہونے کی کوشش کرے گا۔ آپ ابھی بھی اپنا فون استعمال کر سکتے ہیں، مگر ہو سکتا ہے یہ سست چلے۔\n\nایک بار آپ کا فون ٹھنڈا ہوجائے تو یہ معمول کے مطابق چلے گا۔"</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"نگہداشت کے اقدامات ملاحظہ کریں"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"چارجر ان پلگ کریں"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"اس آلہ کو چارج کرنے میں ایک مسئلہ ہے۔ پاور ایڈاپٹر کو ان پلگ کریں اور دھیان دیں کیونکہ تار گرم ہو سکتا ہے۔"</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"نگہداشت کے اقدامات ملاحظہ کریں"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"بائيں جانب کا شارٹ کٹ"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"دائیں جانب کا شارٹ کٹ"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 231e6fc..0102c3cb 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Bu yuz notanish. Barmoq izi orqali urining."</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"Yuz aniqlanmadi"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Barmoq izi orqali urining"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth ulandi."</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Batareya quvvati foizi nomaʼlum."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Ulangan: <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -419,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Taglavhalarni chiqarish"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"faollashtirish"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"faolsizlantirish"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"Tovush va tebranish"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Sozlamalar"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"Ilova mahkamlandi"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Ekran yechilmaguncha u o‘zgarmas holatda qoladi. Uni yechish uchun “Orqaga” va “Umumiy ma’lumot” tugmalarini bosib turing."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Ekran yechib olinmagunicha u mahkamlangan holatda qoladi. Uni yechish uchun Orqaga va Asosiy tugmalarni birga bosib turing."</string>
@@ -594,7 +598,7 @@
<string name="switch_bar_on" msgid="1770868129120096114">"Yoniq"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"Yoqilmagan"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"Mavjud emas"</string>
- <string name="tile_disabled" msgid="373212051546573069">"Faolsizlantirilgan"</string>
+ <string name="accessibility_tile_disabled_by_policy_action_description" msgid="6958422730461646926">"batafsil"</string>
<string name="nav_bar" msgid="4642708685386136807">"Navigatsiya paneli"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"Tugmalar joylashuvi"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"Qo‘shimcha Chapga tugmasi turi"</string>
@@ -667,8 +671,8 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"Telefon sovib qolganda ayrim funksiyalari ishlamasligi mumkin.\nBatafsil axborot uchun bosing"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Telefon avtomatik ravishda o‘zini sovitadi. Telefoningizdan foydalanishda davom etishingiz mumkin, lekin u sekinroq ishlashi mumkin.\n\nTelefon sovishi bilan normal holatda ishlashni boshlaydi."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Batafsil axborot"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"Quvvatlash moslamasini uzing"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Bu qurilmani quvvatlashda muammo bor. Quvvat adapteri va kabelni tarmoqdan uzing, ular qizib ketgan boʻlishi mumkin."</string>
+ <string name="high_temp_alarm_title" msgid="8654754369605452169">"Qurilmani uzing"</string>
+ <string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"Qurilmangiz quvvatlash porti yaqinida qizib ketmoqda. Agar quvvatlagich yoki USB aksessuarga ulangan boʻlsa, kabel qizib ketmasidan uni darhol uzing."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Batafsil axborot"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Chapga yorlig‘i"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"O‘ngga yorlig‘i"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 6e32c3c..59418146 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -161,6 +161,8 @@
<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 keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"Không nhận ra khuôn mặt"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Hãy dùng vân tay"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Đã kết nối bluetooth."</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Tỷ lệ phần trăm pin không xác định."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Đã kết nối với <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -339,8 +341,7 @@
<string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<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="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Đang sạc nhanh • Sẽ đầy sau <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Đang sạc chậm • Sẽ đầy sau <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
- <!-- no translation found for keyguard_indication_charging_time_dock (3149328898931741271) -->
- <skip />
+ <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="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Chuyển đổi người dùng"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"trình đơn kéo xuống"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Tất cả ứng dụng và dữ liệu trong phiên này sẽ bị xóa."</string>
@@ -420,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Lớp phủ phụ đề"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"bật"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"tắt"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"Âm thanh và chế độ rung"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Cài đặt"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"Đã ghim ứng dụng"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Ứng dụng này sẽ ở cố định trên màn hình cho đến khi bạn bỏ ghim. Hãy chạm và giữ Quay lại và Tổng quan để bỏ ghim."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Ứng dụng này sẽ ở cố định trên màn hình cho đến khi bạn bỏ ghim. Hãy chạm và giữ nút Quay lại và nút Màn hình chính để bỏ ghim."</string>
@@ -595,7 +598,8 @@
<string name="switch_bar_on" msgid="1770868129120096114">"Đang bật"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"Đang tắt"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"Không có sẵn"</string>
- <string name="tile_disabled" msgid="373212051546573069">"Đã tắt"</string>
+ <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+ <skip />
<string name="nav_bar" msgid="4642708685386136807">"Thanh điều hướng"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"Bố cục"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"Loại nút bổ sung bên trái"</string>
@@ -668,8 +672,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"Một số tính năng bị hạn chế trong khi điện thoại nguội dần.\nHãy nhấn để biết thêm thông tin"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Điện thoại của bạn sẽ tự động nguội dần. Bạn vẫn có thể sử dụng điện thoại, nhưng điện thoại có thể chạy chậm hơn. \n\nSau khi đã nguội, điện thoại sẽ chạy bình thường."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Xem các bước chăm sóc"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"Rút phích cắm bộ sạc"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Đã xảy ra sự cố khi sạc thiết bị này. Hãy rút phích cắm bộ chuyển đổi điện và cẩn thận vì dây cáp có thể nóng."</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Xem các bước chăm sóc"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Lối tắt bên trái"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Lối tắt bên phải"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index ab6595f..9f1c029 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"无法识别人脸。请改用指纹。"</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"人脸识别失败"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"改用指纹"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"蓝牙已连接。"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"电池电量百分比未知。"</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"已连接到<xliff:g id="BLUETOOTH">%s</xliff:g>。"</string>
@@ -419,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"字幕重叠显示"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"启用"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"停用"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"提示音和振动"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"设置"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"应用已固定"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"这将会固定显示此屏幕,直到您取消固定为止。触摸并按住“返回”和“概览”即可取消固定屏幕。"</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"这将会固定显示此屏幕,直到您取消固定为止。触摸并按住“返回”和“主屏幕”即可取消固定屏幕。"</string>
@@ -594,7 +598,8 @@
<string name="switch_bar_on" msgid="1770868129120096114">"开启"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"关闭"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"不可用"</string>
- <string name="tile_disabled" msgid="373212051546573069">"已停用"</string>
+ <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+ <skip />
<string name="nav_bar" msgid="4642708685386136807">"导航栏"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"布局"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"其他向左按钮类型"</string>
@@ -667,8 +672,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"手机降温时,部分功能的使用会受限制。\n点按即可了解详情"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"您的手机将自动尝试降温。您依然可以使用您的手机,但是手机运行速度可能会更慢。\n\n手机降温后,就会恢复正常的运行速度。"</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"查看处理步骤"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"拔下充电器"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"为此设备充电时出现问题。这可能是由数据线太热所导致,请拔下电源适配器并采取相应的处理措施。"</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"查看处理步骤"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"向左快捷方式"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"向右快捷方式"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index be80083..62a7e88 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"無法辨識面孔,請改用指紋完成驗證。"</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"無法辨識臉孔"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"請改用指紋"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"藍牙連線已建立。"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"電量百分比不明。"</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"已連線至<xliff:g id="BLUETOOTH">%s</xliff:g>。"</string>
@@ -419,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"字幕重疊"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"啟用"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"停用"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"音效和震動"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"設定"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"已固定應用程式"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"應用程式將會固定在螢幕上顯示,直至您取消固定為止。按住「返回」和「概覽」按鈕即可取消固定。"</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"應用程式將會固定在螢幕上顯示,直至您取消固定為止。按住「返回」按鈕和主按鈕即可取消固定。"</string>
@@ -594,7 +598,8 @@
<string name="switch_bar_on" msgid="1770868129120096114">"開啟"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"關閉"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"無法使用"</string>
- <string name="tile_disabled" msgid="373212051546573069">"已停用"</string>
+ <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+ <skip />
<string name="nav_bar" msgid="4642708685386136807">"導覽列"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"配置"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"其他向左按鈕類型"</string>
@@ -667,8 +672,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"手機降溫時,部分功能會受限制。\n輕按即可瞭解詳情"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"手機會自動嘗試降溫。您仍可以使用手機,但手機的運作速度可能較慢。\n\n手機降溫後便會恢復正常。"</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"查看保養步驟"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"拔下充電器"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"為此裝置充電時發生問題。請拔除電源適配器並注意安全,因為連接線可能會發熱。"</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"查看保養步驟"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"向左捷徑"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"向右捷徑"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 03ce73d..a486d83 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"無法辨識臉孔,請改用指紋完成驗證。"</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"無法辨識臉孔"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"請改用指紋"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"藍牙連線已建立。"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"電池電量不明。"</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"已連線至<xliff:g id="BLUETOOTH">%s</xliff:g>。"</string>
@@ -419,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"字幕重疊顯示"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"啟用"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"停用"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"音效與震動"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"設定"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"應用程式已固定"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"這會讓目前的螢幕畫面保持顯示狀態,直到取消固定為止。按住 [返回] 按鈕和 [總覽] 按鈕即可取消固定。"</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"這會讓應用程式顯示在螢幕上,直到取消固定為止。按住 [返回] 按鈕和主畫面按鈕即可取消固定。"</string>
@@ -594,7 +598,8 @@
<string name="switch_bar_on" msgid="1770868129120096114">"開啟"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"關閉"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"無法使用"</string>
- <string name="tile_disabled" msgid="373212051546573069">"已停用"</string>
+ <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+ <skip />
<string name="nav_bar" msgid="4642708685386136807">"導覽列"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"配置"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"其他向左按鈕類型"</string>
@@ -667,8 +672,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"手機降溫時,某些功能會受限。\n輕觸即可瞭解詳情"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"手機會自動嘗試降溫。你仍可繼續使用手機,但是手機的運作速度可能會較慢。\n\n手機降溫完畢後,就會恢復正常的運作速度。"</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"查看處理步驟"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"拔除充電器"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"為這個裝置充電時發生問題。這可能是因為傳輸線過熱所致,請拔除電源變壓器並採取處理措施。"</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"查看處理步驟"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"向左快速鍵"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"向右快速鍵"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 1406da5..2371351 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -161,6 +161,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Ayibazi ubuso. Sebenzisa izigxivizo zeminwe kunalokho."</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
+ <string name="keyguard_face_failed" msgid="9044619102286917151">"Ayikwazi ukubona ubuso"</string>
+ <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Kunalokho sebenzisa isigxivizo somunwe"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth ixhunyiwe"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Iphesenti lebhethri alaziwa."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Xhuma ku-<xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -419,6 +421,8 @@
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Imbondela yamagama-ncazo"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"nika amandla"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"khubaza"</string>
+ <string name="sound_settings" msgid="8874581353127418308">"Umsindo nokudlidliza"</string>
+ <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Amasethingi"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"I-app iphiniwe"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Lokhu kuyigcina ibukeka uze ususe ukuphina. Thinta uphinde ubambe okuthi Emuva Nokubuka konke ukuze ususe ukuphina."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Lokhu kuyigcina ibonakala uze uyisuse. Thinta uphinde ubambe okuthi Emuva nokuthi Ekhaya ukuze ususe ukuphina."</string>
@@ -594,7 +598,8 @@
<string name="switch_bar_on" msgid="1770868129120096114">"Vuliwe"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"Valiwe"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"Akutholakali"</string>
- <string name="tile_disabled" msgid="373212051546573069">"Kukhutshaziwe"</string>
+ <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+ <skip />
<string name="nav_bar" msgid="4642708685386136807">"Ibha yokuzula"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"Isakhiwo"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"Uhlobo lwenkinobho engakwesokunxele engeziwe"</string>
@@ -667,8 +672,10 @@
<string name="high_temp_notif_message" msgid="1277346543068257549">"Ezinye izici zikhawulelwe ngenkathi ifoni iphola.\nThepha mayelana nolwazi olwengeziwe"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Ifoni yakho izozama ngokuzenzakalela ukuphola. Ungasasebenzisa ifoni yakho, kodwa ingasebenza ngokungasheshi.\n\nUma ifoni yakho isipholile, izosebenza ngokuvamile."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Bona izinyathelo zokunakekelwa"</string>
- <string name="high_temp_alarm_title" msgid="2359958549570161495">"Khipha ishaja"</string>
- <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Kukhona inkinga yokushaja le divayisi. Khipha i-adaptha yamandla, uphinde unakekele njengoba ikhebuli kungenzeka lifudumele."</string>
+ <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+ <skip />
+ <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+ <skip />
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Bona izinyathelo zokunakekelwa"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Isinqamuleli sangakwesokunxele"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Isinqamuleli sangakwesokudla"</string>
diff --git a/packages/SystemUI/res/values/bools.xml b/packages/SystemUI/res/values/bools.xml
index 499e24e..c67ac8d 100644
--- a/packages/SystemUI/res/values/bools.xml
+++ b/packages/SystemUI/res/values/bools.xml
@@ -18,4 +18,6 @@
<resources>
<!-- Whether to show the user switcher in quick settings when only a single user is present. -->
<bool name="qs_show_user_switcher_for_single_user">false</bool>
+ <!-- Whether to show a custom biometric prompt size-->
+ <bool name="use_custom_bp_size">false</bool>
</resources>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index db2ac43..c827e21 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -182,7 +182,7 @@
<color name="media_dialog_item_main_content">@color/material_dynamic_primary20</color>
<color name="media_dialog_item_background">@color/material_dynamic_secondary95</color>
<color name="media_dialog_connected_item_background">@color/material_dynamic_primary90</color>
- <color name="media_dialog_seekbar_progress">@color/material_dynamic_secondary40</color>
+ <color name="media_dialog_seekbar_progress">@android:color/system_accent1_200</color>
<color name="media_dialog_button_background">@color/material_dynamic_primary40</color>
<color name="media_dialog_solid_button_text">@color/material_dynamic_neutral95</color>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index ec22c60..a802723 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -587,9 +587,6 @@
when the double-press power gesture is used. Ignored if empty. -->
<string translatable="false" name="config_cameraGesturePackage"></string>
- <!-- Determines whether to allow the nav bar handle to be forced to be opaque. -->
- <bool name="allow_force_nav_bar_handle_opaque">true</bool>
-
<!-- Whether a transition of ACTIVITY_TYPE_DREAM to the home app should play a home sound
effect -->
<bool name="config_playHomeSoundAfterDream">false</bool>
@@ -617,8 +614,9 @@
<!-- Which face help messages to surface when fingerprint is also enrolled.
Message ids correspond with the acquired ids in BiometricFaceConstants -->
<integer-array name="config_face_help_msgs_when_fingerprint_enrolled">
- <item>25</item>
- <item>26</item>
+ <item>3</item> <!-- TOO_DARK -->
+ <item>25</item> <!-- DARK_GLASSES -->
+ <item>26</item> <!-- MOUTH_COVERING_DETECTED -->
</integer-array>
<!-- Whether the communal service should be enabled -->
@@ -629,11 +627,15 @@
<!-- This value is used when calculating whether the device is in ambient light mode. It is
light mode when the light sensor sample value exceeds above this value. -->
- <integer name="config_ambientLightModeThreshold">10</integer>
+ <item name="config_ambientLightModeThreshold" translatable="false" format="float" type="dimen">
+ 0.8
+ </item>
<!-- This value is used when calculating whether the device is in ambient dark mode. It is
dark mode when the light sensor sample value drops below this value. -->
- <integer name="config_ambientDarkModeThreshold">5</integer>
+ <item name="config_ambientDarkModeThreshold" translatable="false" format="float" type="dimen">
+ 0.4
+ </item>
<!-- This value is used when calculating whether the device is in ambient light mode. Each
sample contains light sensor events from this span of time duration. -->
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index e3be365..8089bb1 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -945,6 +945,8 @@
<dimen name="biometric_dialog_medium_to_large_translation_offset">100dp</dimen>
<!-- Y translation for credential contents when animating in -->
<dimen name="biometric_dialog_credential_translation_offset">60dp</dimen>
+ <dimen name="biometric_dialog_width">240dp</dimen>
+ <dimen name="biometric_dialog_height">240dp</dimen>
<!-- Starting text size in sp of batteryLevel for wireless charging animation -->
<item name="wireless_charging_anim_battery_level_text_size_start" format="float" type="dimen">
@@ -1210,6 +1212,17 @@
fade and expand. -->
<dimen name="lockscreen_shade_qs_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen>
+ <!-- Distance delay for the QS transition to start during the lockscreen shade expansion. -->
+ <dimen name="lockscreen_shade_qs_transition_delay">0dp</dimen>
+
+ <!-- Distance that it takes to complete the QS "squish" transition during the lockscreen shade
+ expansion. -->
+ <dimen name="lockscreen_shade_qs_squish_transition_distance">@dimen/lockscreen_shade_qs_transition_distance</dimen>
+
+ <!-- The fraction at which the QS "squish" transition should start during the lockscreen shade
+ expansion. 0 is fully collapsed, 1 is fully expanded. -->
+ <item type="dimen" format="float" name="lockscreen_shade_qs_squish_start_fraction">0</item>
+
<!-- Distance that the full shade transition takes in order for depth of the wallpaper to fully
change. -->
<dimen name="lockscreen_shade_depth_controller_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen>
@@ -1440,6 +1453,8 @@
<dimen name="fgs_manager_list_top_spacing">12dp</dimen>
+ <dimen name="media_projection_app_selector_icon_size">32dp</dimen>
+
<!-- Dream overlay related dimensions -->
<dimen name="dream_overlay_status_bar_height">60dp</dimen>
<dimen name="dream_overlay_status_bar_margin">40dp</dimen>
@@ -1462,14 +1477,14 @@
if their end is aligned with the parent end. Represented as the percentage over from the
start of the parent container. -->
<item name="dream_overlay_complication_guide_end_percent" format="float" type="dimen">
- 0.75
+ 0.5
</item>
<!-- The position of the start guide, which dream overlay complications can align their end to
if their start is aligned with the parent start. Represented as the percentage over from
the start of the parent container. -->
<item name="dream_overlay_complication_guide_start_percent" format="float" type="dimen">
- 0.25
+ 0.5
</item>
<!-- The position of the bottom guide, which dream overlay complications can align their top to
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index f88f46f..8084254 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -183,5 +183,7 @@
<!-- face scanning view id -->
<item type="id" name="face_scanning_anim"/>
+
+ <item type="id" name="qqs_tile_layout"/>
</resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index b33cea7..53f1227 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1644,8 +1644,9 @@
<!-- The tile in quick settings is unavailable. [CHAR LIMIT=32] -->
<string name="tile_unavailable">Unavailable</string>
- <!-- The tile in quick settings is disabled by a device administration policy [CHAR LIMIT=32] -->
- <string name="tile_disabled">Disabled</string>
+ <!-- Accessibility text for the click action on a tile that is disabled by policy. This will
+ be used following "Double-tap to..." [CHAR LIMIT=NONE] -->
+ <string name="accessibility_tile_disabled_by_policy_action_description">learn more</string>
<!-- SysUI Tuner: Button that leads to the navigation bar customization screen [CHAR LIMIT=60] -->
<string name="nav_bar">Navigation bar</string>
@@ -1861,10 +1862,10 @@
<!-- URL for care instructions for overheating devices -->
<string name="high_temp_dialog_help_url" translatable="false"></string>
- <!-- Title for alarm dialog alerting user the usb adapter has reached a certain temperature that should disconnect charging cable immediately. [CHAR LIMIT=30] -->
- <string name="high_temp_alarm_title">Unplug charger</string>
- <!-- Text body for dialog alerting user the usb adapter has reached a certain temperature that should disconnect charging cable immediately. [CHAR LIMIT=300] -->
- <string name="high_temp_alarm_notify_message">There\u2019s an issue charging this device. Unplug the power adapter, and take care as the cable may be warm.</string>
+ <!-- Title for alarm dialog alerting user the usb charger or accessorry has reached a certain temperature that should unplug the device immediately. [CHAR LIMIT=30] -->
+ <string name="high_temp_alarm_title">Unplug your device</string>
+ <!-- Text body for dialog alerting user the usb charger or accessorry has reached a certain temperature that should unplug the device immediately. [CHAR LIMIT=300] -->
+ <string name="high_temp_alarm_notify_message">Your device is getting warm near the charging port. If it\u2019s connected to a charger or USB accessory, unplug it, and take care as the cable may also be warm.</string>
<!-- Text for See care steps button [CHAR LIMIT=300] -->
<string name="high_temp_alarm_help_care_steps">See care steps</string>
<!-- Text link directs to usb overheat help page. -->
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 6b2ff37..ac3eb7e 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -573,6 +573,7 @@
</style>
<style name="MediaPlayer.ProgressBar" parent="@android:style/Widget.ProgressBar.Horizontal">
+ <item name="android:thumb">@drawable/media_seekbar_thumb</item>
<item name="android:thumbTint">?android:attr/textColorPrimary</item>
<item name="android:progressDrawable">@drawable/media_squiggly_progress</item>
<item name="android:progressTint">?android:attr/textColorPrimary</item>
@@ -971,6 +972,8 @@
<!-- Padding for indeterminate progress bar -->
<item name="progressBarStartPadding">12dp</item>
<item name="progressBarEndPadding">16dp</item>
+
+ <item name="iconSize">25dp</item>
</style>
<style name="TextAppearance.Dialog.Title" parent="@android:style/TextAppearance.DeviceDefault.Large">
diff --git a/packages/SystemUI/res/xml/combined_qs_header_scene.xml b/packages/SystemUI/res/xml/combined_qs_header_scene.xml
index 0fac76d..f3866c0 100644
--- a/packages/SystemUI/res/xml/combined_qs_header_scene.xml
+++ b/packages/SystemUI/res/xml/combined_qs_header_scene.xml
@@ -29,17 +29,15 @@
app:percentX="0"
app:percentY="0"
app:framePosition="49"
- app:percentWidth="1"
- app:percentHeight="1"
+ app:sizePercent="0"
app:curveFit="linear"
app:motionTarget="@id/date" />
<KeyPosition
app:keyPositionType="deltaRelative"
app:percentX="1"
app:percentY="0.51"
+ app:sizePercent="1"
app:framePosition="51"
- app:percentWidth="1"
- app:percentHeight="1"
app:curveFit="linear"
app:motionTarget="@id/date" />
<KeyAttribute
@@ -64,6 +62,7 @@
app:percentX="0"
app:percentY="0"
app:framePosition="50"
+ app:sizePercent="0"
app:curveFit="linear"
app:motionTarget="@id/statusIcons" />
<KeyPosition
@@ -71,6 +70,7 @@
app:percentX="1"
app:percentY="0.51"
app:framePosition="51"
+ app:sizePercent="1"
app:curveFit="linear"
app:motionTarget="@id/statusIcons" />
<KeyAttribute
diff --git a/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ExternalViewScreenshotTestRule.kt b/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ExternalViewScreenshotTestRule.kt
new file mode 100644
index 0000000..2e391c7
--- /dev/null
+++ b/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ExternalViewScreenshotTestRule.kt
@@ -0,0 +1,99 @@
+/*
+ * 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.testing.screenshot
+
+import android.app.Activity
+import android.graphics.Color
+import android.view.View
+import android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
+import androidx.core.view.WindowInsetsCompat
+import androidx.core.view.WindowInsetsControllerCompat
+import androidx.core.view.WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
+import androidx.test.platform.app.InstrumentationRegistry
+import org.junit.rules.RuleChain
+import org.junit.rules.TestRule
+import org.junit.runner.Description
+import org.junit.runners.model.Statement
+import platform.test.screenshot.*
+
+/**
+ * A rule that allows to run a screenshot diff test on a view that is hosted in another activity.
+ */
+class ExternalViewScreenshotTestRule(emulationSpec: DeviceEmulationSpec) : TestRule {
+
+ private val colorsRule = MaterialYouColorsRule()
+ private val deviceEmulationRule = DeviceEmulationRule(emulationSpec)
+ private val screenshotRule =
+ ScreenshotTestRule(
+ SystemUIGoldenImagePathManager(getEmulatedDevicePathConfig(emulationSpec))
+ )
+ private val delegateRule =
+ RuleChain.outerRule(colorsRule).around(deviceEmulationRule).around(screenshotRule)
+ private val matcher = UnitTestBitmapMatcher
+
+ override fun apply(base: Statement, description: Description): Statement {
+ return delegateRule.apply(base, description)
+ }
+
+ /**
+ * Compare the content of the [view] with the golden image identified by [goldenIdentifier] in
+ * the context of [emulationSpec].
+ */
+ fun screenshotTest(goldenIdentifier: String, view: View) {
+ view.removeElevationRecursively()
+
+ ScreenshotRuleAsserter.Builder(screenshotRule)
+ .setScreenshotProvider { view.toBitmap() }
+ .withMatcher(matcher)
+ .build()
+ .assertGoldenImage(goldenIdentifier)
+ }
+
+ /**
+ * Compare the content of the [activity] with the golden image identified by [goldenIdentifier]
+ * in the context of [emulationSpec].
+ */
+ fun activityScreenshotTest(
+ goldenIdentifier: String,
+ activity: Activity,
+ ) {
+ val rootView = activity.window.decorView
+
+ // Hide system bars, remove insets, focus and make sure device-specific cutouts
+ // don't affect screenshots
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ val window = activity.window
+ window.setDecorFitsSystemWindows(false)
+ WindowInsetsControllerCompat(window, rootView).apply {
+ hide(WindowInsetsCompat.Type.systemBars())
+ systemBarsBehavior = BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
+ }
+
+ window.statusBarColor = Color.TRANSPARENT
+ window.navigationBarColor = Color.TRANSPARENT
+ window.attributes =
+ window.attributes.apply {
+ layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
+ }
+
+ rootView.removeInsetsRecursively()
+ activity.currentFocus?.clearFocus()
+ }
+
+ screenshotTest(goldenIdentifier, rootView)
+ }
+}
diff --git a/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/TestAppComponentFactory.kt b/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/TestAppComponentFactory.kt
new file mode 100644
index 0000000..98e9aaf
--- /dev/null
+++ b/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/TestAppComponentFactory.kt
@@ -0,0 +1,60 @@
+/*
+ * 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.testing.screenshot
+
+import android.app.Activity
+import android.content.Intent
+import androidx.core.app.AppComponentFactory
+
+class TestAppComponentFactory : AppComponentFactory() {
+
+ init {
+ instance = this
+ }
+
+ private val overrides: MutableMap<String, () -> Activity> = hashMapOf()
+
+ fun clearOverrides() {
+ overrides.clear()
+ }
+
+ fun <T : Activity> registerActivityOverride(activity: Class<T>, provider: () -> T) {
+ overrides[activity.name] = provider
+ }
+
+ override fun instantiateActivityCompat(
+ cl: ClassLoader,
+ className: String,
+ intent: Intent?
+ ): Activity {
+ return overrides
+ .getOrDefault(className) { super.instantiateActivityCompat(cl, className, intent) }
+ .invoke()
+ }
+
+ companion object {
+
+ private var instance: TestAppComponentFactory? = null
+
+ fun getInstance(): TestAppComponentFactory =
+ instance
+ ?: error(
+ "TestAppComponentFactory is not initialized, " +
+ "did you specify it in the manifest?"
+ )
+ }
+}
diff --git a/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/View.kt b/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/View.kt
new file mode 100644
index 0000000..b84d26a
--- /dev/null
+++ b/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/View.kt
@@ -0,0 +1,42 @@
+/*
+ * 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.testing.screenshot
+
+import android.view.View
+import android.view.ViewGroup
+import com.android.systemui.util.children
+import android.view.WindowInsets
+
+/**
+ * Elevation/shadows is not deterministic when doing hardware rendering, this exentsion allows to
+ * disable it for any view in the hierarchy.
+ */
+fun View.removeElevationRecursively() {
+ this.elevation = 0f
+ (this as? ViewGroup)?.children?.forEach(View::removeElevationRecursively)
+}
+
+/**
+ * Different devices could have different insets (e.g. different height of the navigation bar or
+ * taskbar). This method dispatches empty insets to the whole view hierarchy and removes
+ * the original listener, so the views won't receive real insets.
+ */
+fun View.removeInsetsRecursively() {
+ this.dispatchApplyWindowInsets(WindowInsets.CONSUMED)
+ this.setOnApplyWindowInsetsListener(null)
+ (this as? ViewGroup)?.children?.forEach(View::removeInsetsRecursively)
+}
diff --git a/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ViewCapture.kt b/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ViewCapture.kt
index c609e6f..cdedc64 100644
--- a/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ViewCapture.kt
+++ b/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ViewCapture.kt
@@ -1,10 +1,12 @@
package com.android.systemui.testing.screenshot
+import android.annotation.WorkerThread
import android.app.Activity
import android.content.Context
import android.content.ContextWrapper
import android.graphics.Bitmap
import android.graphics.Canvas
+import android.graphics.HardwareRenderer
import android.graphics.Rect
import android.os.Build
import android.os.Handler
@@ -19,8 +21,13 @@
import androidx.concurrent.futures.ResolvableFuture
import androidx.test.annotation.ExperimentalTestApi
import androidx.test.core.internal.os.HandlerExecutor
+import androidx.test.espresso.Espresso
import androidx.test.platform.graphics.HardwareRendererCompat
+import com.google.common.util.concurrent.FutureCallback
+import com.google.common.util.concurrent.Futures
import com.google.common.util.concurrent.ListenableFuture
+import kotlin.coroutines.suspendCoroutine
+import kotlinx.coroutines.runBlocking
/*
* This file was forked from androidx/test/core/view/ViewCapture.kt to add [Window] parameter to
@@ -62,6 +69,47 @@
}
/**
+ * Synchronously captures an image of the view into a [Bitmap]. Synchronous equivalent of
+ * [captureToBitmap].
+ */
+@WorkerThread
+@ExperimentalTestApi
+@RequiresApi(Build.VERSION_CODES.JELLY_BEAN)
+fun View.toBitmap(window: Window? = null): Bitmap {
+ if (Looper.getMainLooper() == Looper.myLooper()) {
+ error("toBitmap() can't be called from the main thread")
+ }
+
+ if (!HardwareRenderer.isDrawingEnabled()) {
+ error("Hardware rendering is not enabled")
+ }
+
+ // Make sure we are idle.
+ Espresso.onIdle()
+
+ val mainExecutor = context.mainExecutor
+ return runBlocking {
+ suspendCoroutine { continuation ->
+ Futures.addCallback(
+ captureToBitmap(window),
+ object : FutureCallback<Bitmap> {
+ override fun onSuccess(result: Bitmap) {
+ continuation.resumeWith(Result.success(result))
+ }
+
+ override fun onFailure(t: Throwable) {
+ continuation.resumeWith(Result.failure(t))
+ }
+ },
+ // We know that we are not on the main thread, so we can block the current
+ // thread and wait for the result in the main thread.
+ mainExecutor,
+ )
+ }
+ }
+}
+
+/**
* Trigger a redraw of the given view.
*
* Should only be called on UI thread.
diff --git a/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ViewScreenshotTestRule.kt b/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ViewScreenshotTestRule.kt
index 47e2d2c..0b0595f 100644
--- a/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ViewScreenshotTestRule.kt
+++ b/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ViewScreenshotTestRule.kt
@@ -19,21 +19,13 @@
import android.app.Activity
import android.app.Dialog
import android.graphics.Bitmap
-import android.graphics.HardwareRenderer
-import android.os.Looper
import android.view.View
import android.view.ViewGroup
import android.view.ViewGroup.LayoutParams
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
-import android.view.Window
import androidx.activity.ComponentActivity
-import androidx.test.espresso.Espresso
import androidx.test.ext.junit.rules.ActivityScenarioRule
-import com.google.common.util.concurrent.FutureCallback
-import com.google.common.util.concurrent.Futures
-import kotlin.coroutines.suspendCoroutine
-import kotlinx.coroutines.runBlocking
import org.junit.Assert.assertEquals
import org.junit.rules.RuleChain
import org.junit.rules.TestRule
@@ -89,6 +81,8 @@
// Elevation/shadows is not deterministic when doing hardware rendering, so we disable
// it for any view in the hierarchy.
window.decorView.removeElevationRecursively()
+
+ activity.currentFocus?.clearFocus()
}
// We call onActivity again because it will make sure that our Activity is done measuring,
@@ -150,53 +144,11 @@
}
}
- private fun View.removeElevationRecursively() {
- this.elevation = 0f
-
- if (this is ViewGroup) {
- repeat(childCount) { i -> getChildAt(i).removeElevationRecursively() }
- }
- }
-
private fun Dialog.toBitmap(): Bitmap {
val window = window
return window.decorView.toBitmap(window)
}
- private fun View.toBitmap(window: Window? = null): Bitmap {
- if (Looper.getMainLooper() == Looper.myLooper()) {
- error("toBitmap() can't be called from the main thread")
- }
-
- if (!HardwareRenderer.isDrawingEnabled()) {
- error("Hardware rendering is not enabled")
- }
-
- // Make sure we are idle.
- Espresso.onIdle()
-
- val mainExecutor = context.mainExecutor
- return runBlocking {
- suspendCoroutine { continuation ->
- Futures.addCallback(
- captureToBitmap(window),
- object : FutureCallback<Bitmap> {
- override fun onSuccess(result: Bitmap?) {
- continuation.resumeWith(Result.success(result!!))
- }
-
- override fun onFailure(t: Throwable) {
- continuation.resumeWith(Result.failure(t))
- }
- },
- // We know that we are not on the main thread, so we can block the current
- // thread and wait for the result in the main thread.
- mainExecutor,
- )
- }
- }
- }
-
enum class Mode(val layoutParams: LayoutParams) {
WrapContent(LayoutParams(WRAP_CONTENT, WRAP_CONTENT)),
MatchSize(LayoutParams(MATCH_PARENT, MATCH_PARENT)),
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
index a030bf6..e77c650 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
@@ -42,13 +42,6 @@
void onOverviewShown(boolean fromHome) = 6;
/**
- * Control the {@param alpha} of the option nav bar button (back-button in 2 button mode
- * and home handle & background in gestural mode). The {@param animate} is currently only
- * supported for 2 button mode.
- */
- void setNavBarButtonAlpha(float alpha, boolean animate) = 19;
-
- /**
* Proxies motion events from the homescreen UI to the status bar. Only called when
* swipe down is detected on WORKSPACE. The sender guarantees the following order of events on
* the tracking pointer.
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java
deleted file mode 100644
index 30c062b..0000000
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java
+++ /dev/null
@@ -1,380 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui.shared.system;
-
-import android.graphics.HardwareRenderer;
-import android.graphics.Matrix;
-import android.graphics.Rect;
-import android.os.Handler;
-import android.os.Handler.Callback;
-import android.os.Message;
-import android.os.Trace;
-import android.view.SurfaceControl;
-import android.view.SurfaceControl.Transaction;
-import android.view.View;
-import android.view.ViewRootImpl;
-
-import java.util.function.Consumer;
-
-/**
- * Helper class to apply surface transactions in sync with RenderThread.
- *
- * NOTE: This is a modification of {@link android.view.SyncRtSurfaceTransactionApplier}, we can't
- * currently reference that class from the shared lib as it is hidden.
- */
-public class SyncRtSurfaceTransactionApplierCompat {
-
- public static final int FLAG_ALL = 0xffffffff;
- public static final int FLAG_ALPHA = 1;
- public static final int FLAG_MATRIX = 1 << 1;
- public static final int FLAG_WINDOW_CROP = 1 << 2;
- public static final int FLAG_LAYER = 1 << 3;
- public static final int FLAG_CORNER_RADIUS = 1 << 4;
- public static final int FLAG_BACKGROUND_BLUR_RADIUS = 1 << 5;
- public static final int FLAG_VISIBILITY = 1 << 6;
- public static final int FLAG_RELATIVE_LAYER = 1 << 7;
- public static final int FLAG_SHADOW_RADIUS = 1 << 8;
-
- private static final int MSG_UPDATE_SEQUENCE_NUMBER = 0;
-
- private final SurfaceControl mBarrierSurfaceControl;
- private final ViewRootImpl mTargetViewRootImpl;
- private final Handler mApplyHandler;
-
- private int mSequenceNumber = 0;
- private int mPendingSequenceNumber = 0;
- private Runnable mAfterApplyCallback;
-
- /**
- * @param targetView The view in the surface that acts as synchronization anchor.
- */
- public SyncRtSurfaceTransactionApplierCompat(View targetView) {
- mTargetViewRootImpl = targetView != null ? targetView.getViewRootImpl() : null;
- mBarrierSurfaceControl = mTargetViewRootImpl != null
- ? mTargetViewRootImpl.getSurfaceControl() : null;
-
- mApplyHandler = new Handler(new Callback() {
- @Override
- public boolean handleMessage(Message msg) {
- if (msg.what == MSG_UPDATE_SEQUENCE_NUMBER) {
- onApplyMessage(msg.arg1);
- return true;
- }
- return false;
- }
- });
- }
-
- private void onApplyMessage(int seqNo) {
- mSequenceNumber = seqNo;
- if (mSequenceNumber == mPendingSequenceNumber && mAfterApplyCallback != null) {
- Runnable r = mAfterApplyCallback;
- mAfterApplyCallback = null;
- r.run();
- }
- }
-
- /**
- * Schedules applying surface parameters on the next frame.
- *
- * @param params The surface parameters to apply. DO NOT MODIFY the list after passing into
- * this method to avoid synchronization issues.
- */
- public void scheduleApply(final SyncRtSurfaceTransactionApplierCompat.SurfaceParams... params) {
- if (mTargetViewRootImpl == null || mTargetViewRootImpl.getView() == null) {
- return;
- }
-
- mPendingSequenceNumber++;
- final int toApplySeqNo = mPendingSequenceNumber;
- mTargetViewRootImpl.registerRtFrameCallback(new HardwareRenderer.FrameDrawingCallback() {
- @Override
- public void onFrameDraw(long frame) {
- if (mBarrierSurfaceControl == null || !mBarrierSurfaceControl.isValid()) {
- Message.obtain(mApplyHandler, MSG_UPDATE_SEQUENCE_NUMBER, toApplySeqNo, 0)
- .sendToTarget();
- return;
- }
- Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Sync transaction frameNumber=" + frame);
- Transaction t = new Transaction();
- for (int i = params.length - 1; i >= 0; i--) {
- SyncRtSurfaceTransactionApplierCompat.SurfaceParams surfaceParams =
- params[i];
- surfaceParams.applyTo(t);
- }
- if (mTargetViewRootImpl != null) {
- mTargetViewRootImpl.mergeWithNextTransaction(t, frame);
- } else {
- t.apply();
- }
- Trace.traceEnd(Trace.TRACE_TAG_VIEW);
- Message.obtain(mApplyHandler, MSG_UPDATE_SEQUENCE_NUMBER, toApplySeqNo, 0)
- .sendToTarget();
- }
- });
-
- // Make sure a frame gets scheduled.
- mTargetViewRootImpl.getView().invalidate();
- }
-
- /**
- * Calls the runnable when any pending apply calls have completed
- */
- public void addAfterApplyCallback(final Runnable afterApplyCallback) {
- if (mSequenceNumber == mPendingSequenceNumber) {
- afterApplyCallback.run();
- } else {
- if (mAfterApplyCallback == null) {
- mAfterApplyCallback = afterApplyCallback;
- } else {
- final Runnable oldCallback = mAfterApplyCallback;
- mAfterApplyCallback = new Runnable() {
- @Override
- public void run() {
- afterApplyCallback.run();
- oldCallback.run();
- }
- };
- }
- }
- }
-
- public static void applyParams(TransactionCompat t,
- SyncRtSurfaceTransactionApplierCompat.SurfaceParams params) {
- params.applyTo(t.mTransaction);
- }
-
- /**
- * Creates an instance of SyncRtSurfaceTransactionApplier, deferring until the target view is
- * attached if necessary.
- */
- public static void create(final View targetView,
- final Consumer<SyncRtSurfaceTransactionApplierCompat> callback) {
- if (targetView == null) {
- // No target view, no applier
- callback.accept(null);
- } else if (targetView.getViewRootImpl() != null) {
- // Already attached, we're good to go
- callback.accept(new SyncRtSurfaceTransactionApplierCompat(targetView));
- } else {
- // Haven't been attached before we can get the view root
- targetView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
- @Override
- public void onViewAttachedToWindow(View v) {
- targetView.removeOnAttachStateChangeListener(this);
- callback.accept(new SyncRtSurfaceTransactionApplierCompat(targetView));
- }
-
- @Override
- public void onViewDetachedFromWindow(View v) {
- // Do nothing
- }
- });
- }
- }
-
- public static class SurfaceParams {
- public static class Builder {
- final SurfaceControl surface;
- int flags;
- float alpha;
- float cornerRadius;
- int backgroundBlurRadius;
- Matrix matrix;
- Rect windowCrop;
- int layer;
- SurfaceControl relativeTo;
- int relativeLayer;
- boolean visible;
- float shadowRadius;
-
- /**
- * @param surface The surface to modify.
- */
- public Builder(SurfaceControl surface) {
- this.surface = surface;
- }
-
- /**
- * @param alpha The alpha value to apply to the surface.
- * @return this Builder
- */
- public Builder withAlpha(float alpha) {
- this.alpha = alpha;
- flags |= FLAG_ALPHA;
- return this;
- }
-
- /**
- * @param matrix The matrix to apply to the surface.
- * @return this Builder
- */
- public Builder withMatrix(Matrix matrix) {
- this.matrix = new Matrix(matrix);
- flags |= FLAG_MATRIX;
- return this;
- }
-
- /**
- * @param windowCrop The window crop to apply to the surface.
- * @return this Builder
- */
- public Builder withWindowCrop(Rect windowCrop) {
- this.windowCrop = new Rect(windowCrop);
- flags |= FLAG_WINDOW_CROP;
- return this;
- }
-
- /**
- * @param layer The layer to assign the surface.
- * @return this Builder
- */
- public Builder withLayer(int layer) {
- this.layer = layer;
- flags |= FLAG_LAYER;
- return this;
- }
-
- /**
- * @param relativeTo The surface that's set relative layer to.
- * @param relativeLayer The relative layer.
- * @return this Builder
- */
- public Builder withRelativeLayerTo(SurfaceControl relativeTo, int relativeLayer) {
- this.relativeTo = relativeTo;
- this.relativeLayer = relativeLayer;
- flags |= FLAG_RELATIVE_LAYER;
- return this;
- }
-
- /**
- * @param radius the Radius for rounded corners to apply to the surface.
- * @return this Builder
- */
- public Builder withCornerRadius(float radius) {
- this.cornerRadius = radius;
- flags |= FLAG_CORNER_RADIUS;
- return this;
- }
-
- /**
- * @param radius the Radius for the shadows to apply to the surface.
- * @return this Builder
- */
- public Builder withShadowRadius(float radius) {
- this.shadowRadius = radius;
- flags |= FLAG_SHADOW_RADIUS;
- return this;
- }
-
- /**
- * @param radius the Radius for blur to apply to the background surfaces.
- * @return this Builder
- */
- public Builder withBackgroundBlur(int radius) {
- this.backgroundBlurRadius = radius;
- flags |= FLAG_BACKGROUND_BLUR_RADIUS;
- return this;
- }
-
- /**
- * @param visible The visibility to apply to the surface.
- * @return this Builder
- */
- public Builder withVisibility(boolean visible) {
- this.visible = visible;
- flags |= FLAG_VISIBILITY;
- return this;
- }
-
- /**
- * @return a new SurfaceParams instance
- */
- public SurfaceParams build() {
- return new SurfaceParams(surface, flags, alpha, matrix, windowCrop, layer,
- relativeTo, relativeLayer, cornerRadius, backgroundBlurRadius, visible,
- shadowRadius);
- }
- }
-
- private SurfaceParams(SurfaceControl surface, int flags, float alpha, Matrix matrix,
- Rect windowCrop, int layer, SurfaceControl relativeTo, int relativeLayer,
- float cornerRadius, int backgroundBlurRadius, boolean visible, float shadowRadius) {
- this.flags = flags;
- this.surface = surface;
- this.alpha = alpha;
- this.matrix = matrix;
- this.windowCrop = windowCrop;
- this.layer = layer;
- this.relativeTo = relativeTo;
- this.relativeLayer = relativeLayer;
- this.cornerRadius = cornerRadius;
- this.backgroundBlurRadius = backgroundBlurRadius;
- this.visible = visible;
- this.shadowRadius = shadowRadius;
- }
-
- private final int flags;
- private final float[] mTmpValues = new float[9];
-
- public final SurfaceControl surface;
- public final float alpha;
- public final float cornerRadius;
- public final int backgroundBlurRadius;
- public final Matrix matrix;
- public final Rect windowCrop;
- public final int layer;
- public final SurfaceControl relativeTo;
- public final int relativeLayer;
- public final boolean visible;
- public final float shadowRadius;
-
- public void applyTo(SurfaceControl.Transaction t) {
- if ((flags & FLAG_MATRIX) != 0) {
- t.setMatrix(surface, matrix, mTmpValues);
- }
- if ((flags & FLAG_WINDOW_CROP) != 0) {
- t.setWindowCrop(surface, windowCrop);
- }
- if ((flags & FLAG_ALPHA) != 0) {
- t.setAlpha(surface, alpha);
- }
- if ((flags & FLAG_LAYER) != 0) {
- t.setLayer(surface, layer);
- }
- if ((flags & FLAG_CORNER_RADIUS) != 0) {
- t.setCornerRadius(surface, cornerRadius);
- }
- if ((flags & FLAG_BACKGROUND_BLUR_RADIUS) != 0) {
- t.setBackgroundBlurRadius(surface, backgroundBlurRadius);
- }
- if ((flags & FLAG_VISIBILITY) != 0) {
- if (visible) {
- t.show(surface);
- } else {
- t.hide(surface);
- }
- }
- if ((flags & FLAG_RELATIVE_LAYER) != 0) {
- t.setRelativeLayer(surface, relativeTo, relativeLayer);
- }
- if ((flags & FLAG_SHADOW_RADIUS) != 0) {
- t.setShadowRadius(surface, shadowRadius);
- }
- }
- }
-}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TransactionCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TransactionCompat.java
deleted file mode 100644
index 43a882a5..0000000
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TransactionCompat.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui.shared.system;
-
-import android.graphics.Matrix;
-import android.graphics.Rect;
-import android.view.SurfaceControl;
-import android.view.SurfaceControl.Transaction;
-
-public class TransactionCompat {
-
- final Transaction mTransaction;
-
- final float[] mTmpValues = new float[9];
-
- public TransactionCompat() {
- mTransaction = new Transaction();
- }
-
- public void apply() {
- mTransaction.apply();
- }
-
- public TransactionCompat show(SurfaceControl surfaceControl) {
- mTransaction.show(surfaceControl);
- return this;
- }
-
- public TransactionCompat hide(SurfaceControl surfaceControl) {
- mTransaction.hide(surfaceControl);
- return this;
- }
-
- public TransactionCompat setPosition(SurfaceControl surfaceControl, float x, float y) {
- mTransaction.setPosition(surfaceControl, x, y);
- return this;
- }
-
- public TransactionCompat setSize(SurfaceControl surfaceControl, int w, int h) {
- mTransaction.setBufferSize(surfaceControl, w, h);
- return this;
- }
-
- public TransactionCompat setLayer(SurfaceControl surfaceControl, int z) {
- mTransaction.setLayer(surfaceControl, z);
- return this;
- }
-
- public TransactionCompat setAlpha(SurfaceControl surfaceControl, float alpha) {
- mTransaction.setAlpha(surfaceControl, alpha);
- return this;
- }
-
- public TransactionCompat setOpaque(SurfaceControl surfaceControl, boolean opaque) {
- mTransaction.setOpaque(surfaceControl, opaque);
- return this;
- }
-
- public TransactionCompat setMatrix(SurfaceControl surfaceControl, float dsdx, float dtdx,
- float dtdy, float dsdy) {
- mTransaction.setMatrix(surfaceControl, dsdx, dtdx, dtdy, dsdy);
- return this;
- }
-
- public TransactionCompat setMatrix(SurfaceControl surfaceControl, Matrix matrix) {
- mTransaction.setMatrix(surfaceControl, matrix, mTmpValues);
- return this;
- }
-
- public TransactionCompat setWindowCrop(SurfaceControl surfaceControl, Rect crop) {
- mTransaction.setWindowCrop(surfaceControl, crop);
- return this;
- }
-
- public TransactionCompat setCornerRadius(SurfaceControl surfaceControl, float radius) {
- mTransaction.setCornerRadius(surfaceControl, radius);
- return this;
- }
-
- public TransactionCompat setBackgroundBlurRadius(SurfaceControl surfaceControl, int radius) {
- mTransaction.setBackgroundBlurRadius(surfaceControl, radius);
- return this;
- }
-
- public TransactionCompat setColor(SurfaceControl surfaceControl, float[] color) {
- mTransaction.setColor(surfaceControl, color);
- return this;
- }
-
- public static void setRelativeLayer(Transaction t, SurfaceControl surfaceControl,
- SurfaceControl relativeTo, int z) {
- t.setRelativeLayer(surfaceControl, relativeTo, z);
- }
-}
diff --git a/packages/SystemUI/src/com/android/keyguard/AuthKeyguardMessageArea.kt b/packages/SystemUI/src/com/android/keyguard/AuthKeyguardMessageArea.kt
new file mode 100644
index 0000000..82ce1ca
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/AuthKeyguardMessageArea.kt
@@ -0,0 +1,33 @@
+/*
+ * 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.keyguard
+
+import android.content.Context
+import android.content.res.ColorStateList
+import android.graphics.Color
+import android.util.AttributeSet
+
+/**
+ * Displays security messages for auth outside of the security method (pin, password, pattern), like
+ * biometric auth.
+ */
+class AuthKeyguardMessageArea(context: Context?, attrs: AttributeSet?) :
+ KeyguardMessageArea(context, attrs) {
+ override fun updateTextColor() {
+ setTextColor(ColorStateList.valueOf(Color.WHITE))
+ }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/BouncerKeyguardMessageArea.kt b/packages/SystemUI/src/com/android/keyguard/BouncerKeyguardMessageArea.kt
new file mode 100644
index 0000000..0075ddd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/BouncerKeyguardMessageArea.kt
@@ -0,0 +1,61 @@
+/*
+ * 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.keyguard
+
+import android.content.Context
+import android.content.res.ColorStateList
+import android.content.res.TypedArray
+import android.graphics.Color
+import android.util.AttributeSet
+import com.android.settingslib.Utils
+
+/** Displays security messages for the keyguard bouncer. */
+class BouncerKeyguardMessageArea(context: Context?, attrs: AttributeSet?) :
+ KeyguardMessageArea(context, attrs) {
+ private val DEFAULT_COLOR = -1
+ private var mDefaultColorState: ColorStateList? = null
+ private var mNextMessageColorState: ColorStateList? = ColorStateList.valueOf(DEFAULT_COLOR)
+
+ override fun updateTextColor() {
+ var colorState = mDefaultColorState
+ mNextMessageColorState?.defaultColor?.let { color ->
+ if (color != DEFAULT_COLOR) {
+ colorState = mNextMessageColorState
+ mNextMessageColorState = ColorStateList.valueOf(DEFAULT_COLOR)
+ }
+ }
+ setTextColor(colorState)
+ }
+
+ override fun setNextMessageColor(colorState: ColorStateList?) {
+ mNextMessageColorState = colorState
+ }
+
+ override fun onThemeChanged() {
+ val array: TypedArray =
+ mContext.obtainStyledAttributes(intArrayOf(android.R.attr.textColorPrimary))
+ val newTextColors: ColorStateList = ColorStateList.valueOf(array.getColor(0, Color.RED))
+ array.recycle()
+ mDefaultColorState = newTextColors
+ super.onThemeChanged()
+ }
+
+ override fun reloadColor() {
+ mDefaultColorState = Utils.getColorAttr(context, android.R.attr.textColorPrimary)
+ super.reloadColor()
+ }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/FaceAuthReason.kt b/packages/SystemUI/src/com/android/keyguard/FaceAuthReason.kt
new file mode 100644
index 0000000..6fcb6f5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/FaceAuthReason.kt
@@ -0,0 +1,255 @@
+/*
+ * 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.keyguard
+
+import android.annotation.StringDef
+import com.android.internal.logging.UiEvent
+import com.android.internal.logging.UiEventLogger
+import com.android.keyguard.FaceAuthApiRequestReason.Companion.NOTIFICATION_PANEL_CLICKED
+import com.android.keyguard.FaceAuthApiRequestReason.Companion.PICK_UP_GESTURE_TRIGGERED
+import com.android.keyguard.FaceAuthApiRequestReason.Companion.QS_EXPANDED
+import com.android.keyguard.FaceAuthApiRequestReason.Companion.SWIPE_UP_ON_BOUNCER
+import com.android.keyguard.FaceAuthApiRequestReason.Companion.UDFPS_POINTER_DOWN
+import com.android.keyguard.InternalFaceAuthReasons.ALL_AUTHENTICATORS_REGISTERED
+import com.android.keyguard.InternalFaceAuthReasons.ALTERNATE_BIOMETRIC_BOUNCER_SHOWN
+import com.android.keyguard.InternalFaceAuthReasons.ASSISTANT_VISIBILITY_CHANGED
+import com.android.keyguard.InternalFaceAuthReasons.AUTH_REQUEST_DURING_CANCELLATION
+import com.android.keyguard.InternalFaceAuthReasons.BIOMETRIC_ENABLED
+import com.android.keyguard.InternalFaceAuthReasons.CAMERA_LAUNCHED
+import com.android.keyguard.InternalFaceAuthReasons.DEVICE_WOKEN_UP_ON_REACH_GESTURE
+import com.android.keyguard.InternalFaceAuthReasons.DREAM_STARTED
+import com.android.keyguard.InternalFaceAuthReasons.DREAM_STOPPED
+import com.android.keyguard.InternalFaceAuthReasons.ENROLLMENTS_CHANGED
+import com.android.keyguard.InternalFaceAuthReasons.FACE_AUTHENTICATED
+import com.android.keyguard.InternalFaceAuthReasons.FACE_AUTH_STOPPED_ON_USER_INPUT
+import com.android.keyguard.InternalFaceAuthReasons.FACE_CANCEL_NOT_RECEIVED
+import com.android.keyguard.InternalFaceAuthReasons.FACE_LOCKOUT_RESET
+import com.android.keyguard.InternalFaceAuthReasons.FINISHED_GOING_TO_SLEEP
+import com.android.keyguard.InternalFaceAuthReasons.FP_AUTHENTICATED
+import com.android.keyguard.InternalFaceAuthReasons.FP_LOCKED_OUT
+import com.android.keyguard.InternalFaceAuthReasons.GOING_TO_SLEEP
+import com.android.keyguard.InternalFaceAuthReasons.KEYGUARD_GOING_AWAY
+import com.android.keyguard.InternalFaceAuthReasons.KEYGUARD_INIT
+import com.android.keyguard.InternalFaceAuthReasons.KEYGUARD_OCCLUSION_CHANGED
+import com.android.keyguard.InternalFaceAuthReasons.KEYGUARD_RESET
+import com.android.keyguard.InternalFaceAuthReasons.KEYGUARD_VISIBILITY_CHANGED
+import com.android.keyguard.InternalFaceAuthReasons.OCCLUDING_APP_REQUESTED
+import com.android.keyguard.InternalFaceAuthReasons.PRIMARY_BOUNCER_SHOWN
+import com.android.keyguard.InternalFaceAuthReasons.PRIMARY_BOUNCER_SHOWN_OR_WILL_BE_SHOWN
+import com.android.keyguard.InternalFaceAuthReasons.RETRY_AFTER_HW_UNAVAILABLE
+import com.android.keyguard.InternalFaceAuthReasons.STARTED_WAKING_UP
+import com.android.keyguard.InternalFaceAuthReasons.TRUST_DISABLED
+import com.android.keyguard.InternalFaceAuthReasons.TRUST_ENABLED
+import com.android.keyguard.InternalFaceAuthReasons.USER_SWITCHING
+
+/**
+ * List of reasons why face auth is requested by clients through
+ * [KeyguardUpdateMonitor.requestFaceAuth].
+ */
+@Retention(AnnotationRetention.SOURCE)
+@StringDef(
+ SWIPE_UP_ON_BOUNCER,
+ UDFPS_POINTER_DOWN,
+ NOTIFICATION_PANEL_CLICKED,
+ QS_EXPANDED,
+ PICK_UP_GESTURE_TRIGGERED,
+)
+annotation class FaceAuthApiRequestReason {
+ companion object {
+ const val SWIPE_UP_ON_BOUNCER = "Face auth due to swipe up on bouncer"
+ const val UDFPS_POINTER_DOWN = "Face auth triggered due to finger down on UDFPS"
+ const val NOTIFICATION_PANEL_CLICKED = "Face auth due to notification panel click."
+ const val QS_EXPANDED = "Face auth due to QS expansion."
+ const val PICK_UP_GESTURE_TRIGGERED =
+ "Face auth due to pickup gesture triggered when the device is awake and not from AOD."
+ }
+}
+
+/** List of events why face auth could be triggered by [KeyguardUpdateMonitor]. */
+private object InternalFaceAuthReasons {
+ const val OCCLUDING_APP_REQUESTED = "Face auth due to request from occluding app."
+ const val RETRY_AFTER_HW_UNAVAILABLE = "Face auth due to retry after hardware unavailable."
+ const val FACE_LOCKOUT_RESET = "Face auth due to face lockout reset."
+ const val DEVICE_WOKEN_UP_ON_REACH_GESTURE =
+ "Face auth requested when user reaches for the device on AoD."
+ const val ALTERNATE_BIOMETRIC_BOUNCER_SHOWN = "Face auth due to alternate bouncer shown."
+ const val PRIMARY_BOUNCER_SHOWN = "Face auth started/stopped due to primary bouncer shown."
+ const val PRIMARY_BOUNCER_SHOWN_OR_WILL_BE_SHOWN =
+ "Face auth started/stopped due to bouncer being shown or will be shown."
+ const val TRUST_DISABLED = "Face auth started due to trust disabled."
+ const val TRUST_ENABLED = "Face auth stopped due to trust enabled."
+ const val KEYGUARD_OCCLUSION_CHANGED =
+ "Face auth started/stopped due to keyguard occlusion change."
+ const val ASSISTANT_VISIBILITY_CHANGED =
+ "Face auth started/stopped due to assistant visibility change."
+ const val STARTED_WAKING_UP = "Face auth started/stopped due to device starting to wake up."
+ const val DREAM_STOPPED = "Face auth due to dream stopped."
+ const val ALL_AUTHENTICATORS_REGISTERED = "Face auth due to all authenticators registered."
+ const val ENROLLMENTS_CHANGED = "Face auth due to enrolments changed."
+ const val KEYGUARD_VISIBILITY_CHANGED =
+ "Face auth stopped or started due to keyguard visibility changed."
+ const val FACE_CANCEL_NOT_RECEIVED = "Face auth stopped due to face cancel signal not received."
+ const val AUTH_REQUEST_DURING_CANCELLATION =
+ "Another request to start face auth received while cancelling face auth"
+ const val DREAM_STARTED = "Face auth stopped because dreaming started"
+ const val FP_LOCKED_OUT = "Face auth stopped because fp locked out"
+ const val FACE_AUTH_STOPPED_ON_USER_INPUT =
+ "Face auth stopped because user started typing password/pin"
+ const val KEYGUARD_GOING_AWAY = "Face auth stopped because keyguard going away"
+ const val CAMERA_LAUNCHED = "Face auth started/stopped because camera launched"
+ const val FP_AUTHENTICATED = "Face auth started/stopped because fingerprint launched"
+ const val GOING_TO_SLEEP = "Face auth started/stopped because going to sleep"
+ const val FINISHED_GOING_TO_SLEEP = "Face auth stopped because finished going to sleep"
+ const val KEYGUARD_INIT = "Face auth started/stopped because Keyguard is initialized"
+ const val KEYGUARD_RESET = "Face auth started/stopped because Keyguard is reset"
+ const val USER_SWITCHING = "Face auth started/stopped because user is switching"
+ const val FACE_AUTHENTICATED = "Face auth started/stopped because face is authenticated"
+ const val BIOMETRIC_ENABLED =
+ "Face auth started/stopped because biometric is enabled on keyguard"
+}
+
+/** UiEvents that are logged to identify why face auth is being triggered. */
+enum class FaceAuthUiEvent constructor(private val id: Int, val reason: String) :
+ UiEventLogger.UiEventEnum {
+ @UiEvent(doc = OCCLUDING_APP_REQUESTED)
+ FACE_AUTH_TRIGGERED_OCCLUDING_APP_REQUESTED(1146, OCCLUDING_APP_REQUESTED),
+
+ @UiEvent(doc = UDFPS_POINTER_DOWN)
+ FACE_AUTH_TRIGGERED_UDFPS_POINTER_DOWN(1147, UDFPS_POINTER_DOWN),
+
+ @UiEvent(doc = SWIPE_UP_ON_BOUNCER)
+ FACE_AUTH_TRIGGERED_SWIPE_UP_ON_BOUNCER(1148, SWIPE_UP_ON_BOUNCER),
+
+ @UiEvent(doc = DEVICE_WOKEN_UP_ON_REACH_GESTURE)
+ FACE_AUTH_TRIGGERED_ON_REACH_GESTURE_ON_AOD(1149, DEVICE_WOKEN_UP_ON_REACH_GESTURE),
+
+ @UiEvent(doc = FACE_LOCKOUT_RESET)
+ FACE_AUTH_TRIGGERED_FACE_LOCKOUT_RESET(1150, FACE_LOCKOUT_RESET),
+
+ @UiEvent(doc = QS_EXPANDED)
+ FACE_AUTH_TRIGGERED_QS_EXPANDED(1151, QS_EXPANDED),
+
+ @UiEvent(doc = NOTIFICATION_PANEL_CLICKED)
+ FACE_AUTH_TRIGGERED_NOTIFICATION_PANEL_CLICKED(1152, NOTIFICATION_PANEL_CLICKED),
+
+ @UiEvent(doc = PICK_UP_GESTURE_TRIGGERED)
+ FACE_AUTH_TRIGGERED_PICK_UP_GESTURE_TRIGGERED(1153, PICK_UP_GESTURE_TRIGGERED),
+
+ @UiEvent(doc = ALTERNATE_BIOMETRIC_BOUNCER_SHOWN)
+ FACE_AUTH_TRIGGERED_ALTERNATE_BIOMETRIC_BOUNCER_SHOWN(1154,
+ ALTERNATE_BIOMETRIC_BOUNCER_SHOWN),
+
+ @UiEvent(doc = PRIMARY_BOUNCER_SHOWN)
+ FACE_AUTH_UPDATED_PRIMARY_BOUNCER_SHOWN(1155, PRIMARY_BOUNCER_SHOWN),
+
+ @UiEvent(doc = PRIMARY_BOUNCER_SHOWN_OR_WILL_BE_SHOWN)
+ FACE_AUTH_UPDATED_PRIMARY_BOUNCER_SHOWN_OR_WILL_BE_SHOWN(
+ 1197,
+ PRIMARY_BOUNCER_SHOWN_OR_WILL_BE_SHOWN
+ ),
+
+ @UiEvent(doc = RETRY_AFTER_HW_UNAVAILABLE)
+ FACE_AUTH_TRIGGERED_RETRY_AFTER_HW_UNAVAILABLE(1156, RETRY_AFTER_HW_UNAVAILABLE),
+
+ @UiEvent(doc = TRUST_DISABLED)
+ FACE_AUTH_TRIGGERED_TRUST_DISABLED(1158, TRUST_DISABLED),
+
+ @UiEvent(doc = TRUST_ENABLED)
+ FACE_AUTH_STOPPED_TRUST_ENABLED(1173, TRUST_ENABLED),
+
+ @UiEvent(doc = KEYGUARD_OCCLUSION_CHANGED)
+ FACE_AUTH_UPDATED_KEYGUARD_OCCLUSION_CHANGED(1159, KEYGUARD_OCCLUSION_CHANGED),
+
+ @UiEvent(doc = ASSISTANT_VISIBILITY_CHANGED)
+ FACE_AUTH_UPDATED_ASSISTANT_VISIBILITY_CHANGED(1160, ASSISTANT_VISIBILITY_CHANGED),
+
+ @UiEvent(doc = STARTED_WAKING_UP)
+ FACE_AUTH_UPDATED_STARTED_WAKING_UP(1161, STARTED_WAKING_UP),
+
+ @UiEvent(doc = DREAM_STOPPED)
+ FACE_AUTH_TRIGGERED_DREAM_STOPPED(1162, DREAM_STOPPED),
+
+ @UiEvent(doc = ALL_AUTHENTICATORS_REGISTERED)
+ FACE_AUTH_TRIGGERED_ALL_AUTHENTICATORS_REGISTERED(1163, ALL_AUTHENTICATORS_REGISTERED),
+
+ @UiEvent(doc = ENROLLMENTS_CHANGED)
+ FACE_AUTH_TRIGGERED_ENROLLMENTS_CHANGED(1164, ENROLLMENTS_CHANGED),
+
+ @UiEvent(doc = KEYGUARD_VISIBILITY_CHANGED)
+ FACE_AUTH_UPDATED_KEYGUARD_VISIBILITY_CHANGED(1165, KEYGUARD_VISIBILITY_CHANGED),
+
+ @UiEvent(doc = FACE_CANCEL_NOT_RECEIVED)
+ FACE_AUTH_STOPPED_FACE_CANCEL_NOT_RECEIVED(1174, FACE_CANCEL_NOT_RECEIVED),
+
+ @UiEvent(doc = AUTH_REQUEST_DURING_CANCELLATION)
+ FACE_AUTH_TRIGGERED_DURING_CANCELLATION(1175, AUTH_REQUEST_DURING_CANCELLATION),
+
+ @UiEvent(doc = DREAM_STARTED)
+ FACE_AUTH_STOPPED_DREAM_STARTED(1176, DREAM_STARTED),
+
+ @UiEvent(doc = FP_LOCKED_OUT)
+ FACE_AUTH_STOPPED_FP_LOCKED_OUT(1177, FP_LOCKED_OUT),
+
+ @UiEvent(doc = FACE_AUTH_STOPPED_ON_USER_INPUT)
+ FACE_AUTH_STOPPED_USER_INPUT_ON_BOUNCER(1178, FACE_AUTH_STOPPED_ON_USER_INPUT),
+
+ @UiEvent(doc = KEYGUARD_GOING_AWAY)
+ FACE_AUTH_STOPPED_KEYGUARD_GOING_AWAY(1179, KEYGUARD_GOING_AWAY),
+
+ @UiEvent(doc = CAMERA_LAUNCHED)
+ FACE_AUTH_UPDATED_CAMERA_LAUNCHED(1180, CAMERA_LAUNCHED),
+
+ @UiEvent(doc = FP_AUTHENTICATED)
+ FACE_AUTH_UPDATED_FP_AUTHENTICATED(1181, FP_AUTHENTICATED),
+
+ @UiEvent(doc = GOING_TO_SLEEP)
+ FACE_AUTH_UPDATED_GOING_TO_SLEEP(1182, GOING_TO_SLEEP),
+
+ @UiEvent(doc = FINISHED_GOING_TO_SLEEP)
+ FACE_AUTH_STOPPED_FINISHED_GOING_TO_SLEEP(1183, FINISHED_GOING_TO_SLEEP),
+
+ @UiEvent(doc = KEYGUARD_INIT)
+ FACE_AUTH_UPDATED_ON_KEYGUARD_INIT(1189, KEYGUARD_INIT),
+
+ @UiEvent(doc = KEYGUARD_RESET)
+ FACE_AUTH_UPDATED_KEYGUARD_RESET(1185, KEYGUARD_RESET),
+
+ @UiEvent(doc = USER_SWITCHING)
+ FACE_AUTH_UPDATED_USER_SWITCHING(1186, USER_SWITCHING),
+
+ @UiEvent(doc = FACE_AUTHENTICATED)
+ FACE_AUTH_UPDATED_ON_FACE_AUTHENTICATED(1187, FACE_AUTHENTICATED),
+
+ @UiEvent(doc = BIOMETRIC_ENABLED)
+ FACE_AUTH_UPDATED_BIOMETRIC_ENABLED_ON_KEYGUARD(1188, BIOMETRIC_ENABLED);
+
+ override fun getId(): Int = this.id
+}
+
+private val apiRequestReasonToUiEvent =
+ mapOf(
+ SWIPE_UP_ON_BOUNCER to FaceAuthUiEvent.FACE_AUTH_TRIGGERED_SWIPE_UP_ON_BOUNCER,
+ UDFPS_POINTER_DOWN to FaceAuthUiEvent.FACE_AUTH_TRIGGERED_UDFPS_POINTER_DOWN,
+ NOTIFICATION_PANEL_CLICKED to
+ FaceAuthUiEvent.FACE_AUTH_TRIGGERED_NOTIFICATION_PANEL_CLICKED,
+ QS_EXPANDED to FaceAuthUiEvent.FACE_AUTH_TRIGGERED_QS_EXPANDED,
+ PICK_UP_GESTURE_TRIGGERED to FaceAuthUiEvent.FACE_AUTH_TRIGGERED_PICK_UP_GESTURE_TRIGGERED,
+ )
+
+/** Converts the [reason] to the corresponding [FaceAuthUiEvent]. */
+fun apiRequestReasonToUiEvent(@FaceAuthApiRequestReason reason: String): FaceAuthUiEvent =
+ apiRequestReasonToUiEvent[reason]!!
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java
index b8fcb10..92ba619 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java
@@ -50,7 +50,6 @@
private final FalsingCollector mFalsingCollector;
private final EmergencyButtonController mEmergencyButtonController;
private CountDownTimer mCountdownTimer;
- protected KeyguardMessageAreaController mMessageAreaController;
private boolean mDismissing;
protected AsyncTask<?, ?, ?> mPendingLockCheck;
protected boolean mResumed;
@@ -80,14 +79,13 @@
KeyguardMessageAreaController.Factory messageAreaControllerFactory,
LatencyTracker latencyTracker, FalsingCollector falsingCollector,
EmergencyButtonController emergencyButtonController) {
- super(view, securityMode, keyguardSecurityCallback, emergencyButtonController);
+ super(view, securityMode, keyguardSecurityCallback, emergencyButtonController,
+ messageAreaControllerFactory);
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mLockPatternUtils = lockPatternUtils;
mLatencyTracker = latencyTracker;
mFalsingCollector = falsingCollector;
mEmergencyButtonController = emergencyButtonController;
- KeyguardMessageArea kma = KeyguardMessageArea.findSecurityMessageDisplay(mView);
- mMessageAreaController = messageAreaControllerFactory.create(kma);
}
abstract void resetState();
@@ -95,7 +93,6 @@
@Override
public void onInit() {
super.onInit();
- mMessageAreaController.init();
}
@Override
@@ -134,6 +131,10 @@
@Override
public void showMessage(CharSequence message, ColorStateList colorState) {
+ if (mMessageAreaController == null) {
+ return;
+ }
+
if (colorState != null) {
mMessageAreaController.setNextMessageColor(colorState);
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
index 87300c3..f26b905 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
@@ -17,9 +17,11 @@
package com.android.keyguard;
import android.annotation.CallSuper;
+import android.annotation.Nullable;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.telephony.TelephonyManager;
+import android.util.Log;
import android.view.inputmethod.InputMethodManager;
import com.android.internal.util.LatencyTracker;
@@ -44,7 +46,7 @@
private final EmergencyButton mEmergencyButton;
private final EmergencyButtonController mEmergencyButtonController;
private boolean mPaused;
-
+ protected KeyguardMessageAreaController<BouncerKeyguardMessageArea> mMessageAreaController;
// The following is used to ignore callbacks from SecurityViews that are no longer current
// (e.g. face unlock). This avoids unwanted asynchronous events from messing with the
@@ -72,12 +74,24 @@
protected KeyguardInputViewController(T view, SecurityMode securityMode,
KeyguardSecurityCallback keyguardSecurityCallback,
- EmergencyButtonController emergencyButtonController) {
+ EmergencyButtonController emergencyButtonController,
+ @Nullable KeyguardMessageAreaController.Factory messageAreaControllerFactory) {
super(view);
mSecurityMode = securityMode;
mKeyguardSecurityCallback = keyguardSecurityCallback;
mEmergencyButton = view == null ? null : view.findViewById(R.id.emergency_call_button);
mEmergencyButtonController = emergencyButtonController;
+ if (messageAreaControllerFactory != null) {
+ try {
+ BouncerKeyguardMessageArea kma = view.requireViewById(R.id.bouncer_message_area);
+ mMessageAreaController = messageAreaControllerFactory.create(kma);
+ mMessageAreaController.init();
+ mMessageAreaController.setIsVisible(true);
+ } catch (IllegalArgumentException exception) {
+ Log.e("KeyguardInputViewController",
+ "Ensure that a BouncerKeyguardMessageArea is included in the layout");
+ }
+ }
}
@Override
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardListenModel.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardListenModel.kt
index 0ea1965..919b71b 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardListenModel.kt
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardListenModel.kt
@@ -52,6 +52,7 @@
val becauseCannotSkipBouncer: Boolean,
val biometricSettingEnabledForUser: Boolean,
val bouncerFullyShown: Boolean,
+ val bouncerIsOrWillShow: Boolean,
val faceAuthenticated: Boolean,
val faceDisabled: Boolean,
val goingToSleep: Boolean,
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java
index 5ab2fd0..c79fc2c 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java
@@ -17,9 +17,7 @@
package com.android.keyguard;
import android.content.Context;
-import android.content.res.ColorStateList;
import android.content.res.TypedArray;
-import android.graphics.Color;
import android.os.Handler;
import android.os.Looper;
import android.os.SystemClock;
@@ -33,7 +31,6 @@
import androidx.annotation.Nullable;
import com.android.internal.policy.SystemBarUtils;
-import com.android.settingslib.Utils;
import com.android.systemui.R;
import java.lang.ref.WeakReference;
@@ -41,7 +38,7 @@
/***
* Manages a number of views inside of the given layout. See below for a list of widgets.
*/
-public class KeyguardMessageArea extends TextView implements SecurityMessageDisplay {
+public abstract class KeyguardMessageArea extends TextView implements SecurityMessageDisplay {
/** Handler token posted with accessibility announcement runnables. */
private static final Object ANNOUNCE_TOKEN = new Object();
@@ -50,15 +47,11 @@
* lift-to-type from interrupting itself.
*/
private static final long ANNOUNCEMENT_DELAY = 250;
- private static final int DEFAULT_COLOR = -1;
private final Handler mHandler;
- private ColorStateList mDefaultColorState;
private CharSequence mMessage;
- private ColorStateList mNextMessageColorState = ColorStateList.valueOf(DEFAULT_COLOR);
- private boolean mBouncerShowing;
- private boolean mAltBouncerShowing;
+ private boolean mIsVisible;
/**
* Container that wraps the KeyguardMessageArea - may be null if current view hierarchy doesn't
* contain {@link R.id.keyguard_message_area_container}.
@@ -96,23 +89,11 @@
mContainer.setLayoutParams(lp);
}
- @Override
- public void setNextMessageColor(ColorStateList colorState) {
- mNextMessageColorState = colorState;
- }
-
- void onThemeChanged() {
- TypedArray array = mContext.obtainStyledAttributes(new int[] {
- android.R.attr.textColorPrimary
- });
- ColorStateList newTextColors = ColorStateList.valueOf(array.getColor(0, Color.RED));
- array.recycle();
- mDefaultColorState = newTextColors;
+ protected void onThemeChanged() {
update();
}
- void reloadColor() {
- mDefaultColorState = Utils.getColorAttr(getContext(), android.R.attr.textColorPrimary);
+ protected void reloadColor() {
update();
}
@@ -151,17 +132,6 @@
setMessage(message);
}
- public static KeyguardMessageArea findSecurityMessageDisplay(View v) {
- KeyguardMessageArea messageArea = v.findViewById(R.id.keyguard_message_area);
- if (messageArea == null) {
- messageArea = v.getRootView().findViewById(R.id.keyguard_message_area);
- }
- if (messageArea == null) {
- throw new RuntimeException("Can't find keyguard_message_area in " + v.getClass());
- }
- return messageArea;
- }
-
private void securityMessageChanged(CharSequence message) {
mMessage = message;
update();
@@ -177,40 +147,23 @@
void update() {
CharSequence status = mMessage;
- setVisibility(TextUtils.isEmpty(status) || (!mBouncerShowing && !mAltBouncerShowing)
- ? INVISIBLE : VISIBLE);
+ setVisibility(TextUtils.isEmpty(status) || (!mIsVisible) ? INVISIBLE : VISIBLE);
setText(status);
- ColorStateList colorState = mDefaultColorState;
- if (mNextMessageColorState.getDefaultColor() != DEFAULT_COLOR) {
- colorState = mNextMessageColorState;
- mNextMessageColorState = ColorStateList.valueOf(DEFAULT_COLOR);
- }
- if (mAltBouncerShowing) {
- // alt bouncer has a black scrim, so always show the text in white
- colorState = ColorStateList.valueOf(Color.WHITE);
- }
- setTextColor(colorState);
+ updateTextColor();
}
/**
* Set whether the bouncer is fully showing
*/
- public void setBouncerShowing(boolean bouncerShowing) {
- if (mBouncerShowing != bouncerShowing) {
- mBouncerShowing = bouncerShowing;
+ public void setIsVisible(boolean isVisible) {
+ if (mIsVisible != isVisible) {
+ mIsVisible = isVisible;
update();
}
}
- /**
- * Set whether the alt bouncer is showing
- */
- void setAltBouncerShowing(boolean showing) {
- if (mAltBouncerShowing != showing) {
- mAltBouncerShowing = showing;
- update();
- }
- }
+ /** Set the text color */
+ protected abstract void updateTextColor();
/**
* Runnable used to delay accessibility announcements.
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java
index 3ec8ce9..c2802f7 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java
@@ -26,11 +26,14 @@
import javax.inject.Inject;
-/** Controller for a {@link KeyguardMessageAreaController}. */
-public class KeyguardMessageAreaController extends ViewController<KeyguardMessageArea> {
+/**
+ * Controller for a {@link KeyguardMessageAreaController}.
+ * @param <T> A subclass of KeyguardMessageArea.
+ */
+public class KeyguardMessageAreaController<T extends KeyguardMessageArea>
+ extends ViewController<T> {
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private final ConfigurationController mConfigurationController;
- private boolean mAltBouncerShowing;
private KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() {
public void onFinishedGoingToSleep(int why) {
@@ -59,7 +62,7 @@
}
};
- private KeyguardMessageAreaController(KeyguardMessageArea view,
+ protected KeyguardMessageAreaController(T view,
KeyguardUpdateMonitor keyguardUpdateMonitor,
ConfigurationController configurationController) {
super(view);
@@ -83,17 +86,10 @@
}
/**
- * Set whether alt bouncer is showing
+ * Indicate that view is visible and can display messages.
*/
- public void setAltBouncerShowing(boolean showing) {
- mView.setAltBouncerShowing(showing);
- }
-
- /**
- * Set bouncer is fully showing
- */
- public void setBouncerShowing(boolean showing) {
- mView.setBouncerShowing(showing);
+ public void setIsVisible(boolean isVisible) {
+ mView.setIsVisible(isVisible);
}
public void setMessage(CharSequence s) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
index 6844b65..453072b 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
@@ -16,23 +16,25 @@
package com.android.keyguard;
-import static com.android.internal.jank.InteractionJankMonitor.CUJ_LOCKSCREEN_PIN_APPEAR;
import static com.android.internal.jank.InteractionJankMonitor.CUJ_LOCKSCREEN_PIN_DISAPPEAR;
import static com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_HALF_OPENED;
import static com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_UNKNOWN;
+import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.Configuration;
import android.util.AttributeSet;
+import android.util.MathUtils;
import android.view.View;
import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.constraintlayout.widget.ConstraintSet;
-import com.android.settingslib.animation.AppearAnimationUtils;
import com.android.settingslib.animation.DisappearAnimationUtils;
import com.android.systemui.R;
+import com.android.systemui.animation.Interpolators;
import com.android.systemui.statusbar.policy.DevicePostureController.DevicePostureInt;
/**
@@ -40,12 +42,15 @@
*/
public class KeyguardPINView extends KeyguardPinBasedInputView {
- private final AppearAnimationUtils mAppearAnimationUtils;
+ ValueAnimator mAppearAnimator = ValueAnimator.ofFloat(0f, 1f);
private final DisappearAnimationUtils mDisappearAnimationUtils;
private final DisappearAnimationUtils mDisappearAnimationUtilsLocked;
private ConstraintLayout mContainer;
private int mDisappearYTranslation;
private View[][] mViews;
+ private int mYTrans;
+ private int mYTransOffset;
+ private View mBouncerMessageView;
@DevicePostureInt private int mLastDevicePosture = DEVICE_POSTURE_UNKNOWN;
public KeyguardPINView(Context context) {
@@ -54,7 +59,6 @@
public KeyguardPINView(Context context, AttributeSet attrs) {
super(context, attrs);
- mAppearAnimationUtils = new AppearAnimationUtils(context);
mDisappearAnimationUtils = new DisappearAnimationUtils(context,
125, 0.6f /* translationScale */,
0.45f /* delayScale */, AnimationUtils.loadInterpolator(
@@ -66,6 +70,8 @@
mContext, android.R.interpolator.fast_out_linear_in));
mDisappearYTranslation = getResources().getDimensionPixelSize(
R.dimen.disappear_y_translation);
+ mYTrans = getResources().getDimensionPixelSize(R.dimen.pin_view_trans_y_entry);
+ mYTransOffset = getResources().getDimensionPixelSize(R.dimen.pin_view_trans_y_entry_offset);
}
@Override
@@ -137,6 +143,7 @@
super.onFinishInflate();
mContainer = findViewById(R.id.pin_container);
+ mBouncerMessageView = findViewById(R.id.bouncer_message_area);
mViews = new View[][]{
new View[]{
findViewById(R.id.row0), null, null
@@ -169,25 +176,20 @@
@Override
public void startAppearAnimation() {
- enableClipping(false);
- setAlpha(1f);
- setTranslationY(mAppearAnimationUtils.getStartTranslation());
- AppearAnimationUtils.startTranslationYAnimation(this, 0 /* delay */, 500 /* duration */,
- 0, mAppearAnimationUtils.getInterpolator(),
- getAnimationListener(CUJ_LOCKSCREEN_PIN_APPEAR));
- mAppearAnimationUtils.startAnimation2d(mViews,
- new Runnable() {
- @Override
- public void run() {
- enableClipping(true);
- }
- });
+ if (mAppearAnimator.isRunning()) {
+ mAppearAnimator.cancel();
+ }
+ mAppearAnimator.setDuration(650);
+ mAppearAnimator.addUpdateListener(animation -> animate(animation.getAnimatedFraction()));
+ mAppearAnimator.start();
}
public boolean startDisappearAnimation(boolean needsSlowUnlockTransition,
final Runnable finishRunnable) {
+ if (mAppearAnimator.isRunning()) {
+ mAppearAnimator.cancel();
+ }
- enableClipping(false);
setTranslationY(0);
DisappearAnimationUtils disappearAnimationUtils = needsSlowUnlockTransition
? mDisappearAnimationUtilsLocked
@@ -195,7 +197,6 @@
disappearAnimationUtils.createAnimation(
this, 0, 200, mDisappearYTranslation, false,
mDisappearAnimationUtils.getInterpolator(), () -> {
- enableClipping(true);
if (finishRunnable != null) {
finishRunnable.run();
}
@@ -204,14 +205,39 @@
return true;
}
- private void enableClipping(boolean enable) {
- mContainer.setClipToPadding(enable);
- mContainer.setClipChildren(enable);
- setClipChildren(enable);
- }
-
@Override
public boolean hasOverlappingRendering() {
return false;
}
+
+ /** Animate subviews according to expansion or time. */
+ private void animate(float progress) {
+ Interpolator standardDecelerate = Interpolators.STANDARD_DECELERATE;
+ Interpolator legacyDecelerate = Interpolators.LEGACY_DECELERATE;
+
+ mBouncerMessageView.setTranslationY(
+ mYTrans - mYTrans * standardDecelerate.getInterpolation(progress));
+
+ for (int i = 0; i < mViews.length; i++) {
+ View[] row = mViews[i];
+ for (View view : row) {
+ if (view == null) {
+ continue;
+ }
+
+ float scaledProgress = legacyDecelerate.getInterpolation(MathUtils.constrain(
+ (progress - 0.075f * i) / (1f - 0.075f * mViews.length),
+ 0f,
+ 1f
+ ));
+ view.setAlpha(scaledProgress);
+ int yDistance = mYTrans + mYTransOffset * i;
+ view.setTranslationY(
+ yDistance - (yDistance * standardDecelerate.getInterpolation(progress)));
+ if (view instanceof NumPadAnimationListener) {
+ ((NumPadAnimationListener) view).setProgress(scaledProgress);
+ }
+ }
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
index 1862fc7..afc2590 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
@@ -71,7 +71,7 @@
*/
private long mLastPokeTime = -UNLOCK_PATTERN_WAKE_INTERVAL_MS;
- KeyguardMessageArea mSecurityMessageDisplay;
+ BouncerKeyguardMessageArea mSecurityMessageDisplay;
private View mEcaView;
private ConstraintLayout mContainer;
@@ -120,7 +120,7 @@
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
- mSecurityMessageDisplay = KeyguardMessageArea.findSecurityMessageDisplay(this);
+ mSecurityMessageDisplay = findViewById(R.id.bouncer_message_area);
}
@Override
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
index 9aa6f03..9871645 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
@@ -59,12 +59,9 @@
private final LatencyTracker mLatencyTracker;
private final FalsingCollector mFalsingCollector;
private final EmergencyButtonController mEmergencyButtonController;
- private final KeyguardMessageAreaController.Factory mMessageAreaControllerFactory;
private final DevicePostureController mPostureController;
private final DevicePostureController.Callback mPostureCallback =
posture -> mView.onDevicePostureChanged(posture);
-
- private KeyguardMessageAreaController mMessageAreaController;
private LockPatternView mLockPatternView;
private CountDownTimer mCountdownTimer;
private AsyncTask<?, ?, ?> mPendingLockCheck;
@@ -201,15 +198,13 @@
EmergencyButtonController emergencyButtonController,
KeyguardMessageAreaController.Factory messageAreaControllerFactory,
DevicePostureController postureController) {
- super(view, securityMode, keyguardSecurityCallback, emergencyButtonController);
+ super(view, securityMode, keyguardSecurityCallback, emergencyButtonController,
+ messageAreaControllerFactory);
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mLockPatternUtils = lockPatternUtils;
mLatencyTracker = latencyTracker;
mFalsingCollector = falsingCollector;
mEmergencyButtonController = emergencyButtonController;
- mMessageAreaControllerFactory = messageAreaControllerFactory;
- KeyguardMessageArea kma = KeyguardMessageArea.findSecurityMessageDisplay(mView);
- mMessageAreaController = mMessageAreaControllerFactory.create(kma);
mLockPatternView = mView.findViewById(R.id.lockPatternView);
mPostureController = postureController;
}
@@ -217,7 +212,6 @@
@Override
public void onInit() {
super.onInit();
- mMessageAreaController.init();
}
@Override
@@ -346,6 +340,9 @@
@Override
public void showMessage(CharSequence message, ColorStateList colorState) {
+ if (mMessageAreaController == null) {
+ return;
+ }
if (colorState != null) {
mMessageAreaController.setNextMessageColor(colorState);
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java
index 9f4585f..89fcc47 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java
@@ -82,6 +82,12 @@
}
@Override
+ public void startAppearAnimation() {
+ mMessageAreaController.setMessageIfEmpty(R.string.keyguard_enter_your_pin);
+ super.startAppearAnimation();
+ }
+
+ @Override
public boolean startDisappearAnimation(Runnable finishRunnable) {
return mView.startDisappearAnimation(
mKeyguardUpdateMonitor.needsSlowUnlockTransition(), finishRunnable);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index d0baf3d..f73c98e 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -665,7 +665,8 @@
// When using EXACTLY spec, measure will use the layout width if > 0. Set before
// measuring the child
lp.width = MeasureSpec.getSize(updatedWidthMeasureSpec);
- measureChildWithMargins(view, updatedWidthMeasureSpec, 0, heightMeasureSpec, 0);
+ measureChildWithMargins(view, updatedWidthMeasureSpec, 0,
+ heightMeasureSpec, 0);
maxWidth = Math.max(maxWidth,
view.getMeasuredWidth() + lp.leftMargin + lp.rightMargin);
@@ -1306,7 +1307,6 @@
int yTrans = mResources.getDimensionPixelSize(R.dimen.bouncer_user_switcher_y_trans);
if (mResources.getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
mUserSwitcherViewGroup.setTranslationY(yTrans);
- mViewFlipper.setTranslationY(-yTrans);
} else {
// Attempt to reposition a bit higher to make up for this frame being a bit lower
// on the device
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
index 93175e1..57058b7 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -223,7 +223,7 @@
@Override
public void onSwipeUp() {
if (!mUpdateMonitor.isFaceDetectionRunning()) {
- mUpdateMonitor.requestFaceAuth(true);
+ mUpdateMonitor.requestFaceAuth(true, FaceAuthApiRequestReason.SWIPE_UP_ON_BOUNCER);
mKeyguardSecurityCallback.userActivity();
showMessage(null, null);
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java
index 3aa5ada..bddf4b0 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java
@@ -146,7 +146,8 @@
protected NullKeyguardInputViewController(SecurityMode securityMode,
KeyguardSecurityCallback keyguardSecurityCallback,
EmergencyButtonController emergencyButtonController) {
- super(null, securityMode, keyguardSecurityCallback, emergencyButtonController);
+ super(null, securityMode, keyguardSecurityCallback, emergencyButtonController,
+ null);
}
@Override
@@ -156,7 +157,6 @@
@Override
public void onStartingToHide() {
-
}
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUnfoldTransition.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardUnfoldTransition.kt
index acbea1b..7d6f377 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUnfoldTransition.kt
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUnfoldTransition.kt
@@ -50,12 +50,10 @@
viewsIdToTranslate =
setOf(
ViewIdToTranslate(R.id.keyguard_status_area, LEFT, filterNever),
- ViewIdToTranslate(R.id.controls_button, LEFT, filterNever),
ViewIdToTranslate(R.id.lockscreen_clock_view_large, LEFT, filterSplitShadeOnly),
ViewIdToTranslate(R.id.lockscreen_clock_view, LEFT, filterNever),
ViewIdToTranslate(
R.id.notification_stack_scroller, RIGHT, filterSplitShadeOnly),
- ViewIdToTranslate(R.id.wallet_button, RIGHT, filterNever),
ViewIdToTranslate(R.id.start_button, LEFT, filterNever),
ViewIdToTranslate(R.id.end_button, RIGHT, filterNever)),
progressProvider = unfoldProgressProvider)
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 167d8af..35ee3f7 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -16,6 +16,7 @@
package com.android.keyguard;
+import static android.app.StatusBarManager.SESSION_KEYGUARD;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.Intent.ACTION_USER_REMOVED;
@@ -25,6 +26,7 @@
import static android.hardware.biometrics.BiometricConstants.BIOMETRIC_LOCKOUT_PERMANENT;
import static android.hardware.biometrics.BiometricConstants.BIOMETRIC_LOCKOUT_TIMED;
import static android.hardware.biometrics.BiometricConstants.LockoutMode;
+import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_START;
import static android.os.BatteryManager.BATTERY_STATUS_UNKNOWN;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT;
@@ -32,11 +34,43 @@
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_TIMEOUT;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
+import static com.android.keyguard.FaceAuthReasonKt.apiRequestReasonToUiEvent;
+import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_STOPPED_DREAM_STARTED;
+import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_STOPPED_FACE_CANCEL_NOT_RECEIVED;
+import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_STOPPED_FINISHED_GOING_TO_SLEEP;
+import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_STOPPED_FP_LOCKED_OUT;
+import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_STOPPED_KEYGUARD_GOING_AWAY;
+import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_STOPPED_TRUST_ENABLED;
+import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_STOPPED_USER_INPUT_ON_BOUNCER;
+import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_TRIGGERED_ALL_AUTHENTICATORS_REGISTERED;
+import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_TRIGGERED_ALTERNATE_BIOMETRIC_BOUNCER_SHOWN;
+import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_TRIGGERED_DREAM_STOPPED;
+import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_TRIGGERED_DURING_CANCELLATION;
+import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_TRIGGERED_ENROLLMENTS_CHANGED;
+import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_TRIGGERED_FACE_LOCKOUT_RESET;
+import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_TRIGGERED_OCCLUDING_APP_REQUESTED;
+import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_TRIGGERED_ON_REACH_GESTURE_ON_AOD;
+import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_TRIGGERED_RETRY_AFTER_HW_UNAVAILABLE;
+import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_TRIGGERED_TRUST_DISABLED;
+import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_UPDATED_ASSISTANT_VISIBILITY_CHANGED;
+import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_UPDATED_BIOMETRIC_ENABLED_ON_KEYGUARD;
+import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_UPDATED_CAMERA_LAUNCHED;
+import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_UPDATED_FP_AUTHENTICATED;
+import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_UPDATED_GOING_TO_SLEEP;
+import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_UPDATED_KEYGUARD_OCCLUSION_CHANGED;
+import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_UPDATED_KEYGUARD_RESET;
+import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_UPDATED_KEYGUARD_VISIBILITY_CHANGED;
+import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_UPDATED_ON_FACE_AUTHENTICATED;
+import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_UPDATED_ON_KEYGUARD_INIT;
+import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_UPDATED_PRIMARY_BOUNCER_SHOWN;
+import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_UPDATED_STARTED_WAKING_UP;
+import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_UPDATED_USER_SWITCHING;
import static com.android.systemui.DejankUtils.whitelistIpcs;
import android.annotation.AnyThread;
import android.annotation.MainThread;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
import android.app.ActivityTaskManager.RootTaskInfo;
@@ -71,8 +105,10 @@
import android.os.IRemoteCallback;
import android.os.Looper;
import android.os.Message;
+import android.os.PowerManager;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.SystemClock;
import android.os.Trace;
import android.os.UserHandle;
import android.os.UserManager;
@@ -92,6 +128,8 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.jank.InteractionJankMonitor;
+import com.android.internal.logging.InstanceId;
+import com.android.internal.logging.UiEventLogger;
import com.android.internal.util.LatencyTracker;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.logging.KeyguardUpdateMonitorLogger;
@@ -105,6 +143,7 @@
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.log.SessionTracker;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.TaskStackChangeListeners;
@@ -130,6 +169,7 @@
import java.util.function.Consumer;
import javax.inject.Inject;
+import javax.inject.Provider;
/**
* Watches for updates that may be interesting to the keyguard, and provides
@@ -240,6 +280,7 @@
private final boolean mIsPrimaryUser;
private final AuthController mAuthController;
private final StatusBarStateController mStatusBarStateController;
+ private final UiEventLogger mUiEventLogger;
private int mStatusBarState;
private final StatusBarStateController.StateListener mStatusBarStateControllerListener =
new StatusBarStateController.StateListener() {
@@ -305,7 +346,6 @@
private KeyguardBypassController mKeyguardBypassController;
private int mFingerprintRunningState = BIOMETRIC_STATE_STOPPED;
private int mFaceRunningState = BIOMETRIC_STATE_STOPPED;
- private boolean mIsFaceAuthUserRequested;
private LockPatternUtils mLockPatternUtils;
private final IDreamManager mDreamManager;
private boolean mIsDreaming;
@@ -319,6 +359,8 @@
private final Executor mBackgroundExecutor;
private SensorPrivacyManager mSensorPrivacyManager;
private final ActiveUnlockConfig mActiveUnlockConfig;
+ private final PowerManager mPowerManager;
+ private final boolean mWakeOnFingerprintAcquiredStart;
/**
* Short delay before restarting fingerprint authentication after a successful try. This should
@@ -337,6 +379,7 @@
protected final Runnable mFpCancelNotReceived = this::onFingerprintCancelNotReceived;
private final Runnable mFaceCancelNotReceived = this::onFaceCancelNotReceived;
+ private final Provider<SessionTracker> mSessionTrackerProvider;
@VisibleForTesting
protected Handler getHandler() {
@@ -352,7 +395,8 @@
public void onChanged(boolean enabled, int userId) throws RemoteException {
mHandler.post(() -> {
mBiometricEnabledForUser.put(userId, enabled);
- updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
+ updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE,
+ FACE_AUTH_UPDATED_BIOMETRIC_ENABLED_ON_KEYGUARD);
});
}
};
@@ -420,11 +464,14 @@
// authenticating. TrustManager sends an onTrustChanged whenever a user unlocks keyguard,
// for this reason we need to make sure to not authenticate.
if (wasTrusted == enabled || enabled) {
- updateBiometricListeningState(BIOMETRIC_ACTION_STOP);
+ updateBiometricListeningState(BIOMETRIC_ACTION_STOP,
+ FACE_AUTH_STOPPED_TRUST_ENABLED);
} else {
- updateBiometricListeningState(BIOMETRIC_ACTION_START);
+ updateBiometricListeningState(BIOMETRIC_ACTION_START,
+ FACE_AUTH_TRIGGERED_TRUST_DISABLED);
}
+ mLogger.logTrustChanged(wasTrusted, enabled, userId);
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
@@ -440,12 +487,16 @@
final boolean userHasTrust = getUserHasTrust(userId);
if (userHasTrust && trustGrantedMessages != null) {
for (String msg : trustGrantedMessages) {
- if (!TextUtils.isEmpty(msg)) {
- message = msg;
+ message = msg;
+ if (!TextUtils.isEmpty(message)) {
break;
}
}
}
+
+ if (message != null) {
+ mLogger.logShowTrustGrantedMessage(message.toString());
+ }
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
@@ -616,7 +667,7 @@
public void setKeyguardGoingAway(boolean goingAway) {
mKeyguardGoingAway = goingAway;
// This is set specifically to stop face authentication from running.
- updateBiometricListeningState(BIOMETRIC_ACTION_STOP);
+ updateBiometricListeningState(BIOMETRIC_ACTION_STOP, FACE_AUTH_STOPPED_KEYGUARD_GOING_AWAY);
}
/**
@@ -624,7 +675,8 @@
*/
public void setKeyguardOccluded(boolean occluded) {
mKeyguardOccluded = occluded;
- updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
+ updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE,
+ FACE_AUTH_UPDATED_KEYGUARD_OCCLUSION_CHANGED);
}
@@ -636,7 +688,8 @@
*/
public void requestFaceAuthOnOccludingApp(boolean request) {
mOccludingAppRequestingFace = request;
- updateFaceListeningState(BIOMETRIC_ACTION_UPDATE);
+ updateFaceListeningState(BIOMETRIC_ACTION_UPDATE,
+ FACE_AUTH_TRIGGERED_OCCLUDING_APP_REQUESTED);
}
/**
@@ -655,7 +708,8 @@
*/
public void onCameraLaunched() {
mSecureCameraLaunched = true;
- updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
+ updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE,
+ FACE_AUTH_UPDATED_CAMERA_LAUNCHED);
}
/**
@@ -697,7 +751,9 @@
}
// Don't send cancel if authentication succeeds
mFingerprintCancelSignal = null;
- updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
+ updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE,
+ FACE_AUTH_UPDATED_FP_AUTHENTICATED);
+ mLogger.d("onFingerprintAuthenticated");
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
@@ -754,6 +810,11 @@
private void handleFingerprintAcquired(
@BiometricFingerprintConstants.FingerprintAcquired int acquireInfo) {
Assert.isMainThread();
+ if (mWakeOnFingerprintAcquiredStart && acquireInfo == FINGERPRINT_ACQUIRED_START) {
+ mPowerManager.wakeUp(
+ SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_GESTURE,
+ "com.android.systemui.keyguard:FINGERPRINT_ACQUIRED_START");
+ }
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
@@ -860,7 +921,7 @@
if (isUdfpsEnrolled()) {
updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE);
}
- stopListeningForFace();
+ stopListeningForFace(FACE_AUTH_STOPPED_FP_LOCKED_OUT);
}
for (int i = 0; i < mCallbacks.size(); i++) {
@@ -939,7 +1000,9 @@
}
// Don't send cancel if authentication succeeds
mFaceCancelSignal = null;
- updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
+ updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE,
+ FACE_AUTH_UPDATED_ON_FACE_AUTHENTICATED);
+ mLogger.d("onFaceAuthenticated");
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
@@ -1028,14 +1091,16 @@
@Override
public void run() {
mLogger.logRetryingAfterFaceHwUnavailable(mHardwareFaceUnavailableRetryCount);
- updateFaceListeningState(BIOMETRIC_ACTION_UPDATE);
+ updateFaceListeningState(BIOMETRIC_ACTION_UPDATE,
+ FACE_AUTH_TRIGGERED_RETRY_AFTER_HW_UNAVAILABLE);
}
};
private void onFaceCancelNotReceived() {
mLogger.e("Face cancellation not received, transitioning to STOPPED");
mFaceRunningState = BIOMETRIC_STATE_STOPPED;
- KeyguardUpdateMonitor.this.updateFaceListeningState(BIOMETRIC_ACTION_STOP);
+ KeyguardUpdateMonitor.this.updateFaceListeningState(BIOMETRIC_ACTION_STOP,
+ FACE_AUTH_STOPPED_FACE_CANCEL_NOT_RECEIVED);
}
private void handleFaceError(int msgId, final String originalErrMsg) {
@@ -1058,7 +1123,8 @@
if (msgId == FaceManager.FACE_ERROR_CANCELED
&& mFaceRunningState == BIOMETRIC_STATE_CANCELLING_RESTARTING) {
setFaceRunningState(BIOMETRIC_STATE_STOPPED);
- updateFaceListeningState(BIOMETRIC_ACTION_UPDATE);
+ updateFaceListeningState(BIOMETRIC_ACTION_UPDATE,
+ FACE_AUTH_TRIGGERED_DURING_CANCELLATION);
} else {
setFaceRunningState(BIOMETRIC_STATE_STOPPED);
}
@@ -1104,7 +1170,8 @@
final boolean changed = (mFaceLockedOutPermanent != wasLockoutPermanent);
mHandler.postDelayed(() -> {
- updateFaceListeningState(BIOMETRIC_ACTION_UPDATE);
+ updateFaceListeningState(BIOMETRIC_ACTION_UPDATE,
+ FACE_AUTH_TRIGGERED_FACE_LOCKOUT_RESET);
}, getBiometricLockoutDelay());
if (changed) {
@@ -1349,7 +1416,8 @@
@VisibleForTesting
void setAssistantVisible(boolean assistantVisible) {
mAssistantVisible = assistantVisible;
- updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
+ updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE,
+ FACE_AUTH_UPDATED_ASSISTANT_VISIBILITY_CHANGED);
if (mAssistantVisible) {
requestActiveUnlock(
ActiveUnlockConfig.ACTIVE_UNLOCK_REQUEST_ORIGIN.ASSISTANT,
@@ -1527,7 +1595,7 @@
@Override
public void onUdfpsPointerDown(int sensorId) {
mLogger.logUdfpsPointerDown(sensorId);
- requestFaceAuth(true);
+ requestFaceAuth(true, FaceAuthApiRequestReason.UDFPS_POINTER_DOWN);
}
/**
@@ -1711,7 +1779,7 @@
protected void handleStartedWakingUp() {
Trace.beginSection("KeyguardUpdateMonitor#handleStartedWakingUp");
Assert.isMainThread();
- updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
+ updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE, FACE_AUTH_UPDATED_STARTED_WAKING_UP);
requestActiveUnlock(ActiveUnlockConfig.ACTIVE_UNLOCK_REQUEST_ORIGIN.WAKE, "wakingUp");
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
@@ -1732,7 +1800,7 @@
}
}
mGoingToSleep = true;
- updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
+ updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE, FACE_AUTH_UPDATED_GOING_TO_SLEEP);
}
protected void handleFinishedGoingToSleep(int arg1) {
@@ -1745,7 +1813,8 @@
}
}
// This is set specifically to stop face authentication from running.
- updateBiometricListeningState(BIOMETRIC_ACTION_STOP);
+ updateBiometricListeningState(BIOMETRIC_ACTION_STOP,
+ FACE_AUTH_STOPPED_FINISHED_GOING_TO_SLEEP);
}
private void handleScreenTurnedOff() {
@@ -1765,9 +1834,10 @@
}
if (mIsDreaming) {
updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE);
- updateFaceListeningState(BIOMETRIC_ACTION_STOP);
+ updateFaceListeningState(BIOMETRIC_ACTION_STOP, FACE_AUTH_STOPPED_DREAM_STARTED);
} else {
- updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
+ updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE,
+ FACE_AUTH_TRIGGERED_DREAM_STOPPED);
}
}
@@ -1832,8 +1902,11 @@
InteractionJankMonitor interactionJankMonitor,
LatencyTracker latencyTracker,
ActiveUnlockConfig activeUnlockConfiguration,
- KeyguardUpdateMonitorLogger logger) {
- mLogger = logger;
+ KeyguardUpdateMonitorLogger logger,
+ UiEventLogger uiEventLogger,
+ // This has to be a provider because SessionTracker depends on KeyguardUpdateMonitor :(
+ Provider<SessionTracker> sessionTrackerProvider,
+ PowerManager powerManager) {
mContext = context;
mSubscriptionManager = SubscriptionManager.from(context);
mTelephonyListenerManager = telephonyListenerManager;
@@ -1851,7 +1924,13 @@
dumpManager.registerDumpable(getClass().getName(), this);
mSensorPrivacyManager = context.getSystemService(SensorPrivacyManager.class);
mActiveUnlockConfig = activeUnlockConfiguration;
+ mLogger = logger;
+ mUiEventLogger = uiEventLogger;
+ mSessionTrackerProvider = sessionTrackerProvider;
+ mPowerManager = powerManager;
mActiveUnlockConfig.setKeyguardUpdateMonitor(this);
+ mWakeOnFingerprintAcquiredStart = context.getResources()
+ .getBoolean(com.android.internal.R.bool.kg_wake_on_acquire_start);
mHandler = new Handler(mainLooper) {
@Override
@@ -1934,7 +2013,8 @@
setAssistantVisible((boolean) msg.obj);
break;
case MSG_BIOMETRIC_AUTHENTICATION_CONTINUE:
- updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
+ updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE,
+ FACE_AUTH_UPDATED_FP_AUTHENTICATED);
break;
case MSG_DEVICE_POLICY_MANAGER_STATE_CHANGED:
updateLogoutEnabled();
@@ -2036,15 +2116,17 @@
mAuthController.addCallback(new AuthController.Callback() {
@Override
public void onAllAuthenticatorsRegistered() {
- mainExecutor.execute(() -> updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE));
+ mainExecutor.execute(() -> updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE,
+ FACE_AUTH_TRIGGERED_ALL_AUTHENTICATORS_REGISTERED));
}
@Override
public void onEnrollmentsChanged() {
- mainExecutor.execute(() -> updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE));
+ mainExecutor.execute(() -> updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE,
+ FACE_AUTH_TRIGGERED_ENROLLMENTS_CHANGED));
}
});
- updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
+ updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE, FACE_AUTH_UPDATED_ON_KEYGUARD_INIT);
if (mFpm != null) {
mFpm.addLockoutResetCallback(mFingerprintLockoutResetCallback);
}
@@ -2156,9 +2238,10 @@
mHandler.sendEmptyMessage(MSG_AIRPLANE_MODE_CHANGED);
}
- private void updateBiometricListeningState(int action) {
+ private void updateBiometricListeningState(int action,
+ @NonNull FaceAuthUiEvent faceAuthUiEvent) {
updateFingerprintListeningState(action);
- updateFaceListeningState(action);
+ updateFaceListeningState(action, faceAuthUiEvent);
}
private void updateFingerprintListeningState(int action) {
@@ -2214,7 +2297,8 @@
return;
}
mAuthInterruptActive = active;
- updateFaceListeningState(BIOMETRIC_ACTION_UPDATE);
+ updateFaceListeningState(BIOMETRIC_ACTION_UPDATE,
+ FACE_AUTH_TRIGGERED_ON_REACH_GESTURE_ON_AOD);
requestActiveUnlock(ActiveUnlockConfig.ACTIVE_UNLOCK_REQUEST_ORIGIN.WAKE, "onReach");
}
@@ -2222,25 +2306,27 @@
* Requests face authentication if we're on a state where it's allowed.
* This will re-trigger auth in case it fails.
* @param userInitiatedRequest true if the user explicitly requested face auth
+ * @param reason One of the reasons {@link FaceAuthApiRequestReason} on why this API is being
+ * invoked.
*/
- public void requestFaceAuth(boolean userInitiatedRequest) {
+ public void requestFaceAuth(boolean userInitiatedRequest,
+ @FaceAuthApiRequestReason String reason) {
mLogger.logFaceAuthRequested(userInitiatedRequest);
- mIsFaceAuthUserRequested |= userInitiatedRequest;
- updateFaceListeningState(BIOMETRIC_ACTION_START);
+ updateFaceListeningState(BIOMETRIC_ACTION_START, apiRequestReasonToUiEvent(reason));
}
/**
* In case face auth is running, cancel it.
*/
public void cancelFaceAuth() {
- stopListeningForFace();
+ stopListeningForFace(FACE_AUTH_STOPPED_USER_INPUT_ON_BOUNCER);
}
public boolean isFaceScanning() {
return mFaceRunningState == BIOMETRIC_STATE_RUNNING;
}
- private void updateFaceListeningState(int action) {
+ private void updateFaceListeningState(int action, @NonNull FaceAuthUiEvent faceAuthUiEvent) {
// If this message exists, we should not authenticate again until this message is
// consumed by the handler
if (mHandler.hasMessages(MSG_BIOMETRIC_AUTHENTICATION_CONTINUE)) {
@@ -2253,17 +2339,21 @@
mLogger.v("Ignoring stopListeningForFace()");
return;
}
- mIsFaceAuthUserRequested = false;
- stopListeningForFace();
+ stopListeningForFace(faceAuthUiEvent);
} else if (mFaceRunningState != BIOMETRIC_STATE_RUNNING && shouldListenForFace) {
if (action == BIOMETRIC_ACTION_STOP) {
mLogger.v("Ignoring startListeningForFace()");
return;
}
- startListeningForFace();
+ startListeningForFace(faceAuthUiEvent);
}
}
+ @Nullable
+ private InstanceId getKeyguardSessionId() {
+ return mSessionTrackerProvider.get().getSessionId(SESSION_KEYGUARD);
+ }
+
/**
* Initiates active unlock to get the unlock token ready.
*/
@@ -2332,7 +2422,8 @@
public void setUdfpsBouncerShowing(boolean showing) {
mUdfpsBouncerShowing = showing;
if (mUdfpsBouncerShowing) {
- updateFaceListeningState(BIOMETRIC_ACTION_START);
+ updateFaceListeningState(BIOMETRIC_ACTION_START,
+ FACE_AUTH_TRIGGERED_ALTERNATE_BIOMETRIC_BOUNCER_SHOWN);
requestActiveUnlock(
ActiveUnlockConfig.ACTIVE_UNLOCK_REQUEST_ORIGIN.UNLOCK_INTENT,
"udfpsBouncer");
@@ -2494,7 +2585,7 @@
// on bouncer if both fp and fingerprint are enrolled.
final boolean awakeKeyguardExcludingBouncerShowing = mKeyguardIsVisible
&& mDeviceInteractive && !mGoingToSleep
- && !statusBarShadeLocked && !mBouncerFullyShown;
+ && !statusBarShadeLocked && !mBouncerIsOrWillBeShowing;
final int user = getCurrentUser();
final int strongAuth = mStrongAuthTracker.getStrongAuthForUser(user);
final boolean isLockDown =
@@ -2563,6 +2654,7 @@
becauseCannotSkipBouncer,
biometricEnabledForUser,
mBouncerFullyShown,
+ mBouncerIsOrWillBeShowing,
faceAuthenticated,
faceDisabledForUser,
mGoingToSleep,
@@ -2644,7 +2736,7 @@
}
}
- private void startListeningForFace() {
+ private void startListeningForFace(@NonNull FaceAuthUiEvent faceAuthUiEvent) {
final int userId = getCurrentUser();
final boolean unlockPossible = isUnlockWithFacePossible(userId);
if (mFaceCancelSignal != null) {
@@ -2658,7 +2750,8 @@
// Waiting for ERROR_CANCELED before requesting auth again
return;
}
- mLogger.logStartedListeningForFace(mFaceRunningState);
+ mLogger.logStartedListeningForFace(mFaceRunningState, faceAuthUiEvent.getReason());
+ mUiEventLogger.log(faceAuthUiEvent, getKeyguardSessionId());
if (unlockPossible) {
mFaceCancelSignal = new CancellationSignal();
@@ -2742,8 +2835,10 @@
}
}
- private void stopListeningForFace() {
+ private void stopListeningForFace(@NonNull FaceAuthUiEvent faceAuthUiEvent) {
mLogger.v("stopListeningForFace()");
+ mLogger.logStoppedListeningForFace(mFaceRunningState, faceAuthUiEvent.getReason());
+ mUiEventLogger.log(faceAuthUiEvent, getKeyguardSessionId());
if (mFaceRunningState == BIOMETRIC_STATE_RUNNING) {
if (mFaceCancelSignal != null) {
mFaceCancelSignal.cancel();
@@ -3072,7 +3167,8 @@
cb.onKeyguardVisibilityChangedRaw(showing);
}
}
- updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
+ updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE,
+ FACE_AUTH_UPDATED_KEYGUARD_VISIBILITY_CHANGED);
}
/**
@@ -3080,7 +3176,8 @@
*/
private void handleKeyguardReset() {
mLogger.d("handleKeyguardReset");
- updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
+ updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE,
+ FACE_AUTH_UPDATED_KEYGUARD_RESET);
mNeedsSlowUnlockTransition = resolveNeedsSlowUnlockTransition();
}
@@ -3131,7 +3228,8 @@
cb.onKeyguardBouncerStateChanged(mBouncerIsOrWillBeShowing);
}
}
- updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE);
+ updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE,
+ FaceAuthUiEvent.FACE_AUTH_UPDATED_PRIMARY_BOUNCER_SHOWN_OR_WILL_BE_SHOWN);
}
if (wasBouncerFullyShown != mBouncerFullyShown) {
@@ -3146,7 +3244,8 @@
cb.onKeyguardBouncerFullyShowingChanged(mBouncerFullyShown);
}
}
- updateFaceListeningState(BIOMETRIC_ACTION_UPDATE);
+ updateFaceListeningState(BIOMETRIC_ACTION_UPDATE,
+ FACE_AUTH_UPDATED_PRIMARY_BOUNCER_SHOWN);
}
}
@@ -3274,7 +3373,8 @@
mSwitchingUser = switching;
// Since this comes in on a binder thread, we need to post if first
mHandler.post(() -> {
- updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
+ updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE,
+ FACE_AUTH_UPDATED_USER_SWITCHING);
});
}
@@ -3366,6 +3466,7 @@
mUserFaceAuthenticated.clear();
mTrustManager.clearAllBiometricRecognized(BiometricSourceType.FINGERPRINT, unlockedUser);
mTrustManager.clearAllBiometricRecognized(BiometricSourceType.FACE, unlockedUser);
+ mLogger.d("clearBiometricRecognized");
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
@@ -3615,6 +3716,10 @@
@Override
public void dump(PrintWriter pw, String[] args) {
pw.println("KeyguardUpdateMonitor state:");
+ pw.println(" getUserHasTrust()=" + getUserHasTrust(getCurrentUser()));
+ pw.println(" getUserUnlockedWithBiometric()="
+ + getUserUnlockedWithBiometric(getCurrentUser()));
+ pw.println(" mWakeOnFingerprintAcquiredStart=" + mWakeOnFingerprintAcquiredStart);
pw.println(" SIM States:");
for (SimData data : mSimDatas.values()) {
pw.println(" " + data.toString());
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeConstants.java b/packages/SystemUI/src/com/android/keyguard/NumPadAnimationListener.kt
similarity index 61%
copy from libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeConstants.java
copy to packages/SystemUI/src/com/android/keyguard/NumPadAnimationListener.kt
index e62a63a..f449edf 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeConstants.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadAnimationListener.kt
@@ -14,18 +14,10 @@
* limitations under the License.
*/
-package com.android.wm.shell.desktopmode;
+package com.android.keyguard
-import android.os.SystemProperties;
-
-/**
- * Constants for desktop mode feature
- */
-public class DesktopModeConstants {
-
- /**
- * Flag to indicate whether desktop mode is available on the device
- */
- public static final boolean IS_FEATURE_ENABLED = SystemProperties.getBoolean(
- "persist.wm.debug.desktop_mode", false);
+/** Interface for classes to track animation progress. */
+interface NumPadAnimationListener {
+ /** Track the progress of the animation. */
+ fun setProgress(progress: Float)
}
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java b/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java
index c91c899..41111e3 100644
--- a/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java
@@ -48,6 +48,10 @@
private int mTextColorPrimary;
private int mTextColorPressed;
private int mStyle;
+ private float mStartRadius;
+ private float mEndRadius;
+ private int mHeight;
+
private static final int EXPAND_ANIMATION_MS = 100;
private static final int EXPAND_COLOR_ANIMATION_MS = 50;
private static final int CONTRACT_ANIMATION_DELAY_MS = 33;
@@ -80,12 +84,20 @@
mContractAnimatorSet.start();
}
+ public void setProgress(float progress) {
+ mBackground.setCornerRadius(mEndRadius + (mStartRadius - mEndRadius) * progress);
+ int height = (int) (mHeight * 0.7f + mHeight * 0.3 * progress);
+ int difference = mHeight - height;
+ mBackground.setBounds(0, difference / 2, mHeight, mHeight - difference / 2);
+ }
+
void onLayout(int height) {
- float startRadius = height / 2f;
- float endRadius = height / 4f;
- mBackground.setCornerRadius(startRadius);
- mExpandAnimator.setFloatValues(startRadius, endRadius);
- mContractAnimator.setFloatValues(endRadius, startRadius);
+ mHeight = height;
+ mStartRadius = height / 2f;
+ mEndRadius = height / 4f;
+ mBackground.setCornerRadius(mStartRadius);
+ mExpandAnimator.setFloatValues(mStartRadius, mEndRadius);
+ mContractAnimator.setFloatValues(mEndRadius, mStartRadius);
}
/**
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadButton.java b/packages/SystemUI/src/com/android/keyguard/NumPadButton.java
index 8099f75..37060987c 100644
--- a/packages/SystemUI/src/com/android/keyguard/NumPadButton.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadButton.java
@@ -30,7 +30,7 @@
/**
* Similar to the {@link NumPadKey}, but displays an image.
*/
-public class NumPadButton extends AlphaOptimizedImageButton {
+public class NumPadButton extends AlphaOptimizedImageButton implements NumPadAnimationListener {
@Nullable
private NumPadAnimator mAnimator;
@@ -104,4 +104,11 @@
a.recycle();
((VectorDrawable) getDrawable()).setTintList(ColorStateList.valueOf(imageColor));
}
+
+ @Override
+ public void setProgress(float progress) {
+ if (mAnimator != null) {
+ mAnimator.setProgress(progress);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
index 4aed251..0a4880e 100644
--- a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
@@ -37,7 +37,10 @@
import com.android.settingslib.Utils;
import com.android.systemui.R;
-public class NumPadKey extends ViewGroup {
+/**
+ * Viewgroup for the bouncer numpad button, specifically for digits.
+ */
+public class NumPadKey extends ViewGroup implements NumPadAnimationListener {
// list of "ABC", etc per digit, starting with '0'
static String sKlondike[];
@@ -221,4 +224,11 @@
performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY,
HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
}
+
+ @Override
+ public void setProgress(float progress) {
+ if (mAnimator != null) {
+ mAnimator.setProgress(progress);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/keyguard/SecurityMessageDisplay.java b/packages/SystemUI/src/com/android/keyguard/SecurityMessageDisplay.java
index 7c86a1d..777bd19 100644
--- a/packages/SystemUI/src/com/android/keyguard/SecurityMessageDisplay.java
+++ b/packages/SystemUI/src/com/android/keyguard/SecurityMessageDisplay.java
@@ -20,7 +20,8 @@
public interface SecurityMessageDisplay {
- void setNextMessageColor(ColorStateList colorState);
+ /** Set text color for the next security message. */
+ default void setNextMessageColor(ColorStateList colorState) {}
void setMessage(CharSequence msg);
diff --git a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
index d718a24..7a00cd9 100644
--- a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
+++ b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
@@ -262,10 +262,18 @@
logBuffer.log(TAG, VERBOSE, { int1 = subId }, { "reportSimUnlocked(subId=$int1)" })
}
- fun logStartedListeningForFace(faceRunningState: Int) {
- logBuffer.log(TAG, VERBOSE,
- { int1 = faceRunningState },
- { "startListeningForFace(): $int1" })
+ fun logStartedListeningForFace(faceRunningState: Int, faceAuthReason: String) {
+ logBuffer.log(TAG, VERBOSE, {
+ int1 = faceRunningState
+ str1 = faceAuthReason
+ }, { "startListeningForFace(): $int1, reason: $str1" })
+ }
+
+ fun logStoppedListeningForFace(faceRunningState: Int, faceAuthReason: String) {
+ logBuffer.log(TAG, VERBOSE, {
+ int1 = faceRunningState
+ str1 = faceAuthReason
+ }, { "stopListeningForFace(): currentFaceRunningState: $int1, reason: $str1" })
}
fun logSubInfo(subInfo: SubscriptionInfo?) {
@@ -332,4 +340,40 @@
bool1 = dismissKeyguard
}, { "reportUserRequestedUnlock origin=$str1 reason=$str2 dismissKeyguard=$bool1" })
}
+
+ fun logShowTrustGrantedMessage(
+ message: String
+ ) {
+ logBuffer.log(TAG, DEBUG, {
+ str1 = message
+ }, { "showTrustGrantedMessage message$str1" })
+ }
+
+ fun logTrustChanged(
+ wasTrusted: Boolean,
+ isNowTrusted: Boolean,
+ userId: Int
+ ) {
+ logBuffer.log(TAG, DEBUG, {
+ bool1 = wasTrusted
+ bool2 = isNowTrusted
+ int1 = userId
+ }, { "onTrustChanged[user=$int1] wasTrusted=$bool1 isNowTrusted=$bool2" })
+ }
+
+ fun logKeyguardStateUpdate(
+ secure: Boolean,
+ canDismissLockScreen: Boolean,
+ trusted: Boolean,
+ trustManaged: Boolean
+
+ ) {
+ logBuffer.log("KeyguardState", DEBUG, {
+ bool1 = secure
+ bool2 = canDismissLockScreen
+ bool3 = trusted
+ bool4 = trustManaged
+ }, { "#update secure=$bool1 canDismissKeyguard=$bool2" +
+ " trusted=$bool3 trustManaged=$bool4" })
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index 0cb4da4..7fc8123 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -85,8 +85,6 @@
import com.android.systemui.statusbar.VibratorHelper;
import com.android.systemui.statusbar.events.PrivacyDotViewController;
import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.notification.NotificationEntryManager.KeyguardEnvironment;
import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;
import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
@@ -301,7 +299,6 @@
@Inject Lazy<IStatusBarService> mIStatusBarService;
@Inject Lazy<DisplayMetrics> mDisplayMetrics;
@Inject Lazy<LockscreenGestureLogger> mLockscreenGestureLogger;
- @Inject Lazy<KeyguardEnvironment> mKeyguardEnvironment;
@Inject Lazy<ShadeController> mShadeController;
@Inject Lazy<NotificationRemoteInputManager.Callback> mNotificationRemoteInputManagerCallback;
@Inject Lazy<AppOpsController> mAppOpsController;
@@ -318,10 +315,8 @@
@Inject Lazy<KeyguardDismissUtil> mKeyguardDismissUtil;
@Inject Lazy<SmartReplyController> mSmartReplyController;
@Inject Lazy<RemoteInputQuickSettingsDisabler> mRemoteInputQuickSettingsDisabler;
- @Inject Lazy<NotificationEntryManager> mNotificationEntryManager;
@Inject Lazy<SensorPrivacyManager> mSensorPrivacyManager;
@Inject Lazy<AutoHideController> mAutoHideController;
- @Inject Lazy<ForegroundServiceNotificationListener> mForegroundServiceNotificationListener;
@Inject Lazy<PrivacyItemController> mPrivacyItemController;
@Inject @Background Lazy<Looper> mBgLooper;
@Inject @Background Lazy<Handler> mBgHandler;
@@ -503,7 +498,6 @@
mProviders.put(LockscreenGestureLogger.class, mLockscreenGestureLogger::get);
- mProviders.put(KeyguardEnvironment.class, mKeyguardEnvironment::get);
mProviders.put(ShadeController.class, mShadeController::get);
mProviders.put(NotificationRemoteInputManager.Callback.class,
@@ -530,9 +524,6 @@
mProviders.put(SmartReplyController.class, mSmartReplyController::get);
mProviders.put(RemoteInputQuickSettingsDisabler.class,
mRemoteInputQuickSettingsDisabler::get);
- mProviders.put(NotificationEntryManager.class, mNotificationEntryManager::get);
- mProviders.put(ForegroundServiceNotificationListener.class,
- mForegroundServiceNotificationListener::get);
mProviders.put(ClockManager.class, mClockManager::get);
mProviders.put(PrivacyItemController.class, mPrivacyItemController::get);
mProviders.put(ActivityManagerWrapper.class, mActivityManagerWrapper::get);
diff --git a/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java b/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java
index 04e26d3..a1a3b72 100644
--- a/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java
+++ b/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java
@@ -23,14 +23,10 @@
import android.service.notification.StatusBarNotification;
import android.util.Log;
-import com.android.internal.statusbar.NotificationVisibility;
import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.statusbar.notification.NotificationEntryListener;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
-import com.android.systemui.util.time.SystemClock;
import javax.inject.Inject;
@@ -43,42 +39,20 @@
private final Context mContext;
private final ForegroundServiceController mForegroundServiceController;
- private final NotificationEntryManager mEntryManager;
+ private final NotifPipeline mNotifPipeline;
@Inject
public ForegroundServiceNotificationListener(Context context,
ForegroundServiceController foregroundServiceController,
- NotificationEntryManager notificationEntryManager,
- NotifPipeline notifPipeline,
- SystemClock systemClock) {
+ NotifPipeline notifPipeline) {
mContext = context;
mForegroundServiceController = foregroundServiceController;
+ mNotifPipeline = notifPipeline;
+ }
- // TODO: (b/145659174) remove mEntryManager when moving to NewNotifPipeline. Replaced by
- // ForegroundCoordinator
- mEntryManager = notificationEntryManager;
- mEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
- @Override
- public void onPendingEntryAdded(NotificationEntry entry) {
- addNotification(entry, entry.getImportance());
- }
-
- @Override
- public void onPreEntryUpdated(NotificationEntry entry) {
- updateNotification(entry, entry.getImportance());
- }
-
- @Override
- public void onEntryRemoved(
- NotificationEntry entry,
- NotificationVisibility visibility,
- boolean removedByUser,
- int reason) {
- removeNotification(entry.getSbn());
- }
- });
-
- notifPipeline.addCollectionListener(new NotifCollectionListener() {
+ /** Initializes this listener by connecting it to the notification pipeline. */
+ public void init() {
+ mNotifPipeline.addCollectionListener(new NotifCollectionListener() {
@Override
public void onEntryAdded(NotificationEntry entry) {
addNotification(entry, entry.getImportance());
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceIconController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceIconController.kt
index 40d1eff..e4c197f 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceIconController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceIconController.kt
@@ -29,8 +29,9 @@
/** Face/Fingerprint combined icon animator for BiometricPrompt. */
class AuthBiometricFingerprintAndFaceIconController(
context: Context,
- iconView: LottieAnimationView
-) : AuthBiometricFingerprintIconController(context, iconView) {
+ iconView: LottieAnimationView,
+ iconViewOverlay: LottieAnimationView
+) : AuthBiometricFingerprintIconController(context, iconView, iconViewOverlay) {
override val actsAsConfirmButton: Boolean = true
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceView.kt
index 7371442..7f5a67f 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceView.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceView.kt
@@ -39,5 +39,5 @@
override fun onPointerDown(failedModalities: Set<Int>) = failedModalities.contains(TYPE_FACE)
override fun createIconController(): AuthIconController =
- AuthBiometricFingerprintAndFaceIconController(mContext, mIconView)
+ AuthBiometricFingerprintAndFaceIconController(mContext, mIconView, mIconViewOverlay)
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt
index 9b5f54a..b40b356 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt
@@ -18,7 +18,12 @@
import android.annotation.RawRes
import android.content.Context
+import android.hardware.fingerprint.FingerprintManager
+import android.view.DisplayInfo
+import android.view.Surface
+import android.view.View
import com.airbnb.lottie.LottieAnimationView
+import com.android.settingslib.widget.LottieColorUtils
import com.android.systemui.R
import com.android.systemui.biometrics.AuthBiometricView.BiometricState
import com.android.systemui.biometrics.AuthBiometricView.STATE_AUTHENTICATED
@@ -32,14 +37,18 @@
/** Fingerprint only icon animator for BiometricPrompt. */
open class AuthBiometricFingerprintIconController(
context: Context,
- iconView: LottieAnimationView
+ iconView: LottieAnimationView,
+ protected val iconViewOverlay: LottieAnimationView
) : AuthIconController(context, iconView) {
+ private val isSideFps: Boolean
var iconLayoutParamSize: Pair<Int, Int> = Pair(1, 1)
set(value) {
if (field == value) {
return
}
+ iconViewOverlay.layoutParams.width = value.first
+ iconViewOverlay.layoutParams.height = value.second
iconView.layoutParams.width = value.first
iconView.layoutParams.height = value.second
field = value
@@ -50,9 +59,53 @@
R.dimen.biometric_dialog_fingerprint_icon_width),
context.resources.getDimensionPixelSize(
R.dimen.biometric_dialog_fingerprint_icon_height))
+ var sideFps = false
+ (context.getSystemService(Context.FINGERPRINT_SERVICE)
+ as FingerprintManager?)?.let { fpm ->
+ for (prop in fpm.sensorPropertiesInternal) {
+ if (prop.isAnySidefpsType) {
+ sideFps = true
+ }
+ }
+ }
+ isSideFps = sideFps
+ val displayInfo = DisplayInfo()
+ context.display?.getDisplayInfo(displayInfo)
+ if (isSideFps && displayInfo.rotation == Surface.ROTATION_180) {
+ iconView.rotation = 180f
+ }
}
- override fun updateIcon(@BiometricState lastState: Int, @BiometricState newState: Int) {
+ private fun updateIconSideFps(@BiometricState lastState: Int, @BiometricState newState: Int) {
+ val displayInfo = DisplayInfo()
+ context.display?.getDisplayInfo(displayInfo)
+ val rotation = displayInfo.rotation
+ val iconAnimation = getSideFpsAnimationForTransition(rotation)
+ val iconViewOverlayAnimation =
+ getSideFpsOverlayAnimationForTransition(lastState, newState, rotation) ?: return
+
+ if (!(lastState == STATE_AUTHENTICATING_ANIMATING_IN && newState == STATE_AUTHENTICATING)) {
+ iconView.setAnimation(iconAnimation)
+ iconViewOverlay.setAnimation(iconViewOverlayAnimation)
+ }
+
+ val iconContentDescription = getIconContentDescription(newState)
+ if (iconContentDescription != null) {
+ iconView.contentDescription = iconContentDescription
+ iconViewOverlay.contentDescription = iconContentDescription
+ }
+
+ iconView.frame = 0
+ iconViewOverlay.frame = 0
+ if (shouldAnimateForTransition(lastState, newState)) {
+ iconView.playAnimation()
+ iconViewOverlay.playAnimation()
+ }
+ LottieColorUtils.applyDynamicColors(context, iconView)
+ LottieColorUtils.applyDynamicColors(context, iconViewOverlay)
+ }
+
+ private fun updateIconNormal(@BiometricState lastState: Int, @BiometricState newState: Int) {
val icon = getAnimationForTransition(lastState, newState) ?: return
if (!(lastState == STATE_AUTHENTICATING_ANIMATING_IN && newState == STATE_AUTHENTICATING)) {
@@ -68,6 +121,16 @@
if (shouldAnimateForTransition(lastState, newState)) {
iconView.playAnimation()
}
+ LottieColorUtils.applyDynamicColors(context, iconView)
+ }
+
+ override fun updateIcon(@BiometricState lastState: Int, @BiometricState newState: Int) {
+ if (isSideFps) {
+ updateIconSideFps(lastState, newState)
+ } else {
+ iconViewOverlay.visibility = View.GONE
+ updateIconNormal(lastState, newState)
+ }
}
private fun getIconContentDescription(@BiometricState newState: Int): CharSequence? {
@@ -125,4 +188,89 @@
}
return if (id != null) return id else null
}
+
+ @RawRes
+ private fun getSideFpsAnimationForTransition(rotation: Int): Int = when (rotation) {
+ Surface.ROTATION_0 -> R.raw.biometricprompt_landscape_base
+ Surface.ROTATION_90 -> R.raw.biometricprompt_portrait_base_topleft
+ Surface.ROTATION_180 -> R.raw.biometricprompt_landscape_base
+ Surface.ROTATION_270 -> R.raw.biometricprompt_portrait_base_bottomright
+ else -> R.raw.biometricprompt_landscape_base
+ }
+
+ @RawRes
+ private fun getSideFpsOverlayAnimationForTransition(
+ @BiometricState oldState: Int,
+ @BiometricState newState: Int,
+ rotation: Int
+ ): Int? = when (newState) {
+ STATE_HELP,
+ STATE_ERROR -> {
+ when (rotation) {
+ Surface.ROTATION_0 -> R.raw.biometricprompt_fingerprint_to_error_landscape
+ Surface.ROTATION_90 ->
+ R.raw.biometricprompt_symbol_fingerprint_to_error_portrait_topleft
+ Surface.ROTATION_180 ->
+ R.raw.biometricprompt_fingerprint_to_error_landscape
+ Surface.ROTATION_270 ->
+ R.raw.biometricprompt_symbol_fingerprint_to_error_portrait_bottomright
+ else -> R.raw.biometricprompt_fingerprint_to_error_landscape
+ }
+ }
+ STATE_AUTHENTICATING_ANIMATING_IN,
+ STATE_AUTHENTICATING -> {
+ if (oldState == STATE_ERROR || oldState == STATE_HELP) {
+ when (rotation) {
+ Surface.ROTATION_0 ->
+ R.raw.biometricprompt_symbol_error_to_fingerprint_landscape
+ Surface.ROTATION_90 ->
+ R.raw.biometricprompt_symbol_error_to_fingerprint_portrait_topleft
+ Surface.ROTATION_180 ->
+ R.raw.biometricprompt_symbol_error_to_fingerprint_landscape
+ Surface.ROTATION_270 ->
+ R.raw.biometricprompt_symbol_error_to_fingerprint_portrait_bottomright
+ else -> R.raw.biometricprompt_symbol_error_to_fingerprint_landscape
+ }
+ } else {
+ when (rotation) {
+ Surface.ROTATION_0 -> R.raw.biometricprompt_fingerprint_to_error_landscape
+ Surface.ROTATION_90 ->
+ R.raw.biometricprompt_symbol_fingerprint_to_error_portrait_topleft
+ Surface.ROTATION_180 ->
+ R.raw.biometricprompt_fingerprint_to_error_landscape
+ Surface.ROTATION_270 ->
+ R.raw.biometricprompt_symbol_fingerprint_to_error_portrait_bottomright
+ else -> R.raw.biometricprompt_fingerprint_to_error_landscape
+ }
+ }
+ }
+ STATE_AUTHENTICATED -> {
+ if (oldState == STATE_ERROR || oldState == STATE_HELP) {
+ when (rotation) {
+ Surface.ROTATION_0 ->
+ R.raw.biometricprompt_symbol_error_to_success_landscape
+ Surface.ROTATION_90 ->
+ R.raw.biometricprompt_symbol_error_to_success_portrait_topleft
+ Surface.ROTATION_180 ->
+ R.raw.biometricprompt_symbol_error_to_success_landscape
+ Surface.ROTATION_270 ->
+ R.raw.biometricprompt_symbol_error_to_success_portrait_bottomright
+ else -> R.raw.biometricprompt_symbol_error_to_success_landscape
+ }
+ } else {
+ when (rotation) {
+ Surface.ROTATION_0 ->
+ R.raw.biometricprompt_symbol_fingerprint_to_success_landscape
+ Surface.ROTATION_90 ->
+ R.raw.biometricprompt_symbol_fingerprint_to_success_portrait_topleft
+ Surface.ROTATION_180 ->
+ R.raw.biometricprompt_symbol_fingerprint_to_success_landscape
+ Surface.ROTATION_270 ->
+ R.raw.biometricprompt_symbol_fingerprint_to_success_portrait_bottomright
+ else -> R.raw.biometricprompt_symbol_fingerprint_to_success_landscape
+ }
+ }
+ }
+ else -> null
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintView.kt
index 9cce066..2066634 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintView.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintView.kt
@@ -86,7 +86,7 @@
override fun supportsSmallDialog() = false
override fun createIconController(): AuthIconController =
- AuthBiometricFingerprintIconController(mContext, mIconView)
+ AuthBiometricFingerprintIconController(mContext, mIconView, mIconViewOverlay)
fun updateOverrideIconLayoutParamsSize() {
udfpsAdapter?.let {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
index fc5cf9f..0ac71c4 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
@@ -133,6 +133,7 @@
private TextView mSubtitleView;
private TextView mDescriptionView;
private View mIconHolderView;
+ protected LottieAnimationView mIconViewOverlay;
protected LottieAnimationView mIconView;
protected TextView mIndicatorView;
@@ -168,6 +169,10 @@
private Animator.AnimatorListener mJankListener;
+ private final boolean mUseCustomBpSize;
+ private final int mCustomBpWidth;
+ private final int mCustomBpHeight;
+
private final OnClickListener mBackgroundClickListener = (view) -> {
if (mState == STATE_AUTHENTICATED) {
Log.w(TAG, "Ignoring background click after authenticated");
@@ -208,6 +213,10 @@
handleResetAfterHelp();
Utils.notifyAccessibilityContentChanged(mAccessibilityManager, this);
};
+
+ mUseCustomBpSize = getResources().getBoolean(R.bool.use_custom_bp_size);
+ mCustomBpWidth = getResources().getDimensionPixelSize(R.dimen.biometric_dialog_width);
+ mCustomBpHeight = getResources().getDimensionPixelSize(R.dimen.biometric_dialog_height);
}
/** Delay after authentication is confirmed, before the dialog should be animated away. */
@@ -651,6 +660,7 @@
mTitleView = findViewById(R.id.title);
mSubtitleView = findViewById(R.id.subtitle);
mDescriptionView = findViewById(R.id.description);
+ mIconViewOverlay = findViewById(R.id.biometric_icon_overlay);
mIconView = findViewById(R.id.biometric_icon);
mIconHolderView = findViewById(R.id.biometric_icon_frame);
mIndicatorView = findViewById(R.id.indicator);
@@ -689,6 +699,11 @@
mIconController = createIconController();
if (mIconController.getActsAsConfirmButton()) {
+ mIconViewOverlay.setOnClickListener((view)->{
+ if (mState == STATE_PENDING_CONFIRMATION) {
+ updateState(STATE_AUTHENTICATED);
+ }
+ });
mIconView.setOnClickListener((view) -> {
if (mState == STATE_PENDING_CONFIRMATION) {
updateState(STATE_AUTHENTICATED);
@@ -827,14 +842,17 @@
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- final int width = MeasureSpec.getSize(widthMeasureSpec);
- final int height = MeasureSpec.getSize(heightMeasureSpec);
+ int width = MeasureSpec.getSize(widthMeasureSpec);
+ int height = MeasureSpec.getSize(heightMeasureSpec);
- final int newWidth = Math.min(width, height);
+ if (mUseCustomBpSize) {
+ width = mCustomBpWidth;
+ height = mCustomBpHeight;
+ } else {
+ width = Math.min(width, height);
+ }
- // Use "newWidth" instead, so the landscape dialog width is the same as the portrait
- // width.
- mLayoutParams = onMeasureInternal(newWidth, height);
+ mLayoutParams = onMeasureInternal(width, height);
setMeasuredDimension(mLayoutParams.mMediumWidth, mLayoutParams.mMediumHeight);
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricMessageDeferral.kt b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricMessageDeferral.kt
new file mode 100644
index 0000000..f2d8aaa
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricMessageDeferral.kt
@@ -0,0 +1,89 @@
+/*
+ * 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.biometrics
+
+/**
+ * Provides whether an acquired error message should be shown immediately when its received (see
+ * [shouldDefer]) or should be shown when the biometric error is received [getDeferredMessage].
+ * @property excludedMessages messages that are excluded from counts
+ * @property messagesToDefer messages that shouldn't show immediately when received, but may be
+ * shown later if the message is the most frequent message processed and meets [THRESHOLD]
+ * percentage of all messages (excluding [excludedMessages])
+ */
+class BiometricMessageDeferral(
+ private val excludedMessages: Set<Int>,
+ private val messagesToDefer: Set<Int>
+) {
+ private val msgCounts: MutableMap<Int, Int> = HashMap() // msgId => frequency of msg
+ private val msgIdToCharSequence: MutableMap<Int, CharSequence> = HashMap() // msgId => message
+ private var totalRelevantMessages = 0
+ private var mostFrequentMsgIdToDefer: Int? = null
+
+ /** Reset all saved counts. */
+ fun reset() {
+ totalRelevantMessages = 0
+ msgCounts.clear()
+ msgIdToCharSequence.clear()
+ }
+
+ /** Whether the given message should be deferred instead of being shown immediately. */
+ fun shouldDefer(acquiredMsgId: Int): Boolean {
+ return messagesToDefer.contains(acquiredMsgId)
+ }
+
+ /**
+ * Adds the acquiredMsgId to the counts if it's not in [excludedMessages]. We still count
+ * messages that shouldn't be deferred in these counts.
+ */
+ fun processMessage(acquiredMsgId: Int, helpString: CharSequence) {
+ if (excludedMessages.contains(acquiredMsgId)) {
+ return
+ }
+
+ totalRelevantMessages++
+ msgIdToCharSequence[acquiredMsgId] = helpString
+
+ val newAcquiredMsgCount = msgCounts.getOrDefault(acquiredMsgId, 0) + 1
+ msgCounts[acquiredMsgId] = newAcquiredMsgCount
+ if (
+ messagesToDefer.contains(acquiredMsgId) &&
+ (mostFrequentMsgIdToDefer == null ||
+ newAcquiredMsgCount > msgCounts.getOrDefault(mostFrequentMsgIdToDefer!!, 0))
+ ) {
+ mostFrequentMsgIdToDefer = acquiredMsgId
+ }
+ }
+
+ /**
+ * Get the most frequent deferred message that meets the [THRESHOLD] percentage of processed
+ * messages excluding [excludedMessages].
+ * @return null if no messages have been deferred OR deferred messages didn't meet the
+ * [THRESHOLD] percentage of messages to show.
+ */
+ fun getDeferredMessage(): CharSequence? {
+ mostFrequentMsgIdToDefer?.let {
+ if (msgCounts.getOrDefault(it, 0) > (THRESHOLD * totalRelevantMessages)) {
+ return msgIdToCharSequence[mostFrequentMsgIdToDefer]
+ }
+ }
+
+ return null
+ }
+ companion object {
+ const val THRESHOLD = .5f
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index d1589b2..7f2680b 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -52,6 +52,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.LatencyTracker;
+import com.android.keyguard.FaceAuthApiRequestReason;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.animation.ActivityLaunchAnimator;
import com.android.systemui.biometrics.dagger.BiometricsBackground;
@@ -852,7 +853,9 @@
playStartHaptic();
if (!mKeyguardUpdateMonitor.isFaceDetectionRunning()) {
- mKeyguardUpdateMonitor.requestFaceAuth(/* userInitiatedRequest */ false);
+ mKeyguardUpdateMonitor.requestFaceAuth(
+ /* userInitiatedRequest */ false,
+ FaceAuthApiRequestReason.UDFPS_POINTER_DOWN);
}
}
mOnFingerDown = true;
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarDrawable.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarDrawable.java
index d96476f..49e378e 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarDrawable.java
@@ -99,11 +99,12 @@
mProgressColor = context.getColor(R.color.udfps_enroll_progress);
final AccessibilityManager am = context.getSystemService(AccessibilityManager.class);
mIsAccessibilityEnabled = am.isTouchExplorationEnabled();
- mOnFirstBucketFailedColor = context.getColor(R.color.udfps_moving_target_fill_error);
if (!mIsAccessibilityEnabled) {
mHelpColor = context.getColor(R.color.udfps_enroll_progress_help);
+ mOnFirstBucketFailedColor = context.getColor(R.color.udfps_moving_target_fill_error);
} else {
mHelpColor = context.getColor(R.color.udfps_enroll_progress_help_with_talkback);
+ mOnFirstBucketFailedColor = mHelpColor;
}
mCheckmarkDrawable = context.getDrawable(R.drawable.udfps_enroll_checkmark);
mCheckmarkDrawable.mutate();
@@ -166,8 +167,7 @@
}
private void updateProgress(int remainingSteps, int totalSteps, boolean showingHelp) {
- if (mRemainingSteps == remainingSteps && mTotalSteps == totalSteps
- && mShowingHelp == showingHelp) {
+ if (mRemainingSteps == remainingSteps && mTotalSteps == totalSteps) {
return;
}
@@ -197,7 +197,6 @@
}
}
- mShowingHelp = showingHelp;
mRemainingSteps = remainingSteps;
mTotalSteps = totalSteps;
diff --git a/packages/SystemUI/src/com/android/systemui/common/shared/model/Icon.kt b/packages/SystemUI/src/com/android/systemui/common/shared/model/Icon.kt
index 0b65966..6c45af2 100644
--- a/packages/SystemUI/src/com/android/systemui/common/shared/model/Icon.kt
+++ b/packages/SystemUI/src/com/android/systemui/common/shared/model/Icon.kt
@@ -24,11 +24,15 @@
* [Icon.Resource] to a resource.
*/
sealed class Icon {
+ abstract val contentDescription: ContentDescription?
+
data class Loaded(
val drawable: Drawable,
+ override val contentDescription: ContentDescription?,
) : Icon()
data class Resource(
@DrawableRes val res: Int,
+ override val contentDescription: ContentDescription?,
) : Icon()
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeConstants.java b/packages/SystemUI/src/com/android/systemui/common/shared/model/Text.kt
similarity index 62%
copy from libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeConstants.java
copy to packages/SystemUI/src/com/android/systemui/common/shared/model/Text.kt
index e62a63a..5d0e08f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeConstants.java
+++ b/packages/SystemUI/src/com/android/systemui/common/shared/model/Text.kt
@@ -12,20 +12,23 @@
* WITHOUT 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.desktopmode;
+package com.android.systemui.common.shared.model
-import android.os.SystemProperties;
+import android.annotation.StringRes
/**
- * Constants for desktop mode feature
+ * Models a text, that can either be already [loaded][Text.Loaded] or be a [reference]
+ * [Text.Resource] to a resource.
*/
-public class DesktopModeConstants {
+sealed class Text {
+ data class Loaded(
+ val text: String?,
+ ) : Text()
- /**
- * Flag to indicate whether desktop mode is available on the device
- */
- public static final boolean IS_FEATURE_ENABLED = SystemProperties.getBoolean(
- "persist.wm.debug.desktop_mode", false);
+ data class Resource(
+ @StringRes val res: Int,
+ ) : Text()
}
diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/binder/ContentDescriptionViewBinder.kt b/packages/SystemUI/src/com/android/systemui/common/ui/binder/ContentDescriptionViewBinder.kt
index d6433aa..93ae637 100644
--- a/packages/SystemUI/src/com/android/systemui/common/ui/binder/ContentDescriptionViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/common/ui/binder/ContentDescriptionViewBinder.kt
@@ -21,14 +21,16 @@
object ContentDescriptionViewBinder {
fun bind(
- contentDescription: ContentDescription,
+ contentDescription: ContentDescription?,
view: View,
) {
- when (contentDescription) {
- is ContentDescription.Loaded -> view.contentDescription = contentDescription.description
- is ContentDescription.Resource -> {
- view.contentDescription = view.context.resources.getString(contentDescription.res)
+ view.contentDescription =
+ when (contentDescription) {
+ null -> null
+ is ContentDescription.Loaded -> contentDescription.description
+ is ContentDescription.Resource -> {
+ view.context.resources.getString(contentDescription.res)
+ }
}
- }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/binder/IconViewBinder.kt b/packages/SystemUI/src/com/android/systemui/common/ui/binder/IconViewBinder.kt
index aecee2a..108e22b 100644
--- a/packages/SystemUI/src/com/android/systemui/common/ui/binder/IconViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/common/ui/binder/IconViewBinder.kt
@@ -24,6 +24,7 @@
icon: Icon,
view: ImageView,
) {
+ ContentDescriptionViewBinder.bind(icon.contentDescription, view)
when (icon) {
is Icon.Loaded -> view.setImageDrawable(icon.drawable)
is Icon.Resource -> view.setImageResource(icon.res)
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeConstants.java b/packages/SystemUI/src/com/android/systemui/common/ui/binder/TextViewBinder.kt
similarity index 60%
copy from libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeConstants.java
copy to packages/SystemUI/src/com/android/systemui/common/ui/binder/TextViewBinder.kt
index e62a63a..396e8bb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeConstants.java
+++ b/packages/SystemUI/src/com/android/systemui/common/ui/binder/TextViewBinder.kt
@@ -12,20 +12,20 @@
* WITHOUT 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.desktopmode;
+package com.android.systemui.common.ui.binder
-import android.os.SystemProperties;
+import android.widget.TextView
+import com.android.systemui.common.shared.model.Text
-/**
- * Constants for desktop mode feature
- */
-public class DesktopModeConstants {
-
- /**
- * Flag to indicate whether desktop mode is available on the device
- */
- public static final boolean IS_FEATURE_ENABLED = SystemProperties.getBoolean(
- "persist.wm.debug.desktop_mode", false);
+object TextViewBinder {
+ fun bind(view: TextView, viewModel: Text) {
+ view.text =
+ when (viewModel) {
+ is Text.Resource -> view.context.getString(viewModel.res)
+ is Text.Loaded -> viewModel.text
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiController.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiController.kt
index 91e75f6..822f8f2 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiController.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiController.kt
@@ -33,6 +33,12 @@
fun hide()
/**
+ * Returns the preferred activity to start, depending on if the user has favorited any
+ * controls.
+ */
+ fun resolveActivity(): Class<*>
+
+ /**
* Request all open dialogs be closed. Set [immediately] to true to dismiss without
* animations.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
index c1e99f5..bf7d716 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
@@ -149,6 +149,19 @@
}
}
+ override fun resolveActivity(): Class<*> {
+ val allStructures = controlsController.get().getFavorites()
+ val selectedStructure = getPreferredStructure(allStructures)
+
+ return if (controlsController.get().addSeedingFavoritesCallback(onSeedingComplete)) {
+ ControlsActivity::class.java
+ } else if (selectedStructure.controls.isEmpty() && allStructures.size <= 1) {
+ ControlsProviderSelectorActivity::class.java
+ } else {
+ ControlsActivity::class.java
+ }
+ }
+
override fun show(
parent: ViewGroup,
onDismiss: Runnable,
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DefaultServiceBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/DefaultServiceBinder.java
index e1cbdcd..92eeace 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DefaultServiceBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DefaultServiceBinder.java
@@ -18,7 +18,6 @@
import android.app.Service;
-import com.android.systemui.ImageWallpaper;
import com.android.systemui.SystemUIService;
import com.android.systemui.doze.DozeService;
import com.android.systemui.dreams.DreamOverlayService;
@@ -26,6 +25,7 @@
import com.android.systemui.keyguard.KeyguardService;
import com.android.systemui.screenrecord.RecordingService;
import com.android.systemui.statusbar.phone.NotificationListenerWithPlugins;
+import com.android.systemui.wallpapers.ImageWallpaper;
import dagger.Binds;
import dagger.Module;
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
index 4157728..fbfc94a 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
@@ -54,13 +54,11 @@
import com.android.systemui.statusbar.NotificationLockscreenUserManagerImpl;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.dagger.StartCentralSurfacesModule;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider;
import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
import com.android.systemui.statusbar.phone.DozeServiceHost;
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
-import com.android.systemui.statusbar.phone.KeyguardEnvironmentImpl;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
import com.android.systemui.statusbar.policy.BatteryController;
@@ -170,10 +168,6 @@
abstract DockManager bindDockManager(DockManagerImpl dockManager);
@Binds
- abstract NotificationEntryManager.KeyguardEnvironment bindKeyguardEnvironment(
- KeyguardEnvironmentImpl keyguardEnvironment);
-
- @Binds
abstract ShadeController provideShadeController(ShadeControllerImpl shadeController);
@SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index a0ecd22..318529b 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -42,7 +42,6 @@
import com.android.systemui.flags.FlagsModule;
import com.android.systemui.fragments.FragmentService;
import com.android.systemui.log.dagger.LogModule;
-import com.android.systemui.lowlightclock.LowLightClockController;
import com.android.systemui.media.dagger.MediaProjectionModule;
import com.android.systemui.model.SysUiState;
import com.android.systemui.navigationbar.NavigationBarComponent;
@@ -94,7 +93,6 @@
import com.android.systemui.wallet.dagger.WalletModule;
import com.android.systemui.wmshell.BubblesManager;
import com.android.wm.shell.bubbles.Bubbles;
-import com.android.wm.shell.dagger.DynamicOverride;
import java.util.Optional;
import java.util.concurrent.Executor;
@@ -246,21 +244,6 @@
sysuiMainExecutor));
}
- @BindsOptionalOf
- @DynamicOverride
- abstract LowLightClockController optionalLowLightClockController();
-
- @SysUISingleton
- @Provides
- static Optional<LowLightClockController> provideLowLightClockController(
- @DynamicOverride Optional<LowLightClockController> optionalController) {
- if (optionalController.isPresent() && optionalController.get().isLowLightClockEnabled()) {
- return optionalController;
- } else {
- return Optional.empty();
- }
- }
-
@Binds
abstract FgsManagerController bindFgsManagerController(FgsManagerControllerImpl impl);
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
index d89c0be..b598554 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
@@ -101,6 +101,11 @@
* Called when the always on suppression state changes. See {@link #isAlwaysOnSuppressed()}.
*/
default void onAlwaysOnSuppressedChanged(boolean suppressed) {}
+
+ /**
+ * Called when the dozing state may have been updated.
+ */
+ default void onDozingChanged(boolean isDozing) {}
}
interface PulseCallback {
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.java b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
index 1482303..e9c0337 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
@@ -66,6 +66,10 @@
public static final UnreleasedFlag FSI_REQUIRES_KEYGUARD =
new UnreleasedFlag(110, true);
+ public static final UnreleasedFlag INSTANT_VOICE_REPLY = new UnreleasedFlag(111, true);
+
+ // next id: 112
+
/***************************************/
// 200 - keyguard/lockscreen
@@ -88,20 +92,13 @@
public static final ResourceBooleanFlag FACE_SCANNING_ANIM =
new ResourceBooleanFlag(205, R.bool.config_enableFaceScanningAnimation);
- /**
- * Whether the KeyguardBottomArea(View|Controller) should use the modern architecture or the old
- * one.
- */
- public static final ReleasedFlag MODERN_BOTTOM_AREA = new ReleasedFlag(206, true);
-
-
public static final UnreleasedFlag LOCKSCREEN_CUSTOM_CLOCKS = new UnreleasedFlag(207);
/**
* Flag to enable the usage of the new bouncer data source. This is a refactor of and
* eventual replacement of KeyguardBouncer.java.
*/
- public static final ReleasedFlag MODERN_BOUNCER = new ReleasedFlag(208);
+ public static final UnreleasedFlag MODERN_BOUNCER = new UnreleasedFlag(208);
/** Whether UserSwitcherActivity should use modern architecture. */
public static final UnreleasedFlag MODERN_USER_SWITCHER_ACTIVITY =
@@ -187,6 +184,9 @@
// 801 - region sampling
public static final UnreleasedFlag REGION_SAMPLING = new UnreleasedFlag(801);
+ // 802 - wallpaper rendering
+ public static final UnreleasedFlag USE_CANVAS_RENDERER = new UnreleasedFlag(802);
+
/***************************************/
// 900 - media
public static final ReleasedFlag MEDIA_TAP_TO_TRANSFER = new ReleasedFlag(900);
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
index 6dfbd42..2da9232 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
@@ -29,6 +29,7 @@
import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY;
import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_OCCLUDE;
+import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_OCCLUDE_BY_DREAM;
import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_UNOCCLUDE;
import static android.view.WindowManager.TRANSIT_OLD_NONE;
import static android.view.WindowManager.TRANSIT_OPEN;
@@ -189,6 +190,9 @@
return apps.length == 0 ? TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER
: TRANSIT_OLD_KEYGUARD_GOING_AWAY;
} else if (type == TRANSIT_KEYGUARD_OCCLUDE) {
+ boolean isOccludeByDream = apps.length > 0 && apps[0].taskInfo.topActivityType
+ == WindowConfiguration.ACTIVITY_TYPE_DREAM;
+ if (isOccludeByDream) return TRANSIT_OLD_KEYGUARD_OCCLUDE_BY_DREAM;
return TRANSIT_OLD_KEYGUARD_OCCLUDE;
} else if (type == TRANSIT_KEYGUARD_UNOCCLUDE) {
return TRANSIT_OLD_KEYGUARD_UNOCCLUDE;
@@ -303,6 +307,12 @@
definition.addRemoteAnimation(TRANSIT_OLD_KEYGUARD_OCCLUDE,
occludeAnimationAdapter);
+ final RemoteAnimationAdapter occludeByDreamAnimationAdapter =
+ new RemoteAnimationAdapter(
+ mKeyguardViewMediator.getOccludeByDreamAnimationRunner(), 0, 0);
+ definition.addRemoteAnimation(TRANSIT_OLD_KEYGUARD_OCCLUDE_BY_DREAM,
+ occludeByDreamAnimationAdapter);
+
final RemoteAnimationAdapter unoccludeAnimationAdapter =
new RemoteAnimationAdapter(
mKeyguardViewMediator.getUnoccludeAnimationRunner(), 0, 0);
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
index c944e50..bd75ab2 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
@@ -282,7 +282,8 @@
* window like any other app. This can be true while [willUnlockWithSmartspaceTransition] is
* false, if the smartspace is not available or was not ready in time.
*/
- private var willUnlockWithInWindowLauncherAnimations: Boolean = false
+ @VisibleForTesting
+ var willUnlockWithInWindowLauncherAnimations: Boolean = false
/**
* Whether we decided in [prepareForInWindowLauncherAnimations] that we are able to and want to
@@ -484,8 +485,8 @@
// surface behind the keyguard to finish unlocking.
if (keyguardStateController.isFlingingToDismissKeyguard) {
playCannedUnlockAnimation()
- } else if (keyguardStateController.isDismissingFromSwipe
- && willUnlockWithInWindowLauncherAnimations) {
+ } else if (keyguardStateController.isDismissingFromSwipe &&
+ willUnlockWithInWindowLauncherAnimations) {
// If we're swiping to unlock to the Launcher, and can play in-window animations,
// make the launcher surface fully visible and play the in-window unlock animation
// on the launcher icons. System UI will remain locked, using the swipe-to-unlock
@@ -574,7 +575,7 @@
// Now that the Launcher surface (with its smartspace positioned identically to ours) is
// visible, hide our smartspace.
- lockscreenSmartspace!!.visibility = View.INVISIBLE
+ lockscreenSmartspace?.visibility = View.INVISIBLE
// As soon as the shade has animated out of the way, finish the keyguard exit animation. The
// in-window animations in the Launcher window will end on their own.
@@ -727,8 +728,8 @@
// If we're dismissing via swipe to the Launcher, we'll play in-window scale animations, so
// don't also scale the window.
- if (keyguardStateController.isDismissingFromSwipe
- && willUnlockWithInWindowLauncherAnimations) {
+ if (keyguardStateController.isDismissingFromSwipe &&
+ willUnlockWithInWindowLauncherAnimations) {
scaleFactor = 1f
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index d4ef467..d4e0f061 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -887,6 +887,86 @@
private IRemoteAnimationRunner mOccludeAnimationRunner =
new OccludeActivityLaunchRemoteAnimationRunner(mOccludeAnimationController);
+ private final IRemoteAnimationRunner mOccludeByDreamAnimationRunner =
+ new IRemoteAnimationRunner.Stub() {
+ @Nullable private ValueAnimator mOccludeByDreamAnimator;
+
+ @Override
+ public void onAnimationCancelled(boolean isKeyguardOccluded) {
+ if (mOccludeByDreamAnimator != null) {
+ mOccludeByDreamAnimator.cancel();
+ }
+ setOccluded(isKeyguardOccluded /* isOccluded */, false /* animate */);
+ if (DEBUG) {
+ Log.d(TAG, "Occlude by Dream animation cancelled. Occluded state is now: "
+ + mOccluded);
+ }
+ }
+
+ @Override
+ public void onAnimationStart(int transit, RemoteAnimationTarget[] apps,
+ RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps,
+ IRemoteAnimationFinishedCallback finishedCallback) throws RemoteException {
+ setOccluded(true /* isOccluded */, true /* animate */);
+
+ if (apps == null || apps.length == 0 || apps[0] == null) {
+ if (DEBUG) {
+ Log.d(TAG, "No apps provided to the OccludeByDream runner; "
+ + "skipping occluding animation.");
+ }
+ finishedCallback.onAnimationFinished();
+ return;
+ }
+
+ final RemoteAnimationTarget primary = apps[0];
+ final boolean isDream = (apps[0].taskInfo.topActivityType
+ == WindowConfiguration.ACTIVITY_TYPE_DREAM);
+ if (!isDream) {
+ Log.w(TAG, "The occluding app isn't Dream; "
+ + "finishing up. Please check that the config is correct.");
+ finishedCallback.onAnimationFinished();
+ return;
+ }
+
+ final SyncRtSurfaceTransactionApplier applier =
+ new SyncRtSurfaceTransactionApplier(
+ mKeyguardViewControllerLazy.get().getViewRootImpl().getView());
+
+ mContext.getMainExecutor().execute(() -> {
+ if (mOccludeByDreamAnimator != null) {
+ mOccludeByDreamAnimator.cancel();
+ }
+
+ mOccludeByDreamAnimator = ValueAnimator.ofFloat(0f, 1f);
+ // Use the same duration as for the UNOCCLUDE.
+ mOccludeByDreamAnimator.setDuration(UNOCCLUDE_ANIMATION_DURATION);
+ mOccludeByDreamAnimator.setInterpolator(Interpolators.LINEAR);
+ mOccludeByDreamAnimator.addUpdateListener(
+ animation -> {
+ SyncRtSurfaceTransactionApplier.SurfaceParams.Builder
+ paramsBuilder =
+ new SyncRtSurfaceTransactionApplier.SurfaceParams
+ .Builder(primary.leash)
+ .withAlpha(animation.getAnimatedFraction());
+ applier.scheduleApply(paramsBuilder.build());
+ });
+ mOccludeByDreamAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ try {
+ finishedCallback.onAnimationFinished();
+ mOccludeByDreamAnimator = null;
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+ }
+ });
+
+ mOccludeByDreamAnimator.start();
+ });
+ }
+ };
+
/**
* Animation controller for activities that unocclude the keyguard. This does not use the
* ActivityLaunchAnimator since we're just translating down, rather than emerging from a view
@@ -1682,6 +1762,10 @@
return mOccludeAnimationRunner;
}
+ public IRemoteAnimationRunner getOccludeByDreamAnimationRunner() {
+ return mOccludeByDreamAnimationRunner;
+ }
+
public IRemoteAnimationRunner getUnoccludeAnimationRunner() {
return mUnoccludeAnimationRunner;
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
index e52d9ee..840a4b2 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
@@ -20,6 +20,7 @@
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import com.android.systemui.common.shared.model.Position
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.doze.DozeHost
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.policy.KeyguardStateController
import javax.inject.Inject
@@ -28,6 +29,7 @@
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.distinctUntilChanged
/** Defines interface for classes that encapsulate application state for the keyguard. */
interface KeyguardRepository {
@@ -102,6 +104,7 @@
constructor(
statusBarStateController: StatusBarStateController,
keyguardStateController: KeyguardStateController,
+ dozeHost: DozeHost,
) : KeyguardRepository {
private val _animateBottomAreaDozingTransitions = MutableStateFlow(false)
override val animateBottomAreaDozingTransitions =
@@ -136,19 +139,21 @@
awaitClose { keyguardStateController.removeCallback(callback) }
}
- override val isDozing: Flow<Boolean> = conflatedCallbackFlow {
- val callback =
- object : StatusBarStateController.StateListener {
- override fun onDozingChanged(isDozing: Boolean) {
- trySendWithFailureLogging(isDozing, TAG, "updated isDozing")
- }
+ override val isDozing: Flow<Boolean> =
+ conflatedCallbackFlow {
+ val callback =
+ object : DozeHost.Callback {
+ override fun onDozingChanged(isDozing: Boolean) {
+ trySendWithFailureLogging(isDozing, TAG, "updated isDozing")
+ }
+ }
+ dozeHost.addCallback(callback)
+ trySendWithFailureLogging(false, TAG, "initial isDozing: false")
+
+ awaitClose { dozeHost.removeCallback(callback) }
}
+ .distinctUntilChanged()
- statusBarStateController.addCallback(callback)
- trySendWithFailureLogging(statusBarStateController.isDozing, TAG, "initial isDozing")
-
- awaitClose { statusBarStateController.removeCallback(callback) }
- }
override val dozeAmount: Flow<Float> = conflatedCallbackFlow {
val callback =
object : StatusBarStateController.StateListener {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
index 9a69e26..95acc0b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
@@ -32,6 +32,7 @@
import kotlin.reflect.KClass
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.onStart
@SysUISingleton
class KeyguardQuickAffordanceInteractor
@@ -88,7 +89,15 @@
position: KeyguardQuickAffordancePosition
): Flow<KeyguardQuickAffordanceModel> {
val configs = registry.getAll(position)
- return combine(configs.map { config -> config.state }) { states ->
+ return combine(
+ configs.map { config ->
+ // We emit an initial "Hidden" value to make sure that there's always an initial
+ // value and avoid subtle bugs where the downstream isn't receiving any values
+ // because one config implementation is not emitting an initial value. For example,
+ // see b/244296596.
+ config.state.onStart { emit(KeyguardQuickAffordanceConfig.State.Hidden) }
+ }
+ ) { states ->
val index = states.indexOfFirst { it is KeyguardQuickAffordanceConfig.State.Visible }
if (index != -1) {
val visibleState = states[index] as KeyguardQuickAffordanceConfig.State.Visible
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfig.kt
index 8f32ff9..ac2c9b1 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfig.kt
@@ -94,6 +94,7 @@
hasFavorites = favorites?.isNotEmpty() == true,
hasServiceInfos = serviceInfos.isNotEmpty(),
iconResourceId = component.getTileImageId(),
+ visibility = component.getVisibility(),
),
TAG,
)
@@ -110,9 +111,16 @@
isFeatureEnabled: Boolean,
hasFavorites: Boolean,
hasServiceInfos: Boolean,
+ visibility: ControlsComponent.Visibility,
@DrawableRes iconResourceId: Int?,
): KeyguardQuickAffordanceConfig.State {
- return if (isFeatureEnabled && hasFavorites && hasServiceInfos && iconResourceId != null) {
+ return if (
+ isFeatureEnabled &&
+ hasFavorites &&
+ hasServiceInfos &&
+ iconResourceId != null &&
+ visibility == ControlsComponent.Visibility.AVAILABLE
+ ) {
KeyguardQuickAffordanceConfig.State.Visible(
icon = ContainedDrawable.WithResource(iconResourceId),
contentDescriptionResourceId = component.getTileTitleId(),
diff --git a/packages/SystemUI/src/com/android/systemui/lowlightclock/LowLightClockController.java b/packages/SystemUI/src/com/android/systemui/lowlightclock/LowLightClockController.java
deleted file mode 100644
index 0b15f4f..0000000
--- a/packages/SystemUI/src/com/android/systemui/lowlightclock/LowLightClockController.java
+++ /dev/null
@@ -1,48 +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.lowlightclock;
-
-import android.view.ViewGroup;
-
-/**
- * A controller responsible for attaching and showing an optional low-light clock while dozing.
- */
-public interface LowLightClockController {
- /**
- * Returns {@code true} if the low-light clock is enabled.
- */
- boolean isLowLightClockEnabled();
-
- /**
- * Attach the low light-clock to the given parent {@link ViewGroup}.
- * @param parent The parent {@link ViewGroup} to which the low-light clock view should be
- * attached.
- */
- void attachLowLightClockView(ViewGroup parent);
-
- /**
- * Show or hide the low-light clock.
- * @param show Whether to show the low-light clock.
- * @return {@code true} if the low-light clock was shown.
- */
- boolean showLowLightClock(boolean show);
-
- /**
- * An opportunity to perform burn-in prevention.
- */
- void dozeTimeTick();
-}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
index e9caaaf..cc77ed1 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
@@ -148,6 +148,32 @@
}
}
}
+
+ companion object {
+ private const val SQUISHINESS_SCALE_START = 0.5
+ private const val SQUISHINESS_SCALE_FACTOR = 0.5
+ private fun getSquishinessScale(squishinessFraction: Float): Double {
+ return SQUISHINESS_SCALE_START + SQUISHINESS_SCALE_FACTOR * squishinessFraction
+ }
+ }
+
+ var squishinessFraction: Float = 1f
+ set(value) {
+ if (field == value) {
+ return
+ }
+ field = value
+
+ val scale = getSquishinessScale(field)
+ for (mediaPlayer in MediaPlayerData.players()) {
+ mediaPlayer.mediaViewHolder?.let {
+ it.player.bottom = it.player.top + (scale * it.player.measuredHeight).toInt()
+ } ?: mediaPlayer.recommendationViewHolder?.let {
+ it.recommendations.bottom = it.recommendations.top +
+ (scale * it.recommendations.measuredHeight).toInt()
+ }
+ }
+ }
private val configListener = object : ConfigurationController.ConfigurationListener {
override fun onDensityOrFontScaleChanged() {
// System font changes should only happen when UMO is offscreen or a flicker may occur
@@ -432,6 +458,7 @@
val existingPlayer = MediaPlayerData.getMediaPlayer(key)
val curVisibleMediaKey = MediaPlayerData.playerKeys()
.elementAtOrNull(mediaCarouselScrollHandler.visibleMediaIndex)
+ val isCurVisibleMediaPlaying = MediaPlayerData.getMediaData(curVisibleMediaKey)?.isPlaying
if (existingPlayer == null) {
val newPlayer = mediaControlPanelFactory.get()
newPlayer.attachPlayer(MediaViewHolder.create(
@@ -446,13 +473,23 @@
key, data, newPlayer, systemClock, isSsReactivated, debugLogger
)
updatePlayerToState(newPlayer, noAnimation = true)
- reorderAllPlayers(curVisibleMediaKey)
+ if (data.active) {
+ reorderAllPlayers(curVisibleMediaKey)
+ } else {
+ needsReordering = true
+ }
} else {
existingPlayer.bindPlayer(data, key)
MediaPlayerData.addMediaPlayer(
key, data, existingPlayer, systemClock, isSsReactivated, debugLogger
)
- if (isReorderingAllowed || shouldScrollToActivePlayer) {
+ // Check the playing status of both current visible and new media players
+ // To make sure we scroll to the active playing media card.
+ if (isReorderingAllowed ||
+ shouldScrollToActivePlayer &&
+ data.isPlaying == true &&
+ isCurVisibleMediaPlaying == false
+ ) {
reorderAllPlayers(curVisibleMediaKey)
} else {
needsReordering = true
@@ -1009,6 +1046,15 @@
}
}
+ fun getMediaData(mediaSortKey: MediaSortKey?): MediaData? {
+ mediaData.forEach { (key, value) ->
+ if (value == mediaSortKey) {
+ return mediaData[key]?.data
+ }
+ }
+ return null
+ }
+
fun getMediaPlayer(key: String): MediaControlPanel? {
return mediaData.get(key)?.let { mediaPlayers.get(it) }
}
@@ -1076,4 +1122,4 @@
}
fun isSsReactivated(key: String): Boolean = mediaData.get(key)?.isSsReactivated ?: false
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
index ae4c7c7..6baf6e1 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
@@ -41,6 +41,7 @@
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.dreams.DreamOverlayStateController
import com.android.systemui.keyguard.WakefulnessLifecycle
+import com.android.systemui.media.dream.MediaDreamComplication
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.shade.NotifPanelEvents
import com.android.systemui.statusbar.CrossFadeHelper
@@ -401,7 +402,7 @@
}
/**
- * Is the doze animation currently Running
+ * Is the dream overlay currently active
*/
private var dreamOverlayActive: Boolean = false
private set(value) {
@@ -412,6 +413,17 @@
}
/**
+ * Is the dream media complication currently active
+ */
+ private var dreamMediaComplicationActive: Boolean = false
+ private set(value) {
+ if (field != value) {
+ field = value
+ updateDesiredLocation(forceNoAnimation = true)
+ }
+ }
+
+ /**
* The current cross fade progress. 0.5f means it's just switching
* between the start and the end location and the content is fully faded, while 0.75f means
* that we're halfway faded in again in the target state.
@@ -500,6 +512,12 @@
})
dreamOverlayStateController.addCallback(object : DreamOverlayStateController.Callback {
+ override fun onComplicationsChanged() {
+ dreamMediaComplicationActive = dreamOverlayStateController.complications.any {
+ it is MediaDreamComplication
+ }
+ }
+
override fun onStateChanged() {
dreamOverlayStateController.isOverlayActive.also { dreamOverlayActive = it }
}
@@ -1068,7 +1086,7 @@
val onLockscreen = (!bypassController.bypassEnabled &&
(statusbarState == StatusBarState.KEYGUARD))
val location = when {
- dreamOverlayActive -> LOCATION_DREAM_OVERLAY
+ dreamOverlayActive && dreamMediaComplicationActive -> LOCATION_DREAM_OVERLAY
(qsExpansion > 0.0f || inSplitShade) && !onLockscreen -> LOCATION_QS
qsExpansion > 0.4f && onLockscreen -> LOCATION_QS
!hasActiveMedia -> LOCATION_QS
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt
index 53abd99..0f1ee31 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt
@@ -23,35 +23,47 @@
import android.os.Bundle
import android.os.IBinder
import android.os.ResultReceiver
-import android.view.View
+import android.os.UserHandle
+import android.widget.ImageView
import com.android.internal.app.ChooserActivity
+import com.android.internal.app.ResolverListController
import com.android.internal.app.chooser.NotSelectableTargetInfo
import com.android.internal.app.chooser.TargetInfo
+import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.util.AsyncActivityLauncher
-import com.android.systemui.R;
-import javax.inject.Inject
+import com.android.systemui.R
+import com.android.internal.R as AndroidR
-class MediaProjectionAppSelectorActivity @Inject constructor(
- private val activityLauncher: AsyncActivityLauncher
+class MediaProjectionAppSelectorActivity constructor(
+ private val activityLauncher: AsyncActivityLauncher,
+ /** This is used to override the dependency in a screenshot test */
+ @VisibleForTesting
+ private val listControllerFactory: ((userHandle: UserHandle) -> ResolverListController)? = null
) : ChooserActivity() {
+ override fun getLayoutResource() =
+ R.layout.media_projection_app_selector
+
public override fun onCreate(bundle: Bundle?) {
val queryIntent = Intent(Intent.ACTION_MAIN)
.addCategory(Intent.CATEGORY_LAUNCHER)
intent.putExtra(Intent.EXTRA_INTENT, queryIntent)
- // TODO(b/235465652) Use resource lexeme
- intent.putExtra(Intent.EXTRA_TITLE, "Record or cast an app")
+ // TODO(b/240939253): update copies
+ val title = getString(R.string.media_projection_dialog_service_title)
+ intent.putExtra(Intent.EXTRA_TITLE, title)
super.onCreate(bundle)
- // TODO(b/235465652) we should update VisD of the title and add an icon
- findViewById<View>(R.id.title)?.visibility = View.VISIBLE
+ requireViewById<ImageView>(AndroidR.id.icon).setImageResource(R.drawable.ic_present_to_all)
}
override fun appliedThemeResId(): Int =
R.style.Theme_SystemUI_MediaProjectionAppSelector
+ override fun createListController(userHandle: UserHandle): ResolverListController =
+ listControllerFactory?.invoke(userHandle) ?: super.createListController(userHandle)
+
override fun startSelected(which: Int, always: Boolean, filtered: Boolean) {
val currentListAdapter = mChooserMultiProfilePagerAdapter.activeListAdapter
val targetInfo = currentListAdapter.targetInfoForPosition(which, filtered) ?: return
diff --git a/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
index 75fa2f1..0b9b32b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
+++ b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
@@ -96,8 +96,9 @@
mToken = token;
mRingtone = new Ringtone(getContextForUser(user), false);
- mRingtone.setAudioAttributes(aa);
+ mRingtone.setAudioAttributesField(aa);
mRingtone.setUri(uri, volumeShaperConfig);
+ mRingtone.createLocalMediaPlayer();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/media/dagger/MediaProjectionModule.kt b/packages/SystemUI/src/com/android/systemui/media/dagger/MediaProjectionModule.kt
index e33a1b9..9696998 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dagger/MediaProjectionModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/dagger/MediaProjectionModule.kt
@@ -18,8 +18,10 @@
import android.app.Activity
import com.android.systemui.media.MediaProjectionAppSelectorActivity
+import com.android.systemui.util.AsyncActivityLauncher
import dagger.Binds
import dagger.Module
+import dagger.Provides
import dagger.multibindings.ClassKey
import dagger.multibindings.IntoMap
@@ -29,7 +31,17 @@
@Binds
@IntoMap
@ClassKey(MediaProjectionAppSelectorActivity::class)
- abstract fun provideMediaProjectionAppSelectorActivity(
+ abstract fun bindMediaProjectionAppSelectorActivity(
activity: MediaProjectionAppSelectorActivity): Activity
+ companion object {
+ @Provides
+ fun provideMediaProjectionAppSelectorActivity(
+ activityLauncher: AsyncActivityLauncher
+ ): MediaProjectionAppSelectorActivity {
+ return MediaProjectionAppSelectorActivity(
+ activityLauncher
+ )
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
index e08e338..85d8f3f 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
@@ -310,6 +310,7 @@
if (icon.getType() != Icon.TYPE_BITMAP && icon.getType() != Icon.TYPE_ADAPTIVE_BITMAP) {
// icon doesn't support getBitmap, use default value for color scheme
updateButtonBackgroundColorFilter();
+ updateDialogBackgroundColor();
} else {
Configuration config = mContext.getResources().getConfiguration();
int currentNightMode = config.uiMode & Configuration.UI_MODE_NIGHT_MASK;
@@ -319,11 +320,14 @@
if (colorSetUpdated) {
mAdapter.updateColorScheme(wallpaperColors, isDarkThemeOn);
updateButtonBackgroundColorFilter();
+ updateDialogBackgroundColor();
}
}
mHeaderIcon.setVisibility(View.VISIBLE);
mHeaderIcon.setImageIcon(icon);
} else {
+ updateButtonBackgroundColorFilter();
+ updateDialogBackgroundColor();
mHeaderIcon.setVisibility(View.GONE);
}
if (appSourceIcon != null) {
@@ -381,11 +385,16 @@
private void updateButtonBackgroundColorFilter() {
ColorFilter buttonColorFilter = new PorterDuffColorFilter(
- mAdapter.getController().getColorButtonBackground(),
+ mMediaOutputController.getColorButtonBackground(),
PorterDuff.Mode.SRC_IN);
mDoneButton.getBackground().setColorFilter(buttonColorFilter);
mStopButton.getBackground().setColorFilter(buttonColorFilter);
- mDoneButton.setTextColor(mAdapter.getController().getColorPositiveButtonText());
+ mDoneButton.setTextColor(mMediaOutputController.getColorPositiveButtonText());
+ }
+
+ private void updateDialogBackgroundColor() {
+ getDialogView().getBackground().setTint(mMediaOutputController.getColorDialogBackground());
+ mDeviceListLayout.setBackgroundColor(mMediaOutputController.getColorDialogBackground());
}
private Drawable resizeDrawable(Drawable drawable, int size) {
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
index 8dd843a..7b4ac12 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
@@ -133,6 +133,7 @@
@VisibleForTesting
LocalMediaManager mLocalMediaManager;
private MediaOutputMetricLogger mMetricLogger;
+ private int mCurrentState;
private int mColorItemContent;
private int mColorSeekbarProgress;
@@ -140,6 +141,7 @@
private int mColorItemBackground;
private int mColorConnectedItemBackground;
private int mColorPositiveButtonText;
+ private int mColorDialogBackground;
private float mInactiveRadius;
private float mActiveRadius;
@@ -188,6 +190,8 @@
R.dimen.media_output_dialog_background_radius);
mActiveRadius = mContext.getResources().getDimension(
R.dimen.media_output_dialog_active_background_radius);
+ mColorDialogBackground = Utils.getColorStateListDefaultColor(mContext,
+ R.color.media_dialog_background);
}
void start(@NonNull Callback cb) {
@@ -204,6 +208,9 @@
if (TextUtils.equals(controller.getPackageName(), mPackageName)) {
mMediaController = controller;
mMediaController.unregisterCallback(mCb);
+ if (mMediaController.getPlaybackState() != null) {
+ mCurrentState = mMediaController.getPlaybackState().getState();
+ }
mMediaController.registerCallback(mCb);
break;
}
@@ -471,6 +478,7 @@
mColorItemBackground = mCurrentColorScheme.getNeutral2().get(9); // N2-800
mColorConnectedItemBackground = mCurrentColorScheme.getAccent2().get(9); // A2-800
mColorPositiveButtonText = mCurrentColorScheme.getAccent2().get(9); // A2-800
+ mColorDialogBackground = mCurrentColorScheme.getNeutral1().get(10); // N1-900
} else {
mColorItemContent = mCurrentColorScheme.getAccent1().get(9); // A1-800
mColorSeekbarProgress = mCurrentColorScheme.getAccent1().get(4); // A1-300
@@ -478,6 +486,7 @@
mColorItemBackground = mCurrentColorScheme.getAccent2().get(1); // A2-50
mColorConnectedItemBackground = mCurrentColorScheme.getAccent1().get(2); // A1-100
mColorPositiveButtonText = mCurrentColorScheme.getNeutral1().get(1); // N1-50
+ mColorDialogBackground = mCurrentColorScheme.getBackgroundColor();
}
}
@@ -497,6 +506,10 @@
return mColorPositiveButtonText;
}
+ public int getColorDialogBackground() {
+ return mColorDialogBackground;
+ }
+
public int getColorItemContent() {
return mColorItemContent;
}
@@ -994,10 +1007,16 @@
@Override
public void onPlaybackStateChanged(PlaybackState playbackState) {
- final int state = playbackState.getState();
- if (state == PlaybackState.STATE_STOPPED || state == PlaybackState.STATE_PAUSED) {
+ final int newState =
+ playbackState == null ? PlaybackState.STATE_STOPPED : playbackState.getState();
+ if (mCurrentState == newState) {
+ return;
+ }
+
+ if (newState == PlaybackState.STATE_STOPPED || newState == PlaybackState.STATE_PAUSED) {
mCallback.onMediaStoppedOrPaused();
}
+ mCurrentState = newState;
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/media/dream/MediaDreamSentinel.java b/packages/SystemUI/src/com/android/systemui/media/dream/MediaDreamSentinel.java
index acd04f2..dc1488e 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dream/MediaDreamSentinel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dream/MediaDreamSentinel.java
@@ -19,6 +19,7 @@
import static com.android.systemui.flags.Flags.MEDIA_DREAM_COMPLICATION;
import android.content.Context;
+import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -38,6 +39,9 @@
* the media complication as appropriate
*/
public class MediaDreamSentinel extends CoreStartable {
+ private static final String TAG = "MediaDreamSentinel";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
private final MediaDataManager.Listener mListener = new MediaDataManager.Listener() {
private boolean mAdded;
@Override
@@ -46,11 +50,17 @@
@Override
public void onMediaDataRemoved(@NonNull String key) {
+ final boolean hasActiveMedia = mMediaDataManager.hasActiveMedia();
+ if (DEBUG) {
+ Log.d(TAG, "onMediaDataRemoved(" + key + "), mAdded=" + mAdded + ", hasActiveMedia="
+ + hasActiveMedia);
+ }
+
if (!mAdded) {
return;
}
- if (mMediaDataManager.hasActiveMedia()) {
+ if (hasActiveMedia) {
return;
}
@@ -71,11 +81,24 @@
return;
}
+ final boolean hasActiveMedia = mMediaDataManager.hasActiveMedia();
+ if (DEBUG) {
+ Log.d(TAG, "onMediaDataLoaded(" + key + "), mAdded=" + mAdded + ", hasActiveMedia="
+ + hasActiveMedia);
+ }
+
+ // Media data can become inactive without triggering onMediaDataRemoved.
+ if (mAdded && !hasActiveMedia) {
+ mAdded = false;
+ mDreamOverlayStateController.removeComplication(mMediaEntryComplication);
+ return;
+ }
+
if (mAdded) {
return;
}
- if (!mMediaDataManager.hasActiveMedia()) {
+ if (!hasActiveMedia) {
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
index 35a6c74..5d6d683 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
@@ -34,15 +34,14 @@
import com.android.systemui.R
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.media.taptotransfer.common.ChipInfoCommon
-import com.android.systemui.media.taptotransfer.common.DEFAULT_TIMEOUT_MILLIS
-import com.android.systemui.media.taptotransfer.common.MediaTttChipControllerCommon
import com.android.systemui.media.taptotransfer.common.MediaTttLogger
import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.temporarydisplay.DEFAULT_TIMEOUT_MILLIS
+import com.android.systemui.temporarydisplay.TemporaryViewDisplayController
+import com.android.systemui.temporarydisplay.TemporaryViewInfo
import com.android.systemui.util.animation.AnimationUtil.Companion.frames
import com.android.systemui.util.concurrency.DelayableExecutor
-import com.android.systemui.util.view.ViewUtil
import javax.inject.Inject
/**
@@ -56,18 +55,16 @@
context: Context,
@MediaTttReceiverLogger logger: MediaTttLogger,
windowManager: WindowManager,
- viewUtil: ViewUtil,
mainExecutor: DelayableExecutor,
accessibilityManager: AccessibilityManager,
configurationController: ConfigurationController,
powerManager: PowerManager,
@Main private val mainHandler: Handler,
private val uiEventLogger: MediaTttReceiverUiEventLogger,
-) : MediaTttChipControllerCommon<ChipReceiverInfo>(
+) : TemporaryViewDisplayController<ChipReceiverInfo>(
context,
logger,
windowManager,
- viewUtil,
mainExecutor,
accessibilityManager,
configurationController,
@@ -119,18 +116,18 @@
uiEventLogger.logReceiverStateChange(chipState)
if (chipState == ChipStateReceiver.FAR_FROM_SENDER) {
- removeChip(removalReason = ChipStateReceiver.FAR_FROM_SENDER::class.simpleName!!)
+ removeView(removalReason = ChipStateReceiver.FAR_FROM_SENDER::class.simpleName!!)
return
}
if (appIcon == null) {
- displayChip(ChipReceiverInfo(routeInfo, appIconDrawableOverride = null, appName))
+ displayView(ChipReceiverInfo(routeInfo, appIconDrawableOverride = null, appName))
return
}
appIcon.loadDrawableAsync(
context,
Icon.OnDrawableLoadedListener { drawable ->
- displayChip(ChipReceiverInfo(routeInfo, drawable, appName))
+ displayView(ChipReceiverInfo(routeInfo, drawable, appName))
},
// Notify the listener on the main handler since the listener will update
// the UI.
@@ -138,19 +135,19 @@
)
}
- override fun updateChipView(newChipInfo: ChipReceiverInfo, currentChipView: ViewGroup) {
- super.updateChipView(newChipInfo, currentChipView)
+ override fun updateView(newInfo: ChipReceiverInfo, currentView: ViewGroup) {
+ super.updateView(newInfo, currentView)
val iconName = setIcon(
- currentChipView,
- newChipInfo.routeInfo.clientPackageName,
- newChipInfo.appIconDrawableOverride,
- newChipInfo.appNameOverride
+ currentView,
+ newInfo.routeInfo.clientPackageName,
+ newInfo.appIconDrawableOverride,
+ newInfo.appNameOverride
)
- currentChipView.contentDescription = iconName
+ currentView.contentDescription = iconName
}
- override fun animateChipIn(chipView: ViewGroup) {
- val appIconView = chipView.requireViewById<View>(R.id.app_icon)
+ override fun animateViewIn(view: ViewGroup) {
+ val appIconView = view.requireViewById<View>(R.id.app_icon)
appIconView.animate()
.translationYBy(-1 * getTranslationAmount().toFloat())
.setDuration(30.frames)
@@ -160,8 +157,8 @@
.setDuration(5.frames)
.start()
// Using withEndAction{} doesn't apply a11y focus when screen is unlocked.
- appIconView.postOnAnimation { chipView.requestAccessibilityFocus() }
- startRipple(chipView.requireViewById(R.id.ripple))
+ appIconView.postOnAnimation { view.requestAccessibilityFocus() }
+ startRipple(view.requireViewById(R.id.ripple))
}
override fun getIconSize(isAppIcon: Boolean): Int? =
@@ -216,7 +213,7 @@
val routeInfo: MediaRoute2Info,
val appIconDrawableOverride: Drawable?,
val appNameOverride: CharSequence?
-) : ChipInfoCommon {
+) : TemporaryViewInfo {
override fun getTimeoutMs() = DEFAULT_TIMEOUT_MILLIS
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt
index a153cb6..bde588c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt
@@ -25,7 +25,7 @@
import com.android.internal.logging.UiEventLogger
import com.android.internal.statusbar.IUndoMediaTransferCallback
import com.android.systemui.R
-import com.android.systemui.media.taptotransfer.common.DEFAULT_TIMEOUT_MILLIS
+import com.android.systemui.temporarydisplay.DEFAULT_TIMEOUT_MILLIS
/**
* A class enumerating all the possible states of the media tap-to-transfer chip on the sender
@@ -120,7 +120,7 @@
// state, but that may take too long to go through the binder and the user may be
// confused ast o why the UI hasn't changed yet. So, we immediately change the UI
// here.
- controllerSender.displayChip(
+ controllerSender.displayView(
ChipSenderInfo(
TRANSFER_TO_THIS_DEVICE_TRIGGERED, routeInfo, undoCallback
)
@@ -155,7 +155,7 @@
// state, but that may take too long to go through the binder and the user may be
// confused as to why the UI hasn't changed yet. So, we immediately change the UI
// here.
- controllerSender.displayChip(
+ controllerSender.displayView(
ChipSenderInfo(
TRANSFER_TO_RECEIVER_TRIGGERED, routeInfo, undoCallback
)
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt
index 9335489..0c1ebd7 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt
@@ -33,14 +33,13 @@
import com.android.systemui.animation.ViewHierarchyAnimator
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.media.taptotransfer.common.ChipInfoCommon
-import com.android.systemui.media.taptotransfer.common.MediaTttChipControllerCommon
import com.android.systemui.media.taptotransfer.common.MediaTttLogger
-import com.android.systemui.media.taptotransfer.common.MediaTttRemovalReason
import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.temporarydisplay.TemporaryDisplayRemovalReason
+import com.android.systemui.temporarydisplay.TemporaryViewDisplayController
+import com.android.systemui.temporarydisplay.TemporaryViewInfo
import com.android.systemui.util.concurrency.DelayableExecutor
-import com.android.systemui.util.view.ViewUtil
import javax.inject.Inject
/**
@@ -53,17 +52,15 @@
context: Context,
@MediaTttSenderLogger logger: MediaTttLogger,
windowManager: WindowManager,
- viewUtil: ViewUtil,
@Main mainExecutor: DelayableExecutor,
accessibilityManager: AccessibilityManager,
configurationController: ConfigurationController,
powerManager: PowerManager,
private val uiEventLogger: MediaTttSenderUiEventLogger
-) : MediaTttChipControllerCommon<ChipSenderInfo>(
+) : TemporaryViewDisplayController<ChipSenderInfo>(
context,
logger,
windowManager,
- viewUtil,
mainExecutor,
accessibilityManager,
configurationController,
@@ -106,53 +103,52 @@
uiEventLogger.logSenderStateChange(chipState)
if (chipState == ChipStateSender.FAR_FROM_RECEIVER) {
- removeChip(removalReason = ChipStateSender.FAR_FROM_RECEIVER::class.simpleName!!)
+ removeView(removalReason = ChipStateSender.FAR_FROM_RECEIVER::class.simpleName!!)
} else {
- displayChip(ChipSenderInfo(chipState, routeInfo, undoCallback))
+ displayView(ChipSenderInfo(chipState, routeInfo, undoCallback))
}
}
- /** Displays the chip view for the given state. */
- override fun updateChipView(
- newChipInfo: ChipSenderInfo,
- currentChipView: ViewGroup
+ override fun updateView(
+ newInfo: ChipSenderInfo,
+ currentView: ViewGroup
) {
- super.updateChipView(newChipInfo, currentChipView)
+ super.updateView(newInfo, currentView)
- val chipState = newChipInfo.state
+ val chipState = newInfo.state
// App icon
- val iconName = setIcon(currentChipView, newChipInfo.routeInfo.clientPackageName)
+ val iconName = setIcon(currentView, newInfo.routeInfo.clientPackageName)
// Text
- val otherDeviceName = newChipInfo.routeInfo.name.toString()
+ val otherDeviceName = newInfo.routeInfo.name.toString()
val chipText = chipState.getChipTextString(context, otherDeviceName)
- currentChipView.requireViewById<TextView>(R.id.text).text = chipText
+ currentView.requireViewById<TextView>(R.id.text).text = chipText
// Loading
- currentChipView.requireViewById<View>(R.id.loading).visibility =
+ currentView.requireViewById<View>(R.id.loading).visibility =
chipState.isMidTransfer.visibleIfTrue()
// Undo
- val undoView = currentChipView.requireViewById<View>(R.id.undo)
+ val undoView = currentView.requireViewById<View>(R.id.undo)
val undoClickListener = chipState.undoClickListener(
- this, newChipInfo.routeInfo, newChipInfo.undoCallback, uiEventLogger
+ this, newInfo.routeInfo, newInfo.undoCallback, uiEventLogger
)
undoView.setOnClickListener(undoClickListener)
undoView.visibility = (undoClickListener != null).visibleIfTrue()
// Failure
- currentChipView.requireViewById<View>(R.id.failure_icon).visibility =
+ currentView.requireViewById<View>(R.id.failure_icon).visibility =
chipState.isTransferFailure.visibleIfTrue()
// For accessibility
- currentChipView.requireViewById<ViewGroup>(
+ currentView.requireViewById<ViewGroup>(
R.id.media_ttt_sender_chip_inner
).contentDescription = "$iconName $chipText"
}
- override fun animateChipIn(chipView: ViewGroup) {
- val chipInnerView = chipView.requireViewById<ViewGroup>(R.id.media_ttt_sender_chip_inner)
+ override fun animateViewIn(view: ViewGroup) {
+ val chipInnerView = view.requireViewById<ViewGroup>(R.id.media_ttt_sender_chip_inner)
ViewHierarchyAnimator.animateAddition(
chipInnerView,
ViewHierarchyAnimator.Hotspot.TOP,
@@ -165,14 +161,14 @@
)
}
- override fun removeChip(removalReason: String) {
+ override fun removeView(removalReason: String) {
// Don't remove the chip if we're mid-transfer since the user should still be able to
// see the status of the transfer. (But do remove it if it's finally timed out.)
- if (chipInfo?.state?.isMidTransfer == true &&
- removalReason != MediaTttRemovalReason.REASON_TIMEOUT) {
+ if (info?.state?.isMidTransfer == true &&
+ removalReason != TemporaryDisplayRemovalReason.REASON_TIMEOUT) {
return
}
- super.removeChip(removalReason)
+ super.removeView(removalReason)
}
private fun Boolean.visibleIfTrue(): Int {
@@ -188,7 +184,7 @@
val state: ChipStateSender,
val routeInfo: MediaRoute2Info,
val undoCallback: IUndoMediaTransferCallback? = null
-) : ChipInfoCommon {
+) : TemporaryViewInfo {
override fun getTimeoutMs() = state.timeout
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index 75e48d2..30947e8 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -35,7 +35,6 @@
import static com.android.internal.accessibility.common.ShortcutConstants.CHOOSER_PACKAGE_NAME;
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.HOME_BUTTON_LONG_PRESS_DURATION_MS;
-import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.NAV_BAR_HANDLE_FORCE_OPAQUE;
import static com.android.systemui.navigationbar.NavBarHelper.transitionMode;
import static com.android.systemui.recents.OverviewProxyService.OverviewProxyListener;
import static com.android.systemui.shared.recents.utilities.Utilities.isTablet;
@@ -229,10 +228,7 @@
private Locale mLocale;
private int mLayoutDirection;
- private boolean mAllowForceNavBarHandleOpaque;
- private boolean mForceNavBarHandleOpaque;
private Optional<Long> mHomeButtonLongPressDurationMs;
- private boolean mIsCurrentUserSetup;
/** @see android.view.WindowInsetsController#setSystemBarsAppearance(int, int) */
private @Appearance int mAppearance;
@@ -379,37 +375,6 @@
}
@Override
- public void onNavBarButtonAlphaChanged(float alpha, boolean animate) {
- if (!mIsCurrentUserSetup) {
- // If the current user is not yet setup, then don't update any button alphas
- return;
- }
- if (QuickStepContract.isLegacyMode(mNavBarMode)) {
- // Don't allow the bar buttons to be affected by the alpha
- return;
- }
-
- ButtonDispatcher buttonDispatcher = null;
- boolean forceVisible = false;
- if (QuickStepContract.isGesturalMode(mNavBarMode)) {
- // Disallow home handle animations when in gestural
- animate = false;
- forceVisible = mAllowForceNavBarHandleOpaque && mForceNavBarHandleOpaque;
- buttonDispatcher = mView.getHomeHandle();
- if (getBarTransitions() != null) {
- getBarTransitions().setBackgroundOverrideAlpha(alpha);
- }
- } else if (QuickStepContract.isSwipeUpMode(mNavBarMode)) {
- buttonDispatcher = mView.getBackButton();
- }
- if (buttonDispatcher != null) {
- buttonDispatcher.setVisibility(
- (forceVisible || alpha > 0) ? View.VISIBLE : View.INVISIBLE);
- buttonDispatcher.setAlpha(forceVisible ? 1f : alpha, animate);
- }
- }
-
- @Override
public void onHomeRotationEnabled(boolean enabled) {
mView.getRotationButtonController().setHomeRotationEnabled(enabled);
}
@@ -456,15 +421,10 @@
new DeviceConfig.OnPropertiesChangedListener() {
@Override
public void onPropertiesChanged(DeviceConfig.Properties properties) {
- if (properties.getKeyset().contains(NAV_BAR_HANDLE_FORCE_OPAQUE)) {
- mForceNavBarHandleOpaque = properties.getBoolean(
- NAV_BAR_HANDLE_FORCE_OPAQUE, /* defaultValue = */ true);
- }
-
if (properties.getKeyset().contains(HOME_BUTTON_LONG_PRESS_DURATION_MS)) {
mHomeButtonLongPressDurationMs = Optional.of(
- properties.getLong(HOME_BUTTON_LONG_PRESS_DURATION_MS, 0)
- ).filter(duration -> duration != 0);
+ properties.getLong(HOME_BUTTON_LONG_PRESS_DURATION_MS, 0))
+ .filter(duration -> duration != 0);
if (mView != null) {
reconfigureHomeLongClick();
}
@@ -472,14 +432,6 @@
}
};
- private final DeviceProvisionedController.DeviceProvisionedListener mUserSetupListener =
- new DeviceProvisionedController.DeviceProvisionedListener() {
- @Override
- public void onUserSetupChanged() {
- mIsCurrentUserSetup = mDeviceProvisionedController.isCurrentUserSetup();
- }
- };
-
private final NotificationShadeDepthController.DepthListener mDepthListener =
new NotificationShadeDepthController.DepthListener() {
boolean mHasBlurs;
@@ -660,12 +612,6 @@
mCommandQueue.addCallback(this);
mLongPressHomeEnabled = mNavBarHelper.getLongPressHomeEnabled();
mNavBarHelper.init();
- mAllowForceNavBarHandleOpaque = mContext.getResources().getBoolean(
- R.bool.allow_force_nav_bar_handle_opaque);
- mForceNavBarHandleOpaque = mDeviceConfigProxy.getBoolean(
- DeviceConfig.NAMESPACE_SYSTEMUI,
- NAV_BAR_HANDLE_FORCE_OPAQUE,
- /* defaultValue = */ true);
mHomeButtonLongPressDurationMs = Optional.of(mDeviceConfigProxy.getLong(
DeviceConfig.NAMESPACE_SYSTEMUI,
HOME_BUTTON_LONG_PRESS_DURATION_MS,
@@ -685,8 +631,6 @@
// Respect the latest disabled-flags.
mCommandQueue.recomputeDisableFlags(mDisplayId, false);
- mIsCurrentUserSetup = mDeviceProvisionedController.isCurrentUserSetup();
- mDeviceProvisionedController.addCallback(mUserSetupListener);
mNotificationShadeDepthController.addListener(mDepthListener);
}
@@ -698,7 +642,6 @@
mNavBarHelper.removeNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
mNavBarHelper.destroy();
- mDeviceProvisionedController.removeCallback(mUserSetupListener);
mNotificationShadeDepthController.removeListener(mDepthListener);
mDeviceConfigProxy.removeOnPropertiesChangedListener(mOnPropertiesChangedListener);
diff --git a/packages/SystemUI/src/com/android/systemui/power/dagger/PowerModule.java b/packages/SystemUI/src/com/android/systemui/power/dagger/PowerModule.java
index 3709a86..7184fa0 100644
--- a/packages/SystemUI/src/com/android/systemui/power/dagger/PowerModule.java
+++ b/packages/SystemUI/src/com/android/systemui/power/dagger/PowerModule.java
@@ -20,13 +20,18 @@
import com.android.systemui.power.EnhancedEstimatesImpl;
import com.android.systemui.power.PowerNotificationWarnings;
import com.android.systemui.power.PowerUI;
+import com.android.systemui.power.data.repository.PowerRepositoryModule;
import dagger.Binds;
import dagger.Module;
/** Dagger Module for code in the power package. */
-@Module
+@Module(
+ includes = {
+ PowerRepositoryModule.class,
+ }
+)
public interface PowerModule {
/** */
@Binds
diff --git a/packages/SystemUI/src/com/android/systemui/power/data/repository/PowerRepository.kt b/packages/SystemUI/src/com/android/systemui/power/data/repository/PowerRepository.kt
new file mode 100644
index 0000000..b2e04bb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/power/data/repository/PowerRepository.kt
@@ -0,0 +1,74 @@
+/*
+ * 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.power.data.repository
+
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
+import android.os.PowerManager
+import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
+import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
+import com.android.systemui.dagger.SysUISingleton
+import javax.inject.Inject
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+
+/** Defines interface for classes that act as source of truth for power-related data. */
+interface PowerRepository {
+ /** Whether the device is interactive. Starts with the current state. */
+ val isInteractive: Flow<Boolean>
+}
+
+@SysUISingleton
+class PowerRepositoryImpl
+@Inject
+constructor(
+ manager: PowerManager,
+ dispatcher: BroadcastDispatcher,
+) : PowerRepository {
+
+ override val isInteractive: Flow<Boolean> = conflatedCallbackFlow {
+ fun send() {
+ trySendWithFailureLogging(manager.isInteractive, TAG)
+ }
+
+ val receiver =
+ object : BroadcastReceiver() {
+ override fun onReceive(context: Context?, intent: Intent?) {
+ send()
+ }
+ }
+
+ dispatcher.registerReceiver(
+ receiver,
+ IntentFilter().apply {
+ addAction(Intent.ACTION_SCREEN_ON)
+ addAction(Intent.ACTION_SCREEN_OFF)
+ },
+ )
+ send()
+
+ awaitClose { dispatcher.unregisterReceiver(receiver) }
+ }
+
+ companion object {
+ private const val TAG = "PowerRepository"
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeConstants.java b/packages/SystemUI/src/com/android/systemui/power/data/repository/PowerRepositoryModule.kt
similarity index 61%
copy from libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeConstants.java
copy to packages/SystemUI/src/com/android/systemui/power/data/repository/PowerRepositoryModule.kt
index e62a63a..491da65 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeConstants.java
+++ b/packages/SystemUI/src/com/android/systemui/power/data/repository/PowerRepositoryModule.kt
@@ -12,20 +12,15 @@
* WITHOUT 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.desktopmode;
+package com.android.systemui.power.data.repository
-import android.os.SystemProperties;
+import dagger.Binds
+import dagger.Module
-/**
- * Constants for desktop mode feature
- */
-public class DesktopModeConstants {
-
- /**
- * Flag to indicate whether desktop mode is available on the device
- */
- public static final boolean IS_FEATURE_ENABLED = SystemProperties.getBoolean(
- "persist.wm.debug.desktop_mode", false);
+@Module
+interface PowerRepositoryModule {
+ @Binds fun bindRepository(impl: PowerRepositoryImpl): PowerRepository
}
diff --git a/packages/SystemUI/src/com/android/systemui/power/domain/interactor/PowerInteractor.kt b/packages/SystemUI/src/com/android/systemui/power/domain/interactor/PowerInteractor.kt
new file mode 100644
index 0000000..3f799f7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/power/domain/interactor/PowerInteractor.kt
@@ -0,0 +1,34 @@
+/*
+ * 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.power.domain.interactor
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.power.data.repository.PowerRepository
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+
+/** Hosts business logic for interacting with the power system. */
+@SysUISingleton
+class PowerInteractor
+@Inject
+constructor(
+ repository: PowerRepository,
+) {
+ /** Whether the screen is on or off. */
+ val isInteractive: Flow<Boolean> = repository.isInteractive
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index 56298fa..920f463 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -16,6 +16,7 @@
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
+import android.annotation.NonNull;
import android.util.Log;
import android.util.Pair;
import android.util.SparseArray;
@@ -30,15 +31,11 @@
import com.android.systemui.plugins.qs.QS;
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.plugins.qs.QSTileView;
-import com.android.systemui.qs.PagedTileLayout.PageListener;
-import com.android.systemui.qs.QSHost.Callback;
import com.android.systemui.qs.QSPanel.QSTileLayout;
import com.android.systemui.qs.TouchAnimator.Builder;
-import com.android.systemui.qs.TouchAnimator.Listener;
import com.android.systemui.qs.dagger.QSScope;
import com.android.systemui.qs.tileimpl.HeightOverrideable;
import com.android.systemui.tuner.TunerService;
-import com.android.systemui.tuner.TunerService.Tunable;
import java.util.ArrayList;
import java.util.Collection;
@@ -47,16 +44,26 @@
import javax.inject.Inject;
-/** */
+/**
+ * Performs the animated transition between the QQS and QS views.
+ *
+ * <p>The transition is driven externally via {@link #setPosition(float)}, where 0 is a fully
+ * collapsed QQS and one a fully expanded QS.
+ *
+ * <p>This implementation maintains a set of {@code TouchAnimator} to transition the properties of
+ * views both in QQS and QS. These {@code TouchAnimator} are re-created lazily if contents of either
+ * view change, see {@link #requestAnimatorUpdate()}.
+ *
+ * <p>During the transition, both QS and QQS are visible. For overlapping tiles (Whenever the QS
+ * shows the first page), the corresponding QS tiles are hidden until QS is fully expanded.
+ */
@QSScope
-public class QSAnimator implements Callback, PageListener, Listener, OnLayoutChangeListener,
- OnAttachStateChangeListener, Tunable {
+public class QSAnimator implements QSHost.Callback, PagedTileLayout.PageListener,
+ TouchAnimator.Listener, OnLayoutChangeListener,
+ OnAttachStateChangeListener {
private static final String TAG = "QSAnimator";
- private static final String ALLOW_FANCY_ANIMATION = "sysui_qs_fancy_anim";
- private static final String MOVE_FULL_ROWS = "sysui_qs_move_whole_rows";
-
private static final float EXPANDED_TILE_DELAY = .86f;
//Non first page delays
private static final float QS_TILE_LABEL_FADE_OUT_START = 0.15f;
@@ -65,7 +72,6 @@
public static final float SHORT_PARALLAX_AMOUNT = 0.1f;
-
/**
* List of all views that will be reset when clearing animation state
* see {@link #clearAnimationState()} }
@@ -125,14 +131,11 @@
private boolean mNeedsAnimatorUpdate = false;
private boolean mOnKeyguard;
- private boolean mAllowFancy;
- private boolean mFullRows;
private int mNumQuickTiles;
private int mLastQQSTileHeight;
private float mLastPosition;
private final QSTileHost mHost;
private final Executor mExecutor;
- private final TunerService mTunerService;
private boolean mShowCollapsedOnKeyguard;
private boolean mTranslateWhileExpanding;
private int mQQSTop;
@@ -153,7 +156,6 @@
mQuickStatusBarHeader = quickStatusBarHeader;
mHost = qsTileHost;
mExecutor = executor;
- mTunerService = tunerService;
mQSExpansionPathInterpolator = qsExpansionPathInterpolator;
mHost.addCallback(this);
mQsPanelController.addOnAttachStateChangeListener(this);
@@ -199,7 +201,6 @@
setCurrentPosition();
}
-
private void setCurrentPosition() {
setPosition(mLastPosition);
}
@@ -210,30 +211,15 @@
}
@Override
- public void onViewAttachedToWindow(@Nullable View v) {
- mTunerService.addTunable(this, ALLOW_FANCY_ANIMATION,
- MOVE_FULL_ROWS);
- }
-
- @Override
- public void onViewDetachedFromWindow(View v) {
- mHost.removeCallback(this);
- mTunerService.removeTunable(this);
- }
-
- @Override
- public void onTuningChanged(String key, String newValue) {
- if (ALLOW_FANCY_ANIMATION.equals(key)) {
- mAllowFancy = TunerService.parseIntegerSwitch(newValue, true);
- if (!mAllowFancy) {
- clearAnimationState();
- }
- } else if (MOVE_FULL_ROWS.equals(key)) {
- mFullRows = TunerService.parseIntegerSwitch(newValue, true);
- }
+ public void onViewAttachedToWindow(@NonNull View view) {
updateAnimators();
}
+ @Override
+ public void onViewDetachedFromWindow(@NonNull View v) {
+ mHost.removeCallback(this);
+ }
+
private void addNonFirstPageAnimators(int page) {
Pair<HeightExpansionAnimator, TouchAnimator> pair = createSecondaryPageAnimators(page);
if (pair != null) {
@@ -339,8 +325,7 @@
View view = mQs.getView();
// This case: less tiles to animate in small displays.
- if (count < mQuickQSPanelController.getTileLayout().getNumVisibleTiles()
- && mAllowFancy) {
+ if (count < mQuickQSPanelController.getTileLayout().getNumVisibleTiles()) {
// Quick tiles.
QSTileView quickTileView = mQuickQSPanelController.getTileView(tile);
if (quickTileView == null) continue;
@@ -422,7 +407,7 @@
mAnimatedQsViews.add(tileView);
mAllViews.add(quickTileView);
mAllViews.add(quickTileView.getSecondaryLabel());
- } else if (mFullRows && isIconInAnimatedRow(count)) {
+ } else if (isIconInAnimatedRow(count)) {
firstPageBuilder.addFloat(tileView, "translationY", -heightDiff, 0);
@@ -457,44 +442,42 @@
}
}
- if (mAllowFancy) {
- animateBrightnessSlider(firstPageBuilder);
+ animateBrightnessSlider(firstPageBuilder);
- mFirstPageAnimator = firstPageBuilder
- // Fade in the tiles/labels as we reach the final position.
- .addFloat(tileLayout, "alpha", 0, 1)
- .addFloat(quadraticInterpolatorBuilder.build(), "position", 0, 1)
- .setListener(this)
- .build();
+ mFirstPageAnimator = firstPageBuilder
+ // Fade in the tiles/labels as we reach the final position.
+ .addFloat(tileLayout, "alpha", 0, 1)
+ .addFloat(quadraticInterpolatorBuilder.build(), "position", 0, 1)
+ .setListener(this)
+ .build();
- // Fade in the media player as we reach the final position
- Builder builder = new Builder().setStartDelay(EXPANDED_TILE_DELAY);
- if (mQsPanelController.shouldUseHorizontalLayout()
- && mQsPanelController.mMediaHost.hostView != null) {
- builder.addFloat(mQsPanelController.mMediaHost.hostView, "alpha", 0, 1);
- } else {
- // In portrait, media view should always be visible
- mQsPanelController.mMediaHost.hostView.setAlpha(1.0f);
- }
- mAllPagesDelayedAnimator = builder.build();
- translationYBuilder.setInterpolator(mQSExpansionPathInterpolator.getYInterpolator());
- qqsTranslationYBuilder.setInterpolator(mQSExpansionPathInterpolator.getYInterpolator());
- translationXBuilder.setInterpolator(mQSExpansionPathInterpolator.getXInterpolator());
- if (mOnFirstPage) {
- // Only recreate this animator if we're in the first page. That way we know that
- // the first page is attached and has the proper positions/measures.
- mQQSTranslationYAnimator = qqsTranslationYBuilder.build();
- }
- mTranslationYAnimator = translationYBuilder.build();
- mTranslationXAnimator = translationXBuilder.build();
- if (mQQSTileHeightAnimator != null) {
- mQQSTileHeightAnimator.setInterpolator(
- mQSExpansionPathInterpolator.getYInterpolator());
- }
- if (mOtherFirstPageTilesHeightAnimator != null) {
- mOtherFirstPageTilesHeightAnimator.setInterpolator(
- mQSExpansionPathInterpolator.getYInterpolator());
- }
+ // Fade in the media player as we reach the final position
+ Builder builder = new Builder().setStartDelay(EXPANDED_TILE_DELAY);
+ if (mQsPanelController.shouldUseHorizontalLayout()
+ && mQsPanelController.mMediaHost.hostView != null) {
+ builder.addFloat(mQsPanelController.mMediaHost.hostView, "alpha", 0, 1);
+ } else {
+ // In portrait, media view should always be visible
+ mQsPanelController.mMediaHost.hostView.setAlpha(1.0f);
+ }
+ mAllPagesDelayedAnimator = builder.build();
+ translationYBuilder.setInterpolator(mQSExpansionPathInterpolator.getYInterpolator());
+ qqsTranslationYBuilder.setInterpolator(mQSExpansionPathInterpolator.getYInterpolator());
+ translationXBuilder.setInterpolator(mQSExpansionPathInterpolator.getXInterpolator());
+ if (mOnFirstPage) {
+ // Only recreate this animator if we're in the first page. That way we know that
+ // the first page is attached and has the proper positions/measures.
+ mQQSTranslationYAnimator = qqsTranslationYBuilder.build();
+ }
+ mTranslationYAnimator = translationYBuilder.build();
+ mTranslationXAnimator = translationXBuilder.build();
+ if (mQQSTileHeightAnimator != null) {
+ mQQSTileHeightAnimator.setInterpolator(
+ mQSExpansionPathInterpolator.getYInterpolator());
+ }
+ if (mOtherFirstPageTilesHeightAnimator != null) {
+ mOtherFirstPageTilesHeightAnimator.setInterpolator(
+ mQSExpansionPathInterpolator.getYInterpolator());
}
mNonfirstPageAlphaAnimator = nonFirstPageAlphaBuilder
.addFloat(mQuickQsPanel, "alpha", 1, 0)
@@ -568,7 +551,7 @@
if (animator == null) {
animator = new HeightExpansionAnimator(
- this, mLastQQSTileHeight, tileView.getMeasuredHeight());
+ this, mLastQQSTileHeight, tileView.getMeasuredHeight());
animator.setInterpolator(mQSExpansionPathInterpolator.getYInterpolator());
}
animator.addView(tileView);
@@ -639,7 +622,7 @@
}
private void getRelativePositionInt(int[] loc1, View view, View parent) {
- if(view == parent || view == null) return;
+ if (view == parent || view == null) return;
// Ignore tile pages as they can have some offset we don't want to take into account in
// RTL.
if (!isAPage(view)) {
@@ -672,7 +655,6 @@
}
}
mLastPosition = position;
- if (!mAllowFancy) return;
if (mOnFirstPage) {
mQuickQsPanel.setAlpha(1);
mFirstPageAnimator.setPosition(position);
@@ -806,30 +788,31 @@
private final ValueAnimator.AnimatorUpdateListener mUpdateListener =
new ValueAnimator.AnimatorUpdateListener() {
- float mLastT = -1;
- @Override
- public void onAnimationUpdate(ValueAnimator valueAnimator) {
- float t = valueAnimator.getAnimatedFraction();
- final int viewCount = mViews.size();
- int height = (Integer) valueAnimator.getAnimatedValue();
- for (int i = 0; i < viewCount; i++) {
- View v = mViews.get(i);
- if (v instanceof HeightOverrideable) {
- ((HeightOverrideable) v).setHeightOverride(height);
- } else {
- v.setBottom(v.getTop() + height);
+ float mLastT = -1;
+
+ @Override
+ public void onAnimationUpdate(ValueAnimator valueAnimator) {
+ float t = valueAnimator.getAnimatedFraction();
+ final int viewCount = mViews.size();
+ int height = (Integer) valueAnimator.getAnimatedValue();
+ for (int i = 0; i < viewCount; i++) {
+ View v = mViews.get(i);
+ if (v instanceof HeightOverrideable) {
+ ((HeightOverrideable) v).setHeightOverride(height);
+ } else {
+ v.setBottom(v.getTop() + height);
+ }
+ }
+ if (t == 0f) {
+ mListener.onAnimationAtStart();
+ } else if (t == 1f) {
+ mListener.onAnimationAtEnd();
+ } else if (mLastT <= 0 || mLastT == 1) {
+ mListener.onAnimationStarted();
+ }
+ mLastT = t;
}
- }
- if (t == 0f) {
- mListener.onAnimationAtStart();
- } else if (t == 1f) {
- mListener.onAnimationAtEnd();
- } else if (mLastT <= 0 || mLastT == 1) {
- mListener.onAnimationStarted();
- }
- mLastT = t;
- }
- };
+ };
HeightExpansionAnimator(TouchAnimator.Listener listener, int startHeight, int endHeight) {
mListener = listener;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDetailClipper.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetailClipper.java
index b02efba..de11d56 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSDetailClipper.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSDetailClipper.java
@@ -39,8 +39,15 @@
mBackground = (TransitionDrawable) detail.getBackground();
}
- public void animateCircularClip(int x, int y, boolean in, AnimatorListener listener) {
- updateCircularClip(true /* animate */, x, y, in, listener);
+ /**
+ * @param x x position where animation should originate
+ * @param y y position where animation should originate
+ * @param in whether animating in or out
+ * @param listener Animation listener. Called whether or not {@code animate} is true.
+ * @return the duration of the circular animator
+ */
+ public long animateCircularClip(int x, int y, boolean in, AnimatorListener listener) {
+ return updateCircularClip(true /* animate */, x, y, in, listener);
}
/**
@@ -50,8 +57,9 @@
* @param y y position where animation should originate
* @param in whether animating in or out
* @param listener Animation listener. Called whether or not {@code animate} is true.
+ * @return the duration of the circular animator
*/
- public void updateCircularClip(boolean animate, int x, int y, boolean in,
+ public long updateCircularClip(boolean animate, int x, int y, boolean in,
AnimatorListener listener) {
if (mAnimator != null) {
mAnimator.cancel();
@@ -87,6 +95,7 @@
mAnimator.addListener(mGoneOnEnd);
}
mAnimator.start();
+ return mAnimator.getDuration();
}
private final Runnable mReverseBackground = new Runnable() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index 05b3eae..90fa94c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -34,6 +34,7 @@
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
+import androidx.annotation.FloatRange;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.lifecycle.Lifecycle;
@@ -166,6 +167,13 @@
// visible;
private boolean mQsVisible;
+ /**
+ * Whether the notification panel uses the full width of the screen.
+ *
+ * Usually {@code true} on small screens, and {@code false} on large screens.
+ */
+ private boolean mIsNotificationPanelFullWidth;
+
@Inject
public QSFragment(RemoteInputQuickSettingsDisabler remoteInputQsDisabler,
QSTileHost qsTileHost,
@@ -571,15 +579,17 @@
}
@Override
- public void setTransitionToFullShadeAmount(float pxAmount, float progress) {
- boolean isTransitioningToFullShade = pxAmount > 0;
+ public void setTransitionToFullShadeProgress(
+ boolean isTransitioningToFullShade,
+ @FloatRange(from = 0.0, to = 1.0) float qsTransitionFraction,
+ @FloatRange(from = 0.0, to = 1.0) float qsSquishinessFraction) {
if (isTransitioningToFullShade != mTransitioningToFullShade) {
mTransitioningToFullShade = isTransitioningToFullShade;
updateShowCollapsedOnKeyguard();
}
- mFullShadeProgress = progress;
+ mFullShadeProgress = qsTransitionFraction;
setQsExpansion(mLastQSExpansion, mLastPanelFraction, mLastHeaderTranslation,
- isTransitioningToFullShade ? progress : mSquishinessFraction);
+ isTransitioningToFullShade ? qsSquishinessFraction : mSquishinessFraction);
}
@Override
@@ -598,12 +608,16 @@
}
@Override
+ public void setIsNotificationPanelFullWidth(boolean isFullWidth) {
+ mIsNotificationPanelFullWidth = isFullWidth;
+ }
+
+ @Override
public void setQsExpansion(float expansion, float panelExpansionFraction,
float proposedTranslation, float squishinessFraction) {
float headerTranslation = mTransitioningToFullShade ? 0 : proposedTranslation;
- float alphaProgress = mTransitioningToFullShade || mState == StatusBarState.KEYGUARD
- ? mFullShadeProgress : panelExpansionFraction;
- setAlphaAnimationProgress(mInSplitShade ? alphaProgress : 1);
+ float alphaProgress = calculateAlphaProgress(panelExpansionFraction);
+ setAlphaAnimationProgress(alphaProgress);
mContainer.setExpansion(expansion);
final float translationScaleY = (mInSplitShade
? 1 : QSAnimator.SHORT_PARALLAX_AMOUNT) * (expansion - 1);
@@ -683,10 +697,43 @@
} else if (progress > 0 && view.getVisibility() != View.VISIBLE) {
view.setVisibility((View.VISIBLE));
}
- float alpha = mQSPanelController.isBouncerInTransit()
- ? BouncerPanelExpansionCalculator.aboutToShowBouncerProgress(progress)
- : ShadeInterpolation.getContentAlpha(progress);
- view.setAlpha(alpha);
+ view.setAlpha(interpolateAlphaAnimationProgress(progress));
+ }
+
+ private float calculateAlphaProgress(float panelExpansionFraction) {
+ if (mIsNotificationPanelFullWidth) {
+ // Small screens. QS alpha is not animated.
+ return 1;
+ }
+ if (mInSplitShade) {
+ // Large screens in landscape.
+ if (mTransitioningToFullShade || isKeyguardState()) {
+ // Always use "mFullShadeProgress" on keyguard, because
+ // "panelExpansionFractions" is always 1 on keyguard split shade.
+ return mFullShadeProgress;
+ } else {
+ return panelExpansionFraction;
+ }
+ }
+ // Large screens in portrait.
+ if (mTransitioningToFullShade) {
+ // Only use this value during the standard lock screen shade expansion. During the
+ // "quick" expansion from top, this value is 0.
+ return mFullShadeProgress;
+ } else {
+ return panelExpansionFraction;
+ }
+ }
+
+ private float interpolateAlphaAnimationProgress(float progress) {
+ if (mQSPanelController.isBouncerInTransit()) {
+ return BouncerPanelExpansionCalculator.aboutToShowBouncerProgress(progress);
+ }
+ if (isKeyguardState()) {
+ // Alpha progress should be linear on lockscreen shade expansion.
+ return progress;
+ }
+ return ShadeInterpolation.getContentAlpha(progress);
}
private void updateQsBounds() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 7155626..448e180 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -49,7 +49,6 @@
import java.util.ArrayList;
import java.util.List;
-import java.util.Objects;
/** View that represents the quick settings tile panel (when expanded/pulled down). **/
public class QSPanel extends LinearLayout implements Tunable {
@@ -291,7 +290,16 @@
} else {
topOffset = tileHeightOffset;
}
- int top = Objects.requireNonNull(mChildrenLayoutTop.get(child));
+ // Animation can occur before the layout pass, meaning setSquishinessFraction() gets
+ // called before onLayout(). So, a child view could be null because it has not
+ // been added to mChildrenLayoutTop yet (which happens in onLayout()).
+ // We use a continue statement here to catch this NPE because, on the layout pass,
+ // this code will be called again from onLayout() with the populated children views.
+ Integer childLayoutTop = mChildrenLayoutTop.get(child);
+ if (childLayoutTop == null) {
+ continue;
+ }
+ int top = childLayoutTop;
child.setLeftTopRightBottom(child.getLeft(), top + topOffset,
child.getRight(), top + topOffset + child.getHeight());
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
index 8f85905..59b871c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
@@ -28,6 +28,7 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.media.MediaCarouselController;
import com.android.systemui.media.MediaHierarchyManager;
import com.android.systemui.media.MediaHost;
import com.android.systemui.media.MediaHostState;
@@ -87,13 +88,14 @@
@Named(QS_USING_MEDIA_PLAYER) boolean usingMediaPlayer,
@Named(QS_PANEL) MediaHost mediaHost,
QSTileRevealController.Factory qsTileRevealControllerFactory,
- DumpManager dumpManager, MetricsLogger metricsLogger, UiEventLogger uiEventLogger,
+ DumpManager dumpManager, MediaCarouselController mediaCarouselController,
+ MetricsLogger metricsLogger, UiEventLogger uiEventLogger,
QSLogger qsLogger, BrightnessController.Factory brightnessControllerFactory,
BrightnessSliderController.Factory brightnessSliderFactory,
FalsingManager falsingManager,
StatusBarKeyguardViewManager statusBarKeyguardViewManager) {
super(view, qstileHost, qsCustomizerController, usingMediaPlayer, mediaHost,
- metricsLogger, uiEventLogger, qsLogger, dumpManager);
+ metricsLogger, uiEventLogger, qsLogger, dumpManager, mediaCarouselController);
mTunerService = tunerService;
mQsCustomizerController = qsCustomizerController;
mQsTileRevealControllerFactory = qsTileRevealControllerFactory;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
index 6d5f844..57bea67 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
@@ -31,6 +31,7 @@
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.Dumpable;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.media.MediaCarouselController;
import com.android.systemui.media.MediaHost;
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.plugins.qs.QSTileView;
@@ -68,6 +69,7 @@
private final UiEventLogger mUiEventLogger;
private final QSLogger mQSLogger;
private final DumpManager mDumpManager;
+ private final MediaCarouselController mMediaCarouselController;
protected final ArrayList<TileRecord> mRecords = new ArrayList<>();
protected boolean mShouldUseSplitNotificationShade;
@@ -122,7 +124,8 @@
MetricsLogger metricsLogger,
UiEventLogger uiEventLogger,
QSLogger qsLogger,
- DumpManager dumpManager
+ DumpManager dumpManager,
+ MediaCarouselController mediaCarouselController
) {
super(view);
mHost = host;
@@ -135,6 +138,7 @@
mDumpManager = dumpManager;
mShouldUseSplitNotificationShade =
LargeScreenUtils.shouldUseSplitNotificationShade(getResources());
+ mMediaCarouselController = mediaCarouselController;
}
@Override
@@ -152,6 +156,7 @@
public void setSquishinessFraction(float squishinessFraction) {
mView.setSquishinessFraction(squishinessFraction);
+ mMediaCarouselController.setSquishinessFraction(squishinessFraction);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
index b20d7ba..67bf300 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
@@ -97,7 +97,8 @@
super(rootView);
mFooterText = mView.findViewById(R.id.footer_text);
mPrimaryFooterIcon = mView.findViewById(R.id.primary_footer_icon);
- mFooterIcon = new Icon.Resource(R.drawable.ic_info_outline);
+ mFooterIcon = new Icon.Resource(
+ R.drawable.ic_info_outline, /* contentDescription= */ null);
mContext = rootView.getContext();
mSecurityController = securityController;
mMainHandler = mainHandler;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooterUtils.java b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooterUtils.java
index f632274..bd75c75 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooterUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooterUtils.java
@@ -75,6 +75,7 @@
import com.android.systemui.R;
import com.android.systemui.animation.DialogCuj;
import com.android.systemui.animation.DialogLaunchAnimator;
+import com.android.systemui.common.shared.model.ContentDescription;
import com.android.systemui.common.shared.model.Icon;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Application;
@@ -243,16 +244,17 @@
isWorkProfileOn).toString();
Icon icon;
+ ContentDescription contentDescription = null;
if (isParentalControlsEnabled) {
- icon = new Icon.Loaded(securityModel.getDeviceAdminIcon());
+ icon = new Icon.Loaded(securityModel.getDeviceAdminIcon(), contentDescription);
} else if (vpnName != null || vpnNameWorkProfile != null) {
if (securityModel.isVpnBranded()) {
- icon = new Icon.Resource(R.drawable.stat_sys_branded_vpn);
+ icon = new Icon.Resource(R.drawable.stat_sys_branded_vpn, contentDescription);
} else {
- icon = new Icon.Resource(R.drawable.stat_sys_vpn_ic);
+ icon = new Icon.Resource(R.drawable.stat_sys_vpn_ic, contentDescription);
}
} else {
- icon = new Icon.Resource(R.drawable.ic_info_outline);
+ icon = new Icon.Resource(R.drawable.ic_info_outline, contentDescription);
}
return new SecurityButtonConfig(icon, text, isClickable);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index 112b1e8..46724ad 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -54,7 +54,9 @@
@Override
public TileLayout getOrCreateTileLayout() {
- return new QQSSideLabelTileLayout(mContext);
+ QQSSideLabelTileLayout layout = new QQSSideLabelTileLayout(mContext);
+ layout.setId(R.id.qqs_tile_layout);
+ return layout;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
index be44202..c86e6e8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
@@ -26,6 +26,7 @@
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.R;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.media.MediaCarouselController;
import com.android.systemui.media.MediaHierarchyManager;
import com.android.systemui.media.MediaHost;
import com.android.systemui.plugins.qs.QSTile;
@@ -63,10 +64,10 @@
@Named(QS_USING_COLLAPSED_LANDSCAPE_MEDIA)
Provider<Boolean> usingCollapsedLandscapeMediaProvider,
MetricsLogger metricsLogger, UiEventLogger uiEventLogger, QSLogger qsLogger,
- DumpManager dumpManager
+ DumpManager dumpManager, MediaCarouselController mediaCarouselController
) {
super(view, qsTileHost, qsCustomizerController, usingMediaPlayer, mediaHost, metricsLogger,
- uiEventLogger, qsLogger, dumpManager);
+ uiEventLogger, qsLogger, dumpManager, mediaCarouselController);
mUsingCollapsedLandscapeMediaProvider = usingCollapsedLandscapeMediaProvider;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
index 2a6cf66..b585961 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
@@ -128,6 +128,8 @@
mPrivacyIconsController.setChipVisibilityListener(this);
mIconContainer.addIgnoredSlot(
getResources().getString(com.android.internal.R.string.status_bar_managed_profile));
+ mIconContainer.addIgnoredSlot(
+ getResources().getString(com.android.internal.R.string.status_bar_alarm_clock));
mIconContainer.setShouldRestrictIcons(false);
mStatusBarIconController.addIconGroup(mIconManager);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
index 8ad0119..cf10c79 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
@@ -125,9 +125,10 @@
isShown = true;
mOpening = true;
setVisibility(View.VISIBLE);
- mClipper.animateCircularClip(mX, mY, true, new ExpandAnimatorListener(tileAdapter));
+ long duration = mClipper.animateCircularClip(
+ mX, mY, true, new ExpandAnimatorListener(tileAdapter));
mQsContainerController.setCustomizerAnimating(true);
- mQsContainerController.setCustomizerShowing(true);
+ mQsContainerController.setCustomizerShowing(true, duration);
}
}
@@ -153,13 +154,14 @@
// Make sure we're not opening (because we're closing). Nobody can think we are
// customizing after the next two lines.
mOpening = false;
+ long duration = 0;
if (animate) {
- mClipper.animateCircularClip(mX, mY, false, mCollapseAnimationListener);
+ duration = mClipper.animateCircularClip(mX, mY, false, mCollapseAnimationListener);
} else {
setVisibility(View.GONE);
}
mQsContainerController.setCustomizerAnimating(animate);
- mQsContainerController.setCustomizerShowing(false);
+ mQsContainerController.setCustomizerShowing(false, duration);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/binder/FooterActionsViewBinder.kt b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/binder/FooterActionsViewBinder.kt
index 8dd506e..28ddead 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/binder/FooterActionsViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/binder/FooterActionsViewBinder.kt
@@ -31,7 +31,6 @@
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import com.android.systemui.R
-import com.android.systemui.common.ui.binder.ContentDescriptionViewBinder
import com.android.systemui.common.ui.binder.IconViewBinder
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.people.ui.view.PeopleViewBinder.bind
@@ -233,10 +232,8 @@
val icon = model.icon
val iconView = button.icon
- val contentDescription = model.contentDescription
IconViewBinder.bind(icon, iconView)
- ContentDescriptionViewBinder.bind(contentDescription, iconView)
if (model.iconTint != null) {
iconView.setColorFilter(model.iconTint, PorterDuff.Mode.SRC_IN)
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsButtonViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsButtonViewModel.kt
index 4c0879e..2ad0513 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsButtonViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsButtonViewModel.kt
@@ -18,7 +18,6 @@
import android.annotation.DrawableRes
import android.view.View
-import com.android.systemui.common.shared.model.ContentDescription
import com.android.systemui.common.shared.model.Icon
/**
@@ -29,7 +28,6 @@
val icon: Icon,
val iconTint: Int?,
@DrawableRes val background: Int,
- val contentDescription: ContentDescription,
// TODO(b/230830644): Replace View by an Expandable interface that can expand in either dialog
// or activity.
val onClick: (View) -> Unit,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt
index b556a3e..a935338 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt
@@ -138,10 +138,12 @@
/** The model for the settings button. */
val settings: FooterActionsButtonViewModel =
FooterActionsButtonViewModel(
- Icon.Resource(R.drawable.ic_settings),
+ Icon.Resource(
+ R.drawable.ic_settings,
+ ContentDescription.Resource(R.string.accessibility_quick_settings_settings)
+ ),
iconTint = null,
R.drawable.qs_footer_action_circle,
- ContentDescription.Resource(R.string.accessibility_quick_settings_settings),
this::onSettingsButtonClicked,
)
@@ -149,14 +151,16 @@
val power: FooterActionsButtonViewModel? =
if (showPowerButton) {
FooterActionsButtonViewModel(
- Icon.Resource(android.R.drawable.ic_lock_power_off),
+ Icon.Resource(
+ android.R.drawable.ic_lock_power_off,
+ ContentDescription.Resource(R.string.accessibility_quick_settings_power_menu)
+ ),
iconTint =
Utils.getColorAttrDefaultColor(
context,
com.android.internal.R.attr.textColorOnAccent,
),
R.drawable.qs_footer_action_circle_color,
- ContentDescription.Resource(R.string.accessibility_quick_settings_power_menu),
this::onPowerButtonClicked,
)
} else {
@@ -252,10 +256,12 @@
}
return FooterActionsButtonViewModel(
- Icon.Loaded(icon),
+ Icon.Loaded(
+ icon,
+ ContentDescription.Loaded(userSwitcherContentDescription(status.currentUserName)),
+ ),
iconTint,
R.drawable.qs_footer_action_circle,
- ContentDescription.Loaded(userSwitcherContentDescription(status.currentUserName)),
this::onUserSwitcherClicked,
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
index be6982a..5842665 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
@@ -165,7 +165,7 @@
iv.clearColorFilter();
}
if (state.state != mState) {
- int color = getColor(state.state);
+ int color = getColor(state);
mState = state.state;
if (mTint != 0 && allowAnimations && shouldAnimate(iv)) {
animateGrayScale(mTint, color, iv, () -> updateIcon(iv, state, allowAnimations));
@@ -183,7 +183,7 @@
}
}
- protected int getColor(int state) {
+ protected int getColor(QSTile.State state) {
return getIconColorForState(getContext(), state);
}
@@ -239,19 +239,18 @@
/**
* Color to tint the tile icon based on state
*/
- public static int getIconColorForState(Context context, int state) {
- switch (state) {
- case Tile.STATE_UNAVAILABLE:
- return Utils.applyAlpha(QSTileViewImpl.UNAVAILABLE_ALPHA,
- Utils.getColorAttrDefaultColor(context, android.R.attr.textColorPrimary));
- case Tile.STATE_INACTIVE:
- return Utils.getColorAttrDefaultColor(context, android.R.attr.textColorPrimary);
- case Tile.STATE_ACTIVE:
- return Utils.getColorAttrDefaultColor(context,
- com.android.internal.R.attr.textColorOnAccent);
- default:
- Log.e("QSIconView", "Invalid state " + state);
- return 0;
+ private static int getIconColorForState(Context context, QSTile.State state) {
+ if (state.disabledByPolicy || state.state == Tile.STATE_UNAVAILABLE) {
+ return Utils.applyAlpha(QSTileViewImpl.UNAVAILABLE_ALPHA,
+ Utils.getColorAttrDefaultColor(context, android.R.attr.textColorPrimary));
+ } else if (state.state == Tile.STATE_INACTIVE) {
+ return Utils.getColorAttrDefaultColor(context, android.R.attr.textColorPrimary);
+ } else if (state.state == Tile.STATE_ACTIVE) {
+ return Utils.getColorAttrDefaultColor(context,
+ com.android.internal.R.attr.textColorOnAccent);
+ } else {
+ Log.e("QSIconView", "Invalid state " + state);
+ return 0;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
index 2731d64..163ee2a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
@@ -35,6 +35,7 @@
import android.view.ViewGroup
import android.view.accessibility.AccessibilityEvent
import android.view.accessibility.AccessibilityNodeInfo
+import android.widget.Button
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.Switch
@@ -144,6 +145,7 @@
superSetVisibility = { super.setVisibility(it) },
superSetTransitionVisibility = { super.setTransitionVisibility(it) },
)
+ private var lastDisabledByPolicy = false
private val locInScreen = IntArray(2)
@@ -376,8 +378,22 @@
super.onInitializeAccessibilityNodeInfo(info)
// Clear selected state so it is not announce by talkback.
info.isSelected = false
+ if (lastDisabledByPolicy) {
+ info.addAction(
+ AccessibilityNodeInfo.AccessibilityAction(
+ AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK.id,
+ resources.getString(
+ R.string.accessibility_tile_disabled_by_policy_action_description
+ )
+ )
+ )
+ }
if (!TextUtils.isEmpty(accessibilityClass)) {
- info.className = accessibilityClass
+ info.className = if (lastDisabledByPolicy) {
+ Button::class.java.name
+ } else {
+ accessibilityClass
+ }
if (Switch::class.java.name == accessibilityClass) {
val label = resources.getString(
if (tileState) R.string.switch_bar_on else R.string.switch_bar_off)
@@ -430,6 +446,10 @@
state.secondaryLabel = stateText
}
}
+ if (state.disabledByPolicy && state.state != Tile.STATE_UNAVAILABLE) {
+ stateDescription.append(", ")
+ stateDescription.append(getUnavailableText(state.spec))
+ }
if (!TextUtils.isEmpty(state.stateDescription)) {
stateDescription.append(", ")
stateDescription.append(state.stateDescription)
@@ -470,38 +490,38 @@
}
// Colors
- if (state.state != lastState) {
+ if (state.state != lastState || state.disabledByPolicy || lastDisabledByPolicy) {
singleAnimator.cancel()
if (allowAnimations) {
singleAnimator.setValues(
colorValuesHolder(
BACKGROUND_NAME,
paintColor,
- getBackgroundColorForState(state.state)
+ getBackgroundColorForState(state.state, state.disabledByPolicy)
),
colorValuesHolder(
LABEL_NAME,
label.currentTextColor,
- getLabelColorForState(state.state)
+ getLabelColorForState(state.state, state.disabledByPolicy)
),
colorValuesHolder(
SECONDARY_LABEL_NAME,
secondaryLabel.currentTextColor,
- getSecondaryLabelColorForState(state.state)
+ getSecondaryLabelColorForState(state.state, state.disabledByPolicy)
),
colorValuesHolder(
CHEVRON_NAME,
chevronView.imageTintList?.defaultColor ?: 0,
- getChevronColorForState(state.state)
+ getChevronColorForState(state.state, state.disabledByPolicy)
)
)
singleAnimator.start()
} else {
setAllColors(
- getBackgroundColorForState(state.state),
- getLabelColorForState(state.state),
- getSecondaryLabelColorForState(state.state),
- getChevronColorForState(state.state)
+ getBackgroundColorForState(state.state, state.disabledByPolicy),
+ getLabelColorForState(state.state, state.disabledByPolicy),
+ getSecondaryLabelColorForState(state.state, state.disabledByPolicy),
+ getChevronColorForState(state.state, state.disabledByPolicy)
)
}
}
@@ -512,6 +532,7 @@
label.isEnabled = !state.disabledByPolicy
lastState = state.state
+ lastDisabledByPolicy = state.disabledByPolicy
}
private fun setAllColors(
@@ -559,13 +580,14 @@
}
}
- private fun getStateText(state: QSTile.State): String {
- if (state.disabledByPolicy) {
- return context.getString(R.string.tile_disabled)
- }
+ private fun getUnavailableText(spec: String?): String {
+ val arrayResId = SubtitleArrayMapping.getSubtitleId(spec)
+ return resources.getStringArray(arrayResId)[Tile.STATE_UNAVAILABLE]
+ }
+ private fun getStateText(state: QSTile.State): String {
return if (state.state == Tile.STATE_UNAVAILABLE || state is BooleanState) {
- var arrayResId = SubtitleArrayMapping.getSubtitleId(state.spec)
+ val arrayResId = SubtitleArrayMapping.getSubtitleId(state.spec)
val array = resources.getStringArray(arrayResId)
array[state.state]
} else {
@@ -587,11 +609,11 @@
return locInScreen.get(1) >= -height
}
- private fun getBackgroundColorForState(state: Int): Int {
- return when (state) {
- Tile.STATE_ACTIVE -> colorActive
- Tile.STATE_INACTIVE -> colorInactive
- Tile.STATE_UNAVAILABLE -> colorUnavailable
+ private fun getBackgroundColorForState(state: Int, disabledByPolicy: Boolean = false): Int {
+ return when {
+ state == Tile.STATE_UNAVAILABLE || disabledByPolicy -> colorUnavailable
+ state == Tile.STATE_ACTIVE -> colorActive
+ state == Tile.STATE_INACTIVE -> colorInactive
else -> {
Log.e(TAG, "Invalid state $state")
0
@@ -599,11 +621,11 @@
}
}
- private fun getLabelColorForState(state: Int): Int {
- return when (state) {
- Tile.STATE_ACTIVE -> colorLabelActive
- Tile.STATE_INACTIVE -> colorLabelInactive
- Tile.STATE_UNAVAILABLE -> colorLabelUnavailable
+ private fun getLabelColorForState(state: Int, disabledByPolicy: Boolean = false): Int {
+ return when {
+ state == Tile.STATE_UNAVAILABLE || disabledByPolicy -> colorLabelUnavailable
+ state == Tile.STATE_ACTIVE -> colorLabelActive
+ state == Tile.STATE_INACTIVE -> colorLabelInactive
else -> {
Log.e(TAG, "Invalid state $state")
0
@@ -611,11 +633,11 @@
}
}
- private fun getSecondaryLabelColorForState(state: Int): Int {
- return when (state) {
- Tile.STATE_ACTIVE -> colorSecondaryLabelActive
- Tile.STATE_INACTIVE -> colorSecondaryLabelInactive
- Tile.STATE_UNAVAILABLE -> colorSecondaryLabelUnavailable
+ private fun getSecondaryLabelColorForState(state: Int, disabledByPolicy: Boolean = false): Int {
+ return when {
+ state == Tile.STATE_UNAVAILABLE || disabledByPolicy -> colorSecondaryLabelUnavailable
+ state == Tile.STATE_ACTIVE -> colorSecondaryLabelActive
+ state == Tile.STATE_INACTIVE -> colorSecondaryLabelInactive
else -> {
Log.e(TAG, "Invalid state $state")
0
@@ -623,7 +645,16 @@
}
}
- private fun getChevronColorForState(state: Int): Int = getSecondaryLabelColorForState(state)
+ private fun getChevronColorForState(state: Int, disabledByPolicy: Boolean = false): Int =
+ getSecondaryLabelColorForState(state, disabledByPolicy)
+
+ @VisibleForTesting
+ internal fun getCurrentColors(): List<Int> = listOf(
+ paintColor,
+ label.currentTextColor,
+ secondaryLabel.currentTextColor,
+ chevronView.imageTintList?.defaultColor ?: 0
+ )
}
@VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt
index 05b3420..c65bd9b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt
@@ -31,7 +31,6 @@
import com.android.systemui.controls.dagger.ControlsComponent
import com.android.systemui.controls.dagger.ControlsComponent.Visibility.AVAILABLE
import com.android.systemui.controls.management.ControlsListingController
-import com.android.systemui.controls.ui.ControlsActivity
import com.android.systemui.controls.ui.ControlsUiController
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
@@ -42,7 +41,6 @@
import com.android.systemui.qs.QSHost
import com.android.systemui.qs.logging.QSLogger
import com.android.systemui.qs.tileimpl.QSTileImpl
-import com.android.systemui.statusbar.policy.KeyguardStateController
import java.util.concurrent.atomic.AtomicBoolean
import javax.inject.Inject
@@ -55,8 +53,7 @@
statusBarStateController: StatusBarStateController,
activityStarter: ActivityStarter,
qsLogger: QSLogger,
- private val controlsComponent: ControlsComponent,
- private val keyguardStateController: KeyguardStateController
+ private val controlsComponent: ControlsComponent
) : QSTileImpl<QSTile.State>(
host,
backgroundLooper,
@@ -105,7 +102,8 @@
}
val intent = Intent().apply {
- component = ComponentName(mContext, ControlsActivity::class.java)
+ component = ComponentName(mContext, controlsComponent.getControlsUiController().get()
+ .resolveActivity())
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK)
putExtra(ControlsUiController.EXTRA_ANIMATE, true)
}
@@ -127,10 +125,15 @@
state.icon = icon
if (controlsComponent.isEnabled() && hasControlsApps.get()) {
if (controlsComponent.getVisibility() == AVAILABLE) {
- val structure = controlsComponent
- .getControlsController().get().getPreferredStructure().structure
- state.state = Tile.STATE_ACTIVE
- state.secondaryLabel = if (structure == tileLabel) null else structure
+ val structureInfo = controlsComponent
+ .getControlsController().get().getPreferredStructure()
+ state.state = if (structureInfo.controls.isEmpty()) {
+ Tile.STATE_INACTIVE
+ } else {
+ Tile.STATE_ACTIVE
+ }
+ val label = structureInfo.structure
+ state.secondaryLabel = if (label == tileLabel) null else label
} else {
state.state = Tile.STATE_INACTIVE
state.secondaryLabel = mContext.getText(R.string.controls_tile_locked)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java
index e2964ea..f60e066 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java
@@ -17,6 +17,7 @@
package com.android.systemui.qs.tiles;
import android.app.UiModeManager;
+import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.os.Handler;
@@ -60,9 +61,7 @@
ConfigurationController.ConfigurationListener,
BatteryController.BatteryStateChangeCallback {
public static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("hh:mm a");
- private final Icon mIcon = ResourceIcon.get(
- com.android.internal.R.drawable.ic_qs_ui_mode_night);
- private UiModeManager mUiModeManager;
+ private final UiModeManager mUiModeManager;
private final BatteryController mBatteryController;
private final LocationController mLocationController;
@Inject
@@ -82,7 +81,8 @@
super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
statusBarStateController, activityStarter, qsLogger);
mBatteryController = batteryController;
- mUiModeManager = host.getUserContext().getSystemService(UiModeManager.class);
+ mUiModeManager = (UiModeManager) host.getUserContext().getSystemService(
+ Context.UI_MODE_SERVICE);
mLocationController = locationController;
configurationController.observe(getLifecycle(), this);
batteryController.observe(getLifecycle(), this);
@@ -155,7 +155,6 @@
}
state.value = nightMode;
state.label = mContext.getString(R.string.quick_settings_ui_mode_night_label);
- state.icon = mIcon;
state.contentDescription = TextUtils.isEmpty(state.secondaryLabel)
? state.label
: TextUtils.concat(state.label, ", ", state.secondaryLabel);
@@ -164,6 +163,9 @@
} else {
state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
}
+ state.icon = ResourceIcon.get(state.state == Tile.STATE_ACTIVE
+ ? R.drawable.qs_light_dark_theme_icon_on
+ : R.drawable.qs_light_dark_theme_icon_off);
state.showRippleEffect = false;
state.expandedAccessibilityClassName = Switch.class.getName();
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index 30862b7..3788ad9 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -61,6 +61,7 @@
import android.os.IBinder;
import android.os.Looper;
import android.os.PatternMatcher;
+import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
@@ -174,7 +175,6 @@
private boolean mBound;
private boolean mIsEnabled;
private int mCurrentBoundedUserId = -1;
- private float mNavBarButtonAlpha;
private boolean mInputFocusTransferStarted;
private float mInputFocusTransferStartY;
private long mInputFocusTransferStartMillis;
@@ -296,12 +296,6 @@
}
@Override
- public void setNavBarButtonAlpha(float alpha, boolean animate) {
- verifyCallerAndClearCallingIdentityPostMain("setNavBarButtonAlpha", () ->
- notifyNavBarButtonAlphaChanged(alpha, animate));
- }
-
- @Override
public void onAssistantProgress(@FloatRange(from = 0.0, to = 1.0) float progress) {
verifyCallerAndClearCallingIdentityPostMain("onAssistantProgress", () ->
notifyAssistantProgress(progress));
@@ -581,6 +575,12 @@
AssistUtils assistUtils,
DumpManager dumpManager) {
super(broadcastDispatcher);
+
+ // b/241601880: This component shouldn't be running for a non-primary user
+ if (!Process.myUserHandle().equals(UserHandle.SYSTEM)) {
+ Log.e(TAG_OPS, "Unexpected initialization for non-primary user", new Throwable());
+ }
+
mContext = context;
mPipOptional = pipOptional;
mCentralSurfacesOptionalLazy = centralSurfacesOptionalLazy;
@@ -603,9 +603,6 @@
mBackAnimation = backAnimation;
mUiEventLogger = uiEventLogger;
- // Assumes device always starts with back button until launcher tells it that it does not
- mNavBarButtonAlpha = 1.0f;
-
dumpManager.registerDumpable(getClass().getSimpleName(), this);
// Listen for nav bar mode changes
@@ -807,7 +804,6 @@
mConnectionCallbacks.add(listener);
}
listener.onConnectionChanged(mOverviewProxy != null);
- listener.onNavBarButtonAlphaChanged(mNavBarButtonAlpha, false);
}
@Override
@@ -837,17 +833,10 @@
if (mOverviewProxy != null) {
mOverviewProxy.asBinder().unlinkToDeath(mOverviewServiceDeathRcpt, 0);
mOverviewProxy = null;
- notifyNavBarButtonAlphaChanged(1f, false /* animate */);
notifyConnectionChanged();
}
}
- private void notifyNavBarButtonAlphaChanged(float alpha, boolean animate) {
- for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
- mConnectionCallbacks.get(i).onNavBarButtonAlphaChanged(alpha, animate);
- }
- }
-
private void notifyHomeRotationEnabled(boolean enabled) {
for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
mConnectionCallbacks.get(i).onHomeRotationEnabled(enabled);
@@ -1076,7 +1065,6 @@
pw.print(" mInputFocusTransferStartMillis="); pw.println(mInputFocusTransferStartMillis);
pw.print(" mWindowCornerRadius="); pw.println(mWindowCornerRadius);
pw.print(" mSupportsRoundedCornersOnWindows="); pw.println(mSupportsRoundedCornersOnWindows);
- pw.print(" mNavBarButtonAlpha="); pw.println(mNavBarButtonAlpha);
pw.print(" mActiveNavBarRegion="); pw.println(mActiveNavBarRegion);
pw.print(" mNavBarMode="); pw.println(mNavBarMode);
mSysUiState.dump(pw, args);
@@ -1091,8 +1079,6 @@
default void onQuickScrubStarted() {}
/** Notify the recents app (overview) is started by 3-button navigation. */
default void onToggleRecentApps() {}
- /** Notify changes in the nav bar button alpha */
- default void onNavBarButtonAlphaChanged(float alpha, boolean animate) {}
default void onHomeRotationEnabled(boolean enabled) {}
default void onTaskbarStatusUpdated(boolean visible, boolean stashed) {}
default void onTaskbarAutohideSuspend(boolean suspend) {}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/LargeScreenShadeHeaderController.kt b/packages/SystemUI/src/com/android/systemui/shade/LargeScreenShadeHeaderController.kt
index fab70fc..fe40d4c 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/LargeScreenShadeHeaderController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/LargeScreenShadeHeaderController.kt
@@ -30,6 +30,7 @@
import com.android.settingslib.Utils
import com.android.systemui.Dumpable
import com.android.systemui.R
+import com.android.systemui.animation.Interpolators
import com.android.systemui.animation.ShadeInterpolation
import com.android.systemui.battery.BatteryMeterView
import com.android.systemui.battery.BatteryMeterViewController
@@ -270,6 +271,14 @@
qsCarrierGroupController = qsCarrierGroupControllerBuilder
.setQSCarrierGroup(qsCarrierGroup)
.build()
+
+ if (!combinedHeaders) {
+ // In the new header, we display alarm icon but we ignore it when not using the new
+ // headers.
+ iconContainer.addIgnoredSlot(
+ context.getString(com.android.internal.R.string.status_bar_alarm_clock)
+ )
+ }
}
override fun onViewAttached() {
@@ -302,6 +311,14 @@
updateVisibility()
}
+ fun startCustomizingAnimation(show: Boolean, duration: Long) {
+ header.animate()
+ .setDuration(duration)
+ .alpha(if (show) 0f else 1f)
+ .setInterpolator(if (show) Interpolators.ALPHA_OUT else Interpolators.ALPHA_IN)
+ .start()
+ }
+
private fun loadConstraints() {
if (header is MotionLayout) {
// Use resources.getXml instead of passing the resource id due to bug b/205018300
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 70c0cab..3429b9d 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -97,6 +97,7 @@
import com.android.internal.policy.SystemBarUtils;
import com.android.internal.util.LatencyTracker;
import com.android.keyguard.ActiveUnlockConfig;
+import com.android.keyguard.FaceAuthApiRequestReason;
import com.android.keyguard.KeyguardClockSwitch.ClockSize;
import com.android.keyguard.KeyguardStatusView;
import com.android.keyguard.KeyguardStatusViewController;
@@ -116,7 +117,6 @@
import com.android.systemui.camera.CameraGestureHelper;
import com.android.systemui.classifier.Classifier;
import com.android.systemui.classifier.FalsingCollector;
-import com.android.systemui.controls.dagger.ControlsComponent;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.DisplayId;
import com.android.systemui.dagger.qualifiers.Main;
@@ -139,7 +139,6 @@
import com.android.systemui.plugins.qs.QS;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
-import com.android.systemui.qrcodescanner.controller.QRCodeScannerController;
import com.android.systemui.screenrecord.RecordingController;
import com.android.systemui.shade.transition.ShadeTransitionController;
import com.android.systemui.shared.system.QuickStepContract;
@@ -161,7 +160,6 @@
import com.android.systemui.statusbar.notification.AnimatableProperty;
import com.android.systemui.statusbar.notification.ConversationNotificationManager;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
import com.android.systemui.statusbar.notification.PropertyAnimator;
import com.android.systemui.statusbar.notification.ViewGroupFadeHelper;
@@ -217,7 +215,6 @@
import com.android.systemui.util.ListenerSet;
import com.android.systemui.util.Utils;
import com.android.systemui.util.time.SystemClock;
-import com.android.systemui.wallet.controller.QuickAccessWalletController;
import com.android.wm.shell.animation.FlingAnimationUtils;
import java.io.PrintWriter;
@@ -325,9 +322,6 @@
private final FragmentService mFragmentService;
private final ScrimController mScrimController;
private final PrivacyDotViewController mPrivacyDotViewController;
- private final QuickAccessWalletController mQuickAccessWalletController;
- private final QRCodeScannerController mQRCodeScannerController;
- private final ControlsComponent mControlsComponent;
private final NotificationRemoteInputManager mRemoteInputManager;
private final LockscreenShadeTransitionController mLockscreenShadeTransitionController;
@@ -449,6 +443,8 @@
private boolean mQsTouchAboveFalsingThreshold;
private int mQsFalsingThreshold;
+ /** Indicates drag starting height when swiping down or up on heads-up notifications */
+ private int mHeadsUpStartHeight;
private HeadsUpTouchHelper mHeadsUpTouchHelper;
private boolean mListenForHeadsUp;
private int mNavigationBarBottomHeight;
@@ -518,7 +514,6 @@
}
}).setCustomInterpolator(
mPanelAlphaAnimator.getProperty(), Interpolators.ALPHA_IN);
- private final NotificationEntryManager mEntryManager;
private final CommandQueue mCommandQueue;
private final UserManager mUserManager;
@@ -652,6 +647,8 @@
/** The drag distance required to fully expand the split shade. */
private int mSplitShadeFullTransitionDistance;
+ /** The drag distance required to fully transition scrims. */
+ private int mSplitShadeScrimTransitionDistance;
private final NotificationListContainer mNotificationListContainer;
private final NotificationStackSizeCalculator mNotificationStackSizeCalculator;
@@ -697,8 +694,8 @@
};
private final CameraGestureHelper mCameraGestureHelper;
- private final Provider<KeyguardBottomAreaViewModel> mKeyguardBottomAreaViewModelProvider;
- private final Provider<KeyguardBottomAreaInteractor> mKeyguardBottomAreaInteractorProvider;
+ private final KeyguardBottomAreaViewModel mKeyguardBottomAreaViewModel;
+ private final KeyguardBottomAreaInteractor mKeyguardBottomAreaInteractor;
@Inject
public NotificationPanelViewController(NotificationPanelView view,
@@ -709,7 +706,6 @@
DynamicPrivacyController dynamicPrivacyController,
KeyguardBypassController bypassController, FalsingManager falsingManager,
FalsingCollector falsingCollector,
- NotificationEntryManager notificationEntryManager,
KeyguardStateController keyguardStateController,
StatusBarStateController statusBarStateController,
StatusBarWindowStateController statusBarWindowStateController,
@@ -748,8 +744,6 @@
NavigationModeController navigationModeController,
FragmentService fragmentService,
ContentResolver contentResolver,
- QuickAccessWalletController quickAccessWalletController,
- QRCodeScannerController qrCodeScannerController,
RecordingController recordingController,
LargeScreenShadeHeaderController largeScreenShadeHeaderController,
ScreenOffAnimationController screenOffAnimationController,
@@ -757,7 +751,6 @@
PanelExpansionStateManager panelExpansionStateManager,
NotificationRemoteInputManager remoteInputManager,
Optional<SysUIUnfoldComponent> unfoldComponent,
- ControlsComponent controlsComponent,
InteractionJankMonitor interactionJankMonitor,
QsFrameTranslateController qsFrameTranslateController,
SysUiState sysUiState,
@@ -770,8 +763,8 @@
ShadeTransitionController shadeTransitionController,
SystemClock systemClock,
CameraGestureHelper cameraGestureHelper,
- Provider<KeyguardBottomAreaViewModel> keyguardBottomAreaViewModelProvider,
- Provider<KeyguardBottomAreaInteractor> keyguardBottomAreaInteractorProvider) {
+ KeyguardBottomAreaViewModel keyguardBottomAreaViewModel,
+ KeyguardBottomAreaInteractor keyguardBottomAreaInteractor) {
super(view,
falsingManager,
dozeLog,
@@ -793,9 +786,6 @@
mVibratorHelper = vibratorHelper;
mKeyguardMediaController = keyguardMediaController;
mPrivacyDotViewController = privacyDotViewController;
- mQuickAccessWalletController = quickAccessWalletController;
- mQRCodeScannerController = qrCodeScannerController;
- mControlsComponent = controlsComponent;
mMetricsLogger = metricsLogger;
mConfigurationController = configurationController;
mFlingAnimationUtilsBuilder = flingAnimationUtilsBuilder;
@@ -867,7 +857,6 @@
});
mBottomAreaShadeAlphaAnimator.setDuration(160);
mBottomAreaShadeAlphaAnimator.setInterpolator(Interpolators.ALPHA_OUT);
- mEntryManager = notificationEntryManager;
mConversationNotificationManager = conversationNotificationManager;
mAuthController = authController;
mLockIconViewController = lockIconViewController;
@@ -900,7 +889,7 @@
mQsFrameTranslateController = qsFrameTranslateController;
updateUserSwitcherFlags();
- mKeyguardBottomAreaViewModelProvider = keyguardBottomAreaViewModelProvider;
+ mKeyguardBottomAreaViewModel = keyguardBottomAreaViewModel;
onFinishInflate();
keyguardUnlockAnimationController.addKeyguardUnlockAnimationListener(
new KeyguardUnlockAnimationController.KeyguardUnlockAnimationListener() {
@@ -954,7 +943,7 @@
}
});
mCameraGestureHelper = cameraGestureHelper;
- mKeyguardBottomAreaInteractorProvider = keyguardBottomAreaInteractorProvider;
+ mKeyguardBottomAreaInteractor = keyguardBottomAreaInteractor;
}
@VisibleForTesting
@@ -1067,6 +1056,8 @@
mLockscreenNotificationQSPadding = mResources.getDimensionPixelSize(
R.dimen.notification_side_paddings);
mUdfpsMaxYBurnInOffset = mResources.getDimensionPixelSize(R.dimen.udfps_burn_in_offset_y);
+ mSplitShadeScrimTransitionDistance = mResources.getDimensionPixelSize(
+ R.dimen.split_shade_scrim_transition_distance);
}
private void updateViewControllers(KeyguardStatusView keyguardStatusView,
@@ -1279,17 +1270,7 @@
}
private void initBottomArea() {
- if (mFeatureFlags.isEnabled(Flags.MODERN_BOTTOM_AREA)) {
- mKeyguardBottomArea.init(mKeyguardBottomAreaViewModelProvider.get(), mFalsingManager);
- } else {
- // TODO(b/235403546): remove this method call when the new implementation is complete
- // and these are not needed.
- mKeyguardBottomArea.init(
- mFalsingManager,
- mQuickAccessWalletController,
- mControlsComponent,
- mQRCodeScannerController);
- }
+ mKeyguardBottomArea.init(mKeyguardBottomAreaViewModel, mFalsingManager);
}
@VisibleForTesting
@@ -1345,6 +1326,9 @@
mIsFullWidth = isFullWidth;
mScrimController.setClipsQsScrim(isFullWidth);
mNotificationStackScrollLayoutController.setIsFullWidth(isFullWidth);
+ if (mQs != null) {
+ mQs.setIsNotificationPanelFullWidth(isFullWidth);
+ }
}
private void startQsSizeChangeAnimation(int oldHeight, final int newHeight) {
@@ -1357,7 +1341,7 @@
mQsSizeChangeAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
mQsSizeChangeAnimator.addUpdateListener(animation -> {
requestScrollerTopPaddingUpdate(false /* animate */);
- requestPanelHeightUpdate();
+ updateExpandedHeightToMaxHeight();
int height = (int) mQsSizeChangeAnimator.getAnimatedValue();
mQs.setHeightOverride(height);
});
@@ -1406,7 +1390,6 @@
}
mNotificationStackScrollLayoutController.setIntrinsicPadding(stackScrollerPadding);
- mKeyguardBottomArea.setAntiBurnInOffsetX(mClockPositionResult.clockX);
mStackScrollerMeasuringPass++;
requestScrollerTopPaddingUpdate(animate);
@@ -1456,7 +1439,7 @@
mKeyguardStatusViewController.getClockBottom(mStatusBarHeaderHeightKeyguard),
mKeyguardStatusViewController.isClockTopAligned());
mClockPositionAlgorithm.run(mClockPositionResult);
- mKeyguardBottomAreaInteractorProvider.get().setClockPosition(
+ mKeyguardBottomAreaInteractor.setClockPosition(
mClockPositionResult.clockX, mClockPositionResult.clockY);
boolean animate = mNotificationStackScrollLayoutController.isAddOrRemoveAnimationPending();
boolean animateClock = (animate || mAnimateNextPositionUpdate) && shouldAnimateClockChange;
@@ -2137,7 +2120,7 @@
mMetricsLogger.count(COUNTER_PANEL_OPEN_QS, 1);
setQsExpandImmediate(true);
setShowShelfOnly(true);
- requestPanelHeightUpdate();
+ updateExpandedHeightToMaxHeight();
// Normally, we start listening when the panel is expanded, but here we need to start
// earlier so the state is already up to date when dragging down.
@@ -2349,13 +2332,13 @@
// Reset scroll position and apply that position to the expanded height.
float height = mQsExpansionHeight;
setQsExpansion(height);
- requestPanelHeightUpdate();
+ updateExpandedHeightToMaxHeight();
mNotificationStackScrollLayoutController.checkSnoozeLeavebehind();
// When expanding QS, let's authenticate the user if possible,
// this will speed up notification actions.
if (height == 0) {
- mCentralSurfaces.requestFaceAuth(false);
+ mCentralSurfaces.requestFaceAuth(false, FaceAuthApiRequestReason.QS_EXPANDED);
}
}
@@ -2365,7 +2348,7 @@
if (changed) {
mQsExpanded = expanded;
updateQsState();
- requestPanelHeightUpdate();
+ updateExpandedHeightToMaxHeight();
mFalsingCollector.setQsExpanded(expanded);
mCentralSurfaces.setQsExpanded(expanded);
mNotificationsQSContainerController.setQsExpanded(expanded);
@@ -2454,8 +2437,8 @@
final float squishiness;
if ((mQsExpandImmediate || mQsExpanded) && !mSplitShadeEnabled) {
squishiness = 1;
- } else if (mLockscreenShadeTransitionController.getQSDragProgress() > 0) {
- squishiness = mLockscreenShadeTransitionController.getQSDragProgress();
+ } else if (mTransitioningToFullShadeProgress > 0.0f) {
+ squishiness = mLockscreenShadeTransitionController.getQsSquishTransitionFraction();
} else {
squishiness = mNotificationStackScrollLayoutController
.getNotificationSquishinessFraction();
@@ -3089,16 +3072,7 @@
int maxHeight;
if (mQsExpandImmediate || mQsExpanded || mIsExpanding && mQsExpandedWhenExpandingStarted
|| mPulsing || mSplitShadeEnabled) {
- if (mSplitShadeEnabled && mBarState == SHADE) {
- // Max panel height is used to calculate the fraction of the shade expansion.
- // Traditionally the value is based on the number of notifications.
- // On split-shade, we want the required distance to be a specific and constant
- // value, to make sure the expansion motion has the expected speed.
- // We also only want this on non-lockscreen for now.
- maxHeight = mSplitShadeFullTransitionDistance;
- } else {
- maxHeight = calculatePanelHeightQsExpanded();
- }
+ maxHeight = calculatePanelHeightQsExpanded();
} else {
maxHeight = calculatePanelHeightShade();
}
@@ -3299,8 +3273,7 @@
getExpandedFraction());
float alpha = Math.min(expansionAlpha, 1 - computeQsExpansionFraction());
alpha *= mBottomAreaShadeAlpha;
- mKeyguardBottomArea.setComponentAlphas(alpha);
- mKeyguardBottomAreaInteractorProvider.get().setAlpha(alpha);
+ mKeyguardBottomAreaInteractor.setAlpha(alpha);
mLockIconViewController.setAlpha(alpha);
}
@@ -3458,6 +3431,31 @@
}
@Override
+ public int getMaxPanelTransitionDistance() {
+ // Traditionally the value is based on the number of notifications. On split-shade, we want
+ // the required distance to be a specific and constant value, to make sure the expansion
+ // motion has the expected speed. We also only want this on non-lockscreen for now.
+ if (mSplitShadeEnabled && mBarState == SHADE) {
+ boolean transitionFromHeadsUp =
+ mHeadsUpManager.isTrackingHeadsUp() || mExpandingFromHeadsUp;
+ // heads-up starting height is too close to mSplitShadeFullTransitionDistance and
+ // when dragging HUN transition is already 90% complete. It makes shade become
+ // immediately visible when starting to drag. We want to set distance so that
+ // nothing is immediately visible when dragging (important for HUN swipe up motion) -
+ // 0.4 expansion fraction is a good starting point.
+ if (transitionFromHeadsUp) {
+ double maxDistance = Math.max(mSplitShadeFullTransitionDistance,
+ mHeadsUpStartHeight * 2.5);
+ return (int) Math.min(getMaxPanelHeight(), maxDistance);
+ } else {
+ return mSplitShadeFullTransitionDistance;
+ }
+ } else {
+ return getMaxPanelHeight();
+ }
+ }
+
+ @Override
protected boolean isTrackingBlocked() {
return mConflictingQsExpansionGesture && mQsExpanded || mBlockingExpansionForCurrentTouch;
}
@@ -3499,8 +3497,7 @@
}
private void updateDozingVisibilities(boolean animate) {
- mKeyguardBottomArea.setDozing(mDozing, animate);
- mKeyguardBottomAreaInteractorProvider.get().setAnimateDozingTransitions(animate);
+ mKeyguardBottomAreaInteractor.setAnimateDozingTransitions(animate);
if (!mDozing && animate) {
mKeyguardStatusBarViewController.animateKeyguardStatusBarIn();
}
@@ -3532,7 +3529,8 @@
&& !mUpdateMonitor.isFaceDetectionRunning()
&& !mUpdateMonitor.getUserCanSkipBouncer(
KeyguardUpdateMonitor.getCurrentUser())) {
- mUpdateMonitor.requestFaceAuth(true);
+ mUpdateMonitor.requestFaceAuth(true,
+ FaceAuthApiRequestReason.NOTIFICATION_PANEL_CLICKED);
} else {
mLockscreenGestureLogger.write(MetricsEvent.ACTION_LS_HINT,
0 /* lengthDp - N/A */, 0 /* velocityDp - N/A */);
@@ -3656,10 +3654,35 @@
}
/**
+ * Called when heads-up notification is being dragged up or down to indicate what's the starting
+ * height for shade motion
+ */
+ public void setHeadsUpDraggingStartingHeight(int startHeight) {
+ mHeadsUpStartHeight = startHeight;
+ float scrimMinFraction;
+ if (mSplitShadeEnabled) {
+ boolean highHun = mHeadsUpStartHeight * 2.5 > mSplitShadeScrimTransitionDistance;
+ // if HUN height is higher than 40% of predefined transition distance, it means HUN
+ // is too high for regular transition. In that case we need to calculate transition
+ // distance - here we take scrim transition distance as equal to shade transition
+ // distance. It doesn't result in perfect motion - usually scrim transition distance
+ // should be longer - but it's good enough for HUN case.
+ float transitionDistance =
+ highHun ? getMaxPanelTransitionDistance() : mSplitShadeFullTransitionDistance;
+ scrimMinFraction = mHeadsUpStartHeight / transitionDistance;
+ } else {
+ int transitionDistance = getMaxPanelHeight();
+ scrimMinFraction = transitionDistance > 0f
+ ? (float) mHeadsUpStartHeight / transitionDistance : 0f;
+ }
+ setPanelScrimMinFraction(scrimMinFraction);
+ }
+
+ /**
* Sets the minimum fraction for the panel expansion offset. This may be non-zero in certain
* cases, such as if there's a heads-up notification.
*/
- public void setPanelScrimMinFraction(float minFraction) {
+ private void setPanelScrimMinFraction(float minFraction) {
mMinFraction = minFraction;
mDepthController.setPanelPullDownMinFraction(mMinFraction);
mScrimController.setPanelScrimMinFraction(mMinFraction);
@@ -3743,6 +3766,7 @@
mQs.setHeaderClickable(isQsExpansionEnabled());
mQs.setOverscrolling(mStackScrollerOverscrolling);
mQs.setInSplitShade(mSplitShadeEnabled);
+ mQs.setIsNotificationPanelFullWidth(mIsFullWidth);
// recompute internal state when qspanel height changes
mQs.getView().addOnLayoutChangeListener(
@@ -3801,8 +3825,7 @@
mView.setDozing(dozing);
mDozing = dozing;
mNotificationStackScrollLayoutController.setDozing(mDozing, animate);
- mKeyguardBottomArea.setDozing(mDozing, animate);
- mKeyguardBottomAreaInteractorProvider.get().setAnimateDozingTransitions(animate);
+ mKeyguardBottomAreaInteractor.setAnimateDozingTransitions(animate);
mKeyguardStatusBarViewController.setDozing(mDozing);
if (dozing) {
@@ -3851,7 +3874,6 @@
public void dozeTimeTick() {
mLockIconViewController.dozeTimeTick();
- mKeyguardBottomArea.dozeTimeTick();
mKeyguardStatusViewController.dozeTimeTick();
if (mInterpolatedDarkAmount > 0) {
positionClockAndNotifications();
@@ -4393,7 +4415,7 @@
if (mKeyguardShowing) {
updateMaxDisplayedNotifications(true);
}
- requestPanelHeightUpdate();
+ updateExpandedHeightToMaxHeight();
}
@Override
@@ -4526,7 +4548,7 @@
if (mQsExpanded && mQsFullyExpanded) {
mQsExpansionHeight = mQsMaxExpansionHeight;
requestScrollerTopPaddingUpdate(false /* animate */);
- requestPanelHeightUpdate();
+ updateExpandedHeightToMaxHeight();
}
if (mAccessibilityManager.isEnabled()) {
mView.setAccessibilityPaneTitle(determineAccessibilityPaneTitle());
@@ -4674,7 +4696,6 @@
public void onDozeAmountChanged(float linearAmount, float amount) {
mInterpolatedDarkAmount = amount;
mLinearDarkAmount = linearAmount;
- mKeyguardBottomArea.setDarkAmount(mInterpolatedDarkAmount);
positionClockAndNotifications();
}
}
@@ -4729,7 +4750,6 @@
public void showAodUi() {
setDozing(true /* dozing */, false /* animate */);
mStatusBarStateController.setUpcomingState(KEYGUARD);
- mEntryManager.updateNotifications("showAodUi");
mStatusBarStateListener.onStateChanged(KEYGUARD);
mStatusBarStateListener.onDozeAmountChanged(1f, 1f);
setExpandedFraction(1f);
@@ -4797,7 +4817,7 @@
if (mQsExpanded && mQsFullyExpanded) {
mQsExpansionHeight = mQsMaxExpansionHeight;
requestScrollerTopPaddingUpdate(false /* animate */);
- requestPanelHeightUpdate();
+ updateExpandedHeightToMaxHeight();
// Size has changed, start an animation.
if (mQsMaxExpansionHeight != oldMaxHeight) {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
index fec76b6..abafecc 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
@@ -29,12 +29,12 @@
import android.view.ViewGroup;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.keyguard.AuthKeyguardMessageArea;
import com.android.keyguard.LockIconViewController;
import com.android.systemui.R;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.dock.DockManager;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
-import com.android.systemui.lowlightclock.LowLightClockController;
import com.android.systemui.statusbar.DragDownHelper;
import com.android.systemui.statusbar.LockscreenShadeTransitionController;
import com.android.systemui.statusbar.NotificationShadeDepthController;
@@ -51,7 +51,6 @@
import com.android.systemui.statusbar.window.StatusBarWindowStateController;
import java.io.PrintWriter;
-import java.util.Optional;
import javax.inject.Inject;
@@ -88,7 +87,6 @@
private final DockManager mDockManager;
private final NotificationPanelViewController mNotificationPanelViewController;
private final PanelExpansionStateManager mPanelExpansionStateManager;
- private final Optional<LowLightClockController> mLowLightClockController;
private boolean mIsTrackingBarGesture = false;
@@ -106,7 +104,6 @@
StatusBarKeyguardViewManager statusBarKeyguardViewManager,
StatusBarWindowStateController statusBarWindowStateController,
LockIconViewController lockIconViewController,
- Optional<LowLightClockController> lowLightClockController,
CentralSurfaces centralSurfaces,
NotificationShadeWindowController controller,
KeyguardUnlockAnimationController keyguardUnlockAnimationController,
@@ -125,7 +122,6 @@
mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
mStatusBarWindowStateController = statusBarWindowStateController;
mLockIconViewController = lockIconViewController;
- mLowLightClockController = lowLightClockController;
mService = centralSurfaces;
mNotificationShadeWindowController = controller;
mKeyguardUnlockAnimationController = keyguardUnlockAnimationController;
@@ -143,13 +139,18 @@
return mView.findViewById(R.id.keyguard_bouncer_container);
}
+ /**
+ * @return Location where to place the KeyguardMessageArea
+ */
+ public AuthKeyguardMessageArea getKeyguardMessageArea() {
+ return mView.findViewById(R.id.keyguard_message_area);
+ }
+
/** Inflates the {@link R.layout#status_bar_expanded} layout and sets it up. */
public void setupExpandedStatusBar() {
mStackScrollLayout = mView.findViewById(R.id.notification_stack_scroller);
mGestureDetector = new GestureDetector(mView.getContext(), mPulsingGestureListener);
- mLowLightClockController.ifPresent(controller -> controller.attachLowLightClockView(mView));
-
mView.setInteractionEventHandler(new NotificationShadeWindowView.InteractionEventHandler() {
@Override
public Boolean handleDispatchTouchEvent(MotionEvent ev) {
@@ -434,21 +435,6 @@
mStatusBarViewController = statusBarViewController;
}
- /**
- * Tell the controller that dozing has begun or ended.
- * @param dozing True if dozing has begun.
- */
- public void setDozing(boolean dozing) {
- mLowLightClockController.ifPresent(controller -> controller.showLowLightClock(dozing));
- }
-
- /**
- * Tell the controller to perform burn-in prevention.
- */
- public void dozeTimeTick() {
- mLowLightClockController.ifPresent(LowLightClockController::dozeTimeTick);
- }
-
@VisibleForTesting
void setDragDownHelper(DragDownHelper dragDownHelper) {
mDragDownHelper = dragDownHelper;
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt b/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt
index 2a46776..d6f0de8 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt
@@ -35,6 +35,7 @@
view: NotificationsQuickSettingsContainer,
private val navigationModeController: NavigationModeController,
private val overviewProxyService: OverviewProxyService,
+ private val largeScreenShadeHeaderController: LargeScreenShadeHeaderController,
private val featureFlags: FeatureFlags,
@Main private val delayableExecutor: DelayableExecutor
) : ViewController<NotificationsQuickSettingsContainer>(view), QSContainerController {
@@ -156,9 +157,12 @@
}
}
- override fun setCustomizerShowing(showing: Boolean) {
- isQSCustomizing = showing
- updateBottomSpacing()
+ override fun setCustomizerShowing(showing: Boolean, animationDuration: Long) {
+ if (showing != isQSCustomizing) {
+ isQSCustomizing = showing
+ largeScreenShadeHeaderController.startCustomizingAnimation(showing, animationDuration)
+ updateBottomSpacing()
+ }
}
override fun setDetailShowing(showing: Boolean) {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/PanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/PanelViewController.java
index 876a1ff..c3f1e57 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/PanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/PanelViewController.java
@@ -248,7 +248,7 @@
keyguardStateController.addCallback(new KeyguardStateController.Callback() {
@Override
public void onKeyguardFadingAwayChanged() {
- requestPanelHeightUpdate();
+ updateExpandedHeightToMaxHeight();
}
});
mAmbientState = ambientState;
@@ -397,7 +397,7 @@
mInitialOffsetOnTouch = expandedHeight;
mInitialExpandY = newY;
mInitialExpandX = newX;
- mInitialTouchFromKeyguard = mStatusBarStateController.getState() == StatusBarState.KEYGUARD;
+ mInitialTouchFromKeyguard = mKeyguardStateController.isShowing();
if (startTracking) {
mTouchSlopExceeded = true;
setExpandedHeight(mInitialOffsetOnTouch);
@@ -416,9 +416,7 @@
float vectorVel = (float) Math.hypot(
mVelocityTracker.getXVelocity(), mVelocityTracker.getYVelocity());
- final boolean onKeyguard =
- mStatusBarStateController.getState() == StatusBarState.KEYGUARD;
-
+ final boolean onKeyguard = mKeyguardStateController.isShowing();
final boolean expand;
if (mKeyguardStateController.isKeyguardFadingAway()
|| (mInitialTouchFromKeyguard && !onKeyguard)) {
@@ -732,7 +730,7 @@
setExpandedHeightInternal(height);
}
- protected void requestPanelHeightUpdate() {
+ void updateExpandedHeightToMaxHeight() {
float currentMaxPanelHeight = getMaxPanelHeight();
if (isFullyCollapsed()) {
@@ -755,6 +753,13 @@
setExpandedHeight(currentMaxPanelHeight);
}
+ /**
+ * Returns drag down distance after which panel should be fully expanded. Usually it's the
+ * same as max panel height but for large screen devices (especially split shade) we might
+ * want to return different value to shorten drag distance
+ */
+ public abstract int getMaxPanelTransitionDistance();
+
public void setExpandedHeightInternal(float h) {
if (isNaN(h)) {
Log.wtf(TAG, "ExpandedHeight set to NaN");
@@ -765,18 +770,15 @@
() -> mLatencyTracker.onActionEnd(LatencyTracker.ACTION_EXPAND_PANEL));
mExpandLatencyTracking = false;
}
- float maxPanelHeight = getMaxPanelHeight();
+ float maxPanelHeight = getMaxPanelTransitionDistance();
if (mHeightAnimator == null) {
// Split shade has its own overscroll logic
if (mTracking && !mInSplitShade) {
float overExpansionPixels = Math.max(0, h - maxPanelHeight);
setOverExpansionInternal(overExpansionPixels, true /* isFromGesture */);
}
- mExpandedHeight = Math.min(h, maxPanelHeight);
- } else {
- mExpandedHeight = h;
}
-
+ mExpandedHeight = Math.min(h, maxPanelHeight);
// If we are closing the panel and we are almost there due to a slow decelerating
// interpolator, abort the animation.
if (mExpandedHeight < 1f && mExpandedHeight != 0f && mClosing) {
@@ -834,7 +836,7 @@
protected abstract int getMaxPanelHeight();
public void setExpandedFraction(float frac) {
- setExpandedHeight(getMaxPanelHeight() * frac);
+ setExpandedHeight(getMaxPanelTransitionDistance() * frac);
}
public float getExpandedHeight() {
@@ -1031,7 +1033,7 @@
mHeightAnimator = animator;
if (animator == null && mPanelUpdateWhenAnimatorEnds) {
mPanelUpdateWhenAnimatorEnds = false;
- requestPanelHeightUpdate();
+ updateExpandedHeightToMaxHeight();
}
}
@@ -1423,7 +1425,7 @@
@Override
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,
int oldTop, int oldRight, int oldBottom) {
- requestPanelHeightUpdate();
+ updateExpandedHeightToMaxHeight();
mHasLayoutedSinceDown = true;
if (mUpdateFlingOnLayout) {
abortAnimations();
diff --git a/packages/SystemUI/src/com/android/systemui/shade/PulsingGestureListener.kt b/packages/SystemUI/src/com/android/systemui/shade/PulsingGestureListener.kt
index 621a609..9b3fe92 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/PulsingGestureListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/PulsingGestureListener.kt
@@ -26,6 +26,7 @@
import com.android.systemui.dock.DockManager
import com.android.systemui.dump.DumpManager
import com.android.systemui.plugins.FalsingManager
+import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.phone.CentralSurfaces
import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent
import com.android.systemui.tuner.TunerService
@@ -49,6 +50,7 @@
private val dockManager: DockManager,
private val centralSurfaces: CentralSurfaces,
private val ambientDisplayConfiguration: AmbientDisplayConfiguration,
+ private val statusBarStateController: StatusBarStateController,
tunerService: TunerService,
dumpManager: DumpManager
) : GestureDetector.SimpleOnGestureListener(), Dumpable {
@@ -74,7 +76,8 @@
}
override fun onSingleTapConfirmed(e: MotionEvent): Boolean {
- if (singleTapEnabled &&
+ if (statusBarStateController.isPulsing &&
+ singleTapEnabled &&
!dockManager.isDocked &&
!falsingManager.isProximityNear &&
!falsingManager.isFalseTap(FalsingManager.MODERATE_PENALTY)
@@ -89,7 +92,8 @@
}
override fun onDoubleTap(e: MotionEvent): Boolean {
- if ((doubleTapEnabled || singleTapEnabled) &&
+ if (statusBarStateController.isPulsing &&
+ (doubleTapEnabled || singleTapEnabled) &&
!falsingManager.isProximityNear &&
!falsingManager.isFalseDoubleTap
) {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/transition/ScrimShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/shade/transition/ScrimShadeTransitionController.kt
index afd57da..618c892 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/transition/ScrimShadeTransitionController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/transition/ScrimShadeTransitionController.kt
@@ -14,6 +14,7 @@
import com.android.systemui.statusbar.phone.panelstate.PanelState
import com.android.systemui.statusbar.phone.panelstate.STATE_OPENING
import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.statusbar.policy.HeadsUpManager
import com.android.systemui.util.LargeScreenUtils
import java.io.PrintWriter
import javax.inject.Inject
@@ -28,6 +29,7 @@
private val scrimController: ScrimController,
@Main private val resources: Resources,
private val statusBarStateController: SysuiStatusBarStateController,
+ private val headsUpManager: HeadsUpManager
) {
private var inSplitShade = false
@@ -84,7 +86,11 @@
}
private fun canUseCustomFraction(panelState: Int?) =
- inSplitShade && isScreenUnlocked() && panelState == STATE_OPENING
+ inSplitShade && isScreenUnlocked() && panelState == STATE_OPENING &&
+ // in case of HUN we can't always use predefined distances to manage scrim
+ // transition because dragDownPxAmount can start from value bigger than
+ // splitShadeScrimTransitionDistance
+ !headsUpManager.isTrackingHeadsUp
private fun isScreenUnlocked() =
statusBarStateController.currentOrUpcomingState == StatusBarState.SHADE
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index e992440..04621168 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -52,7 +52,6 @@
import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
-import android.util.Log;
import android.util.Pair;
import android.util.SparseArray;
import android.view.InsetsState.InternalInsetsType;
@@ -76,7 +75,6 @@
import com.android.systemui.tracing.ProtoTracer;
import java.io.FileOutputStream;
-import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -152,7 +150,6 @@
private static final int MSG_TRACING_STATE_CHANGED = 54 << MSG_SHIFT;
private static final int MSG_SUPPRESS_AMBIENT_DISPLAY = 55 << MSG_SHIFT;
private static final int MSG_REQUEST_WINDOW_MAGNIFICATION_CONNECTION = 56 << MSG_SHIFT;
- private static final int MSG_HANDLE_WINDOW_MANAGER_LOGGING_COMMAND = 57 << MSG_SHIFT;
//TODO(b/169175022) Update name and when feature name is locked.
private static final int MSG_EMERGENCY_ACTION_LAUNCH_GESTURE = 58 << MSG_SHIFT;
private static final int MSG_SET_NAVIGATION_BAR_LUMA_SAMPLING_ENABLED = 59 << MSG_SHIFT;
@@ -425,11 +422,6 @@
default void requestWindowMagnificationConnection(boolean connect) { }
/**
- * Handles a window manager shell logging command.
- */
- default void handleWindowManagerLoggingCommand(String[] args, ParcelFileDescriptor outFd) {}
-
- /**
* @see IStatusBar#setNavigationBarLumaSamplingEnabled(int, boolean)
*/
default void setNavigationBarLumaSamplingEnabled(int displayId, boolean enable) {}
@@ -1143,17 +1135,6 @@
}
@Override
- public void handleWindowManagerLoggingCommand(String[] args, ParcelFileDescriptor outFd) {
- synchronized (mLock) {
- SomeArgs internalArgs = SomeArgs.obtain();
- internalArgs.arg1 = args;
- internalArgs.arg2 = outFd;
- mHandler.obtainMessage(MSG_HANDLE_WINDOW_MANAGER_LOGGING_COMMAND, internalArgs)
- .sendToTarget();
- }
- }
-
- @Override
public void suppressAmbientDisplay(boolean suppress) {
synchronized (mLock) {
mHandler.obtainMessage(MSG_SUPPRESS_AMBIENT_DISPLAY, suppress).sendToTarget();
@@ -1637,18 +1618,6 @@
mCallbacks.get(i).requestWindowMagnificationConnection((Boolean) msg.obj);
}
break;
- case MSG_HANDLE_WINDOW_MANAGER_LOGGING_COMMAND:
- args = (SomeArgs) msg.obj;
- try (ParcelFileDescriptor pfd = (ParcelFileDescriptor) args.arg2) {
- for (int i = 0; i < mCallbacks.size(); i++) {
- mCallbacks.get(i).handleWindowManagerLoggingCommand(
- (String[]) args.arg1, pfd);
- }
- } catch (IOException e) {
- Log.e(TAG, "Failed to handle logging command", e);
- }
- args.recycle();
- break;
case MSG_SET_NAVIGATION_BAR_LUMA_SAMPLING_ENABLED:
for (int i = 0; i < mCallbacks.size(); i++) {
mCallbacks.get(i).setNavigationBarLumaSamplingEnabled(msg.arg1,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 47dc5c2..408c61f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -19,6 +19,10 @@
import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_FINANCED;
import static android.app.admin.DevicePolicyResources.Strings.SystemUi.KEYGUARD_MANAGEMENT_DISCLOSURE;
import static android.app.admin.DevicePolicyResources.Strings.SystemUi.KEYGUARD_NAMED_MANAGEMENT_DISCLOSURE;
+import static android.hardware.biometrics.BiometricFaceConstants.FACE_ACQUIRED_FIRST_FRAME_RECEIVED;
+import static android.hardware.biometrics.BiometricFaceConstants.FACE_ACQUIRED_GOOD;
+import static android.hardware.biometrics.BiometricFaceConstants.FACE_ACQUIRED_START;
+import static android.hardware.biometrics.BiometricFaceConstants.FACE_ACQUIRED_TOO_DARK;
import static android.hardware.biometrics.BiometricSourceType.FACE;
import static android.view.View.GONE;
import static android.view.View.VISIBLE;
@@ -78,6 +82,7 @@
import com.android.settingslib.Utils;
import com.android.settingslib.fuelgauge.BatteryStatus;
import com.android.systemui.R;
+import com.android.systemui.biometrics.BiometricMessageDeferral;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Background;
@@ -178,7 +183,7 @@
private boolean mBatteryPresent = true;
private long mChargingTimeRemaining;
private String mBiometricErrorMessageToShowOnScreenOn;
- private final Set<Integer> mCoExFaceHelpMsgIdsToShow;
+ private final Set<Integer> mCoExFaceAcquisitionMsgIdsToShow;
private boolean mInited;
private KeyguardUpdateMonitorCallback mUpdateMonitorCallback;
@@ -249,11 +254,11 @@
mScreenLifecycle = screenLifecycle;
mScreenLifecycle.addObserver(mScreenObserver);
- mCoExFaceHelpMsgIdsToShow = new HashSet<>();
+ mCoExFaceAcquisitionMsgIdsToShow = new HashSet<>();
int[] msgIds = context.getResources().getIntArray(
com.android.systemui.R.array.config_face_help_msgs_when_fingerprint_enrolled);
for (int msgId : msgIds) {
- mCoExFaceHelpMsgIdsToShow.add(msgId);
+ mCoExFaceAcquisitionMsgIdsToShow.add(msgId);
}
mHandler = new Handler(mainLooper) {
@@ -687,11 +692,11 @@
/**
* Returns the indication text indicating that trust has been granted.
*
- * @return {@code null} or an empty string if a trust indication text should not be shown.
+ * @return an empty string if a trust indication text should not be shown.
*/
@VisibleForTesting
String getTrustGrantedIndication() {
- return TextUtils.isEmpty(mTrustGrantedIndication)
+ return mTrustGrantedIndication == null
? mContext.getString(R.string.keyguard_indication_trust_unlocked)
: mTrustGrantedIndication.toString();
}
@@ -927,7 +932,7 @@
return; // udfps affordance is highlighted, no need to show action to unlock
} else if (mKeyguardUpdateMonitor.isFaceEnrolled()) {
String message = mContext.getString(R.string.keyguard_retry);
- mStatusBarKeyguardViewManager.showBouncerMessage(message, mInitialTextColorState);
+ mStatusBarKeyguardViewManager.setKeyguardMessage(message, mInitialTextColorState);
}
} else {
final boolean canSkipBouncer = mKeyguardUpdateMonitor.getUserCanSkipBouncer(
@@ -990,7 +995,7 @@
mTopIndicationView == null ? null : mTopIndicationView.getText()));
pw.println(" computePowerIndication(): " + computePowerIndication());
pw.println(" trustGrantedIndication: " + getTrustGrantedIndication());
- pw.println(" mCoExFaceHelpMsgIdsToShow=" + mCoExFaceHelpMsgIdsToShow);
+ pw.println(" mCoExFaceHelpMsgIdsToShow=" + mCoExFaceAcquisitionMsgIdsToShow);
mRotateTextViewController.dump(pw, args);
}
@@ -1048,6 +1053,17 @@
return;
}
+ if (biometricSourceType == FACE) {
+ if (msgId == KeyguardUpdateMonitor.BIOMETRIC_HELP_FACE_NOT_RECOGNIZED) {
+ mFaceAcquiredMessageDeferral.reset();
+ } else {
+ mFaceAcquiredMessageDeferral.processMessage(msgId, helpString);
+ if (mFaceAcquiredMessageDeferral.shouldDefer(msgId)) {
+ return;
+ }
+ }
+ }
+
final boolean faceAuthSoftError = biometricSourceType == FACE
&& msgId != BIOMETRIC_HELP_FACE_NOT_RECOGNIZED;
final boolean faceAuthFailed = biometricSourceType == FACE
@@ -1055,19 +1071,24 @@
final boolean isUnlockWithFingerprintPossible =
mKeyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible(
getCurrentUser());
- if (faceAuthSoftError
- && isUnlockWithFingerprintPossible
- && !mCoExFaceHelpMsgIdsToShow.contains(msgId)) {
+ final boolean isCoExFaceAcquisitionMessage =
+ faceAuthSoftError && isUnlockWithFingerprintPossible;
+ if (isCoExFaceAcquisitionMessage && !mCoExFaceAcquisitionMsgIdsToShow.contains(msgId)) {
if (DEBUG) {
Log.d(TAG, "skip showing msgId=" + msgId + " helpString=" + helpString
+ ", due to co-ex logic");
}
return;
} else if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
- mStatusBarKeyguardViewManager.showBouncerMessage(helpString,
+ mStatusBarKeyguardViewManager.setKeyguardMessage(helpString,
mInitialTextColorState);
} else if (mScreenLifecycle.getScreenState() == SCREEN_ON) {
- if (faceAuthFailed && isUnlockWithFingerprintPossible) {
+ if (isCoExFaceAcquisitionMessage && msgId == FACE_ACQUIRED_TOO_DARK) {
+ showBiometricMessage(
+ helpString,
+ mContext.getString(R.string.keyguard_suggest_fingerprint)
+ );
+ } else if (faceAuthFailed && isUnlockWithFingerprintPossible) {
showBiometricMessage(
mContext.getString(R.string.keyguard_face_failed),
mContext.getString(R.string.keyguard_suggest_fingerprint)
@@ -1090,41 +1111,51 @@
@Override
public void onBiometricError(int msgId, String errString,
BiometricSourceType biometricSourceType) {
- if (shouldSuppressBiometricError(msgId, biometricSourceType, mKeyguardUpdateMonitor)) {
- return;
+ CharSequence deferredFaceMessage = null;
+ if (biometricSourceType == FACE) {
+ deferredFaceMessage = mFaceAcquiredMessageDeferral.getDeferredMessage();
+ mFaceAcquiredMessageDeferral.reset();
}
- if (biometricSourceType == FACE
- && msgId == FaceManager.FACE_ERROR_UNABLE_TO_PROCESS) {
- // suppress all face UNABLE_TO_PROCESS errors
+ if (shouldSuppressBiometricError(msgId, biometricSourceType, mKeyguardUpdateMonitor)) {
if (DEBUG) {
- Log.d(TAG, "skip showing FACE_ERROR_UNABLE_TO_PROCESS errString="
- + errString);
+ Log.d(TAG, "suppressingBiometricError msgId=" + msgId
+ + " source=" + biometricSourceType);
}
- } else if (biometricSourceType == FACE
- && msgId == FaceManager.FACE_ERROR_TIMEOUT) {
+ } else if (biometricSourceType == FACE && msgId == FaceManager.FACE_ERROR_TIMEOUT) {
+ // Co-ex: show deferred message OR nothing
if (mKeyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible(
- getCurrentUser())) {
- // no message if fingerprint is also enrolled
+ KeyguardUpdateMonitor.getCurrentUser())) {
+ // if we're on the lock screen (bouncer isn't showing), show the deferred msg
+ if (deferredFaceMessage != null
+ && !mStatusBarKeyguardViewManager.isBouncerShowing()) {
+ showBiometricMessage(
+ deferredFaceMessage,
+ mContext.getString(R.string.keyguard_suggest_fingerprint)
+ );
+ return;
+ }
+
+ // otherwise, don't show any message
if (DEBUG) {
Log.d(TAG, "skip showing FACE_ERROR_TIMEOUT due to co-ex logic");
}
return;
}
- // The face timeout message is not very actionable, let's ask the user to
+ // Face-only: The face timeout message is not very actionable, let's ask the user to
// manually retry.
- if (mStatusBarKeyguardViewManager.isShowingAlternateAuth()) {
- mStatusBarKeyguardViewManager.showBouncerMessage(
- mContext.getResources().getString(R.string.keyguard_try_fingerprint),
- mInitialTextColorState
+ if (deferredFaceMessage != null) {
+ showBiometricMessage(
+ deferredFaceMessage,
+ mContext.getString(R.string.keyguard_unlock)
);
} else {
// suggest swiping up to unlock (try face auth again or swipe up to bouncer)
showActionToUnlock();
}
} else if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
- mStatusBarKeyguardViewManager.showBouncerMessage(errString, mInitialTextColorState);
+ mStatusBarKeyguardViewManager.setKeyguardMessage(errString, mInitialTextColorState);
} else if (mScreenLifecycle.getScreenState() == SCREEN_ON) {
showBiometricMessage(errString);
} else {
@@ -1134,8 +1165,9 @@
private boolean shouldSuppressBiometricError(int msgId,
BiometricSourceType biometricSourceType, KeyguardUpdateMonitor updateMonitor) {
- if (biometricSourceType == BiometricSourceType.FINGERPRINT)
+ if (biometricSourceType == BiometricSourceType.FINGERPRINT) {
return shouldSuppressFingerprintError(msgId, updateMonitor);
+ }
if (biometricSourceType == FACE) {
return shouldSuppressFaceError(msgId, updateMonitor);
}
@@ -1161,7 +1193,8 @@
// check of whether non-strong biometric is allowed
return ((!updateMonitor.isUnlockingWithBiometricAllowed(true /* isStrongBiometric */)
&& msgId != FaceManager.FACE_ERROR_LOCKOUT_PERMANENT)
- || msgId == FaceManager.FACE_ERROR_CANCELED);
+ || msgId == FaceManager.FACE_ERROR_CANCELED
+ || msgId == FaceManager.FACE_ERROR_UNABLE_TO_PROCESS);
}
@@ -1200,10 +1233,11 @@
boolean isStrongBiometric) {
super.onBiometricAuthenticated(userId, biometricSourceType, isStrongBiometric);
hideBiometricMessage();
-
- if (biometricSourceType == FACE
- && !mKeyguardBypassController.canBypass()) {
- showActionToUnlock();
+ if (biometricSourceType == FACE) {
+ mFaceAcquiredMessageDeferral.reset();
+ if (!mKeyguardBypassController.canBypass()) {
+ showActionToUnlock();
+ }
}
}
@@ -1274,4 +1308,14 @@
}
}
};
+
+ private final BiometricMessageDeferral mFaceAcquiredMessageDeferral =
+ new BiometricMessageDeferral(
+ Set.of(
+ FACE_ACQUIRED_GOOD,
+ FACE_ACQUIRED_START,
+ FACE_ACQUIRED_FIRST_FRAME_RECEIVED
+ ),
+ Set.of(FACE_ACQUIRED_TOO_DARK)
+ );
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeQsTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeQsTransitionController.kt
new file mode 100644
index 0000000..62c225b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeQsTransitionController.kt
@@ -0,0 +1,159 @@
+/*
+ * 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
+
+import android.content.Context
+import android.util.IndentingPrintWriter
+import android.util.MathUtils
+import androidx.annotation.FloatRange
+import androidx.annotation.Px
+import com.android.systemui.R
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.plugins.qs.QS
+import com.android.systemui.statusbar.policy.ConfigurationController
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+import kotlin.math.max
+
+/** Responsible for the QS components during the lockscreen shade transition. */
+class LockscreenShadeQsTransitionController
+@AssistedInject
+constructor(
+ context: Context,
+ configurationController: ConfigurationController,
+ dumpManager: DumpManager,
+ @Assisted private val qsProvider: () -> QS,
+) : AbstractLockscreenShadeTransitionController(context, configurationController, dumpManager) {
+
+ private val qs: QS
+ get() = qsProvider()
+
+ /**
+ * The progress fraction of the QS transition during lockscreen shade expansion.
+ *
+ * Note that this value might be 0 for some time when the expansion is already in progress,
+ * since there is a transition start delay for QS on some device configurations. For this
+ * reason, don't use this value to check whether the shade expansion is in progress.
+ */
+ @FloatRange(from = 0.0, to = 1.0)
+ var qsTransitionFraction = 0f
+ private set
+
+ /**
+ * The fraction of the QS "squish" transition progress during lockscreen shade expansion.
+ *
+ * Note that in some device configurations (large screens) this value can start at a value
+ * greater than 0. For this reason don't use this value to check whether the QS transition has
+ * started or not.
+ */
+ @FloatRange(from = 0.0, to = 1.0)
+ var qsSquishTransitionFraction = 0f
+ private set
+
+ /**
+ * The drag down amount, in pixels __for the QS transition__, also taking into account the
+ * [qsTransitionStartDelay].
+ *
+ * Since it takes into account the start delay, it is __not__ the same as the raw drag down
+ * amount from the shade expansion.
+ */
+ @Px private var qsDragDownAmount = 0f
+
+ /**
+ * Distance it takes for the QS transition to complete during the lockscreen shade expansion.
+ */
+ @Px private var qsTransitionDistance = 0
+
+ /** Distance delay for the QS transition to start during the lockscreen shade expansion. */
+ @Px private var qsTransitionStartDelay = 0
+
+ /**
+ * Distance that it takes to complete the QS "squish" transition during the lockscreen shade
+ * expansion.
+ */
+ @Px private var qsSquishTransitionDistance = 0
+
+ /**
+ * Whether the transition to full shade is in progress. Might be `true` even though
+ * [qsTransitionFraction] is still 0, due to [qsTransitionStartDelay].
+ */
+ private var isTransitioningToFullShade = false
+
+ /**
+ * The fraction at which the QS "squish" transition should start during the lockscreen shade
+ * expansion.
+ *
+ * 0 is fully collapsed, 1 is fully expanded.
+ */
+ @FloatRange(from = 0.0, to = 1.0) private var qsSquishStartFraction = 0f
+
+ override fun updateResources() {
+ qsTransitionDistance =
+ context.resources.getDimensionPixelSize(R.dimen.lockscreen_shade_qs_transition_distance)
+ qsTransitionStartDelay =
+ context.resources.getDimensionPixelSize(R.dimen.lockscreen_shade_qs_transition_delay)
+ qsSquishTransitionDistance =
+ context.resources.getDimensionPixelSize(
+ R.dimen.lockscreen_shade_qs_squish_transition_distance
+ )
+ qsSquishStartFraction =
+ context.resources.getFloat(R.dimen.lockscreen_shade_qs_squish_start_fraction)
+
+ qsSquishTransitionFraction = max(qsSquishTransitionFraction, qsSquishStartFraction)
+ }
+
+ override fun onDragDownAmountChanged(dragDownAmount: Float) {
+ qsDragDownAmount = dragDownAmount - qsTransitionStartDelay
+ qsTransitionFraction = MathUtils.saturate(qsDragDownAmount / qsTransitionDistance)
+ qsSquishTransitionFraction =
+ MathUtils.lerp(
+ /* start= */ qsSquishStartFraction,
+ /* stop= */ 1f,
+ /* amount= */ MathUtils.saturate(qsDragDownAmount / qsSquishTransitionDistance)
+ )
+ isTransitioningToFullShade = dragDownAmount > 0.0f
+ qs.setTransitionToFullShadeProgress(
+ isTransitioningToFullShade,
+ qsTransitionFraction,
+ qsSquishTransitionFraction
+ )
+ }
+
+ override fun dump(pw: IndentingPrintWriter) {
+ pw.println(
+ """
+ Resources:
+ qsTransitionDistance: $qsTransitionDistance
+ qsTransitionStartDelay: $qsTransitionStartDelay
+ qsSquishTransitionDistance: $qsSquishTransitionDistance
+ qsSquishStartFraction: $qsSquishStartFraction
+ State:
+ dragDownAmount: $dragDownAmount
+ qsDragDownAmount: $qsDragDownAmount
+ qsDragFraction: $qsTransitionFraction
+ qsSquishFraction: $qsSquishTransitionFraction
+ isTransitioningToFullShade: $isTransitioningToFullShade
+ """.trimIndent()
+ )
+ }
+
+ @AssistedFactory
+ fun interface Factory {
+ fun create(qsProvider: () -> QS): LockscreenShadeQsTransitionController
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
index 74d8f1b..8006931 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
@@ -2,7 +2,6 @@
import android.animation.Animator
import android.animation.AnimatorListenerAdapter
-import android.animation.ObjectAnimator
import android.animation.ValueAnimator
import android.content.Context
import android.content.res.Configuration
@@ -12,6 +11,7 @@
import android.view.MotionEvent
import android.view.View
import android.view.ViewConfiguration
+import androidx.annotation.FloatRange
import androidx.annotation.VisibleForTesting
import com.android.systemui.Dumpable
import com.android.systemui.ExpandHelper
@@ -69,7 +69,8 @@
wakefulnessLifecycle: WakefulnessLifecycle,
configurationController: ConfigurationController,
falsingManager: FalsingManager,
- dumpManager: DumpManager
+ dumpManager: DumpManager,
+ qsTransitionControllerFactory: LockscreenShadeQsTransitionController.Factory,
) : Dumpable {
private var pulseHeight: Float = 0f
@get:VisibleForTesting
@@ -121,12 +122,6 @@
private var notificationShelfTransitionDistance = 0
/**
- * Distance that the full shade transition takes in order for the Quick Settings to fully fade
- * and expand.
- */
- private var qsTransitionDistance = 0
-
- /**
* Distance that the full shade transition takes in order for depth of the wallpaper to fully
* change.
*/
@@ -189,6 +184,18 @@
keyguardTransitionControllerFactory.create(notificationPanelController)
}
+ private val qsTransitionController = qsTransitionControllerFactory.create { qS }
+
+ /** See [LockscreenShadeQsTransitionController.qsTransitionFraction].*/
+ @get:FloatRange(from = 0.0, to = 1.0)
+ val qSDragProgress: Float
+ get() = qsTransitionController.qsTransitionFraction
+
+ /** See [LockscreenShadeQsTransitionController.qsSquishTransitionFraction].*/
+ @get:FloatRange(from = 0.0, to = 1.0)
+ val qsSquishTransitionFraction: Float
+ get() = qsTransitionController.qsSquishTransitionFraction
+
/**
* [LockScreenShadeOverScroller] property that delegates to either
* [SingleShadeLockScreenOverScroller] or [SplitShadeLockScreenOverScroller].
@@ -243,8 +250,6 @@
R.dimen.lockscreen_shade_transition_by_tap_distance)
notificationShelfTransitionDistance = context.resources.getDimensionPixelSize(
R.dimen.lockscreen_shade_notif_shelf_transition_distance)
- qsTransitionDistance = context.resources.getDimensionPixelSize(
- R.dimen.lockscreen_shade_qs_transition_distance)
depthControllerTransitionDistance = context.resources.getDimensionPixelSize(
R.dimen.lockscreen_shade_depth_controller_transition_distance)
udfpsTransitionDistance = context.resources.getDimensionPixelSize(
@@ -412,8 +417,7 @@
MathUtils.saturate(dragDownAmount / notificationShelfTransitionDistance)
nsslController.setTransitionToFullShadeAmount(fractionToShade)
- qSDragProgress = MathUtils.saturate(dragDownAmount / qsTransitionDistance)
- qS.setTransitionToFullShadeAmount(field, qSDragProgress)
+ qsTransitionController.dragDownAmount = value
notificationPanelController.setTransitionToFullShadeAmount(field,
false /* animate */, 0 /* delay */)
@@ -427,12 +431,6 @@
}
}
- /**
- * The drag progress of the quick settings drag down amount
- */
- var qSDragProgress = 0f
- private set
-
private fun transitionToShadeAmountCommon(dragDownAmount: Float) {
if (depthControllerTransitionDistance == 0) { // split shade
depthController.transitionToFullShadeProgress = 0f
@@ -705,7 +703,6 @@
it.println("pulseHeight: $pulseHeight")
it.println("useSplitShade: $useSplitShade")
it.println("dragDownAmount: $dragDownAmount")
- it.println("qSDragProgress: $qSDragProgress")
it.println("isDragDownAnywhereEnabled: $isDragDownAnywhereEnabled")
it.println("isFalsingCheckNeeded: $isFalsingCheckNeeded")
it.println("isWakingToShadeLocked: $isWakingToShadeLocked")
@@ -880,15 +877,22 @@
child.actualHeight = (child.collapsedHeight + rubberband).toInt()
}
- private fun cancelChildExpansion(child: ExpandableView) {
+ @VisibleForTesting
+ fun cancelChildExpansion(
+ child: ExpandableView,
+ animationDuration: Long = SPRING_BACK_ANIMATION_LENGTH_MS
+ ) {
if (child.actualHeight == child.collapsedHeight) {
expandCallback.setUserLockedChild(child, false)
return
}
- val anim = ObjectAnimator.ofInt(child, "actualHeight",
- child.actualHeight, child.collapsedHeight)
+ val anim = ValueAnimator.ofInt(child.actualHeight, child.collapsedHeight)
anim.interpolator = Interpolators.FAST_OUT_SLOW_IN
- anim.duration = SPRING_BACK_ANIMATION_LENGTH_MS
+ anim.duration = animationDuration
+ anim.addUpdateListener { animation: ValueAnimator ->
+ // don't use reflection, because the `actualHeight` field may be obfuscated
+ child.actualHeight = animation.animatedValue as Int
+ }
anim.addListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
expandCallback.setUserLockedChild(child, false)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
index ae5a2c3..8699441 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
@@ -51,7 +51,6 @@
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
import com.android.systemui.recents.OverviewProxyService;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider;
@@ -85,9 +84,6 @@
private final SecureSettings mSecureSettings;
private final Object mLock = new Object();
- // Lazy
- private NotificationEntryManager mEntryManager;
-
private final Lazy<NotificationVisibilityProvider> mVisibilityProviderLazy;
private final Lazy<CommonNotifCollection> mCommonNotifCollectionLazy;
private final DevicePolicyManager mDevicePolicyManager;
@@ -119,7 +115,6 @@
isCurrentProfile(getSendingUserId())) {
mUsersAllowingPrivateNotifications.clear();
updateLockscreenNotificationSetting();
- getEntryManager().updateNotifications("ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED");
// TODO(b/231976036): Consolidate pipeline invalidations related to this event
// notifyNotificationStateChanged();
}
@@ -140,10 +135,6 @@
updateLockscreenNotificationSetting();
updatePublicMode();
- // The filtering needs to happen before the update call below in order to
- // make sure
- // the presenter has the updated notifications from the new user
- getEntryManager().reapplyFilterAndSort("user switched");
mPresenter.onUserSwitched(mCurrentUserId);
for (UserChangedListener listener : mListeners) {
@@ -200,13 +191,6 @@
protected ContentObserver mSettingsObserver;
private boolean mHideSilentNotificationsOnLockscreen;
- private NotificationEntryManager getEntryManager() {
- if (mEntryManager == null) {
- mEntryManager = Dependency.get(NotificationEntryManager.class);
- }
- return mEntryManager;
- }
-
@Inject
public NotificationLockscreenUserManagerImpl(Context context,
BroadcastDispatcher broadcastDispatcher,
@@ -253,8 +237,6 @@
mUsersAllowingNotifications.clear();
// ... and refresh all the notifications
updateLockscreenNotificationSetting();
- getEntryManager().updateNotifications("LOCK_SCREEN_SHOW_NOTIFICATIONS,"
- + " or LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS change");
notifyNotificationStateChanged();
}
};
@@ -264,8 +246,6 @@
public void onChange(boolean selfChange) {
updateLockscreenNotificationSetting();
if (mDeviceProvisionedController.isDeviceProvisioned()) {
- getEntryManager().updateNotifications("LOCK_SCREEN_ALLOW_REMOTE_INPUT"
- + " or ZEN_MODE change");
// TODO(b/231976036): Consolidate pipeline invalidations related to this event
// notifyNotificationStateChanged();
}
@@ -596,7 +576,6 @@
setLockscreenPublicMode(isProfilePublic, userId);
mUsersWithSeparateWorkChallenge.put(userId, needsSeparateChallenge);
}
- getEntryManager().updateNotifications("NotificationLockscreenUserManager.updatePublicMode");
// TODO(b/234738798): Migrate KeyguardNotificationVisibilityProvider to use this listener
if (!mLockscreenPublicMode.equals(oldPublicModes)
|| !mUsersWithSeparateWorkChallenge.equals(oldWorkChallenges)) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
index d74d408..f668528 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
@@ -53,8 +53,6 @@
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.dagger.CentralSurfacesDependenciesModule;
import com.android.systemui.statusbar.notification.NotifPipelineFlags;
-import com.android.systemui.statusbar.notification.NotificationEntryListener;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntry.EditedSuggestionInfo;
import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider;
@@ -256,7 +254,6 @@
NotificationLockscreenUserManager lockscreenUserManager,
SmartReplyController smartReplyController,
NotificationVisibilityProvider visibilityProvider,
- NotificationEntryManager notificationEntryManager,
Lazy<Optional<CentralSurfaces>> centralSurfacesOptionalLazy,
StatusBarStateController statusBarStateController,
RemoteInputUriController remoteInputUriController,
@@ -279,25 +276,6 @@
mClickNotifier = clickNotifier;
dumpManager.registerDumpable(this);
-
- notificationEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
- @Override
- public void onPreEntryUpdated(NotificationEntry entry) {
- // Mark smart replies as sent whenever a notification is updated - otherwise the
- // smart replies are never marked as sent.
- mSmartReplyController.stopSending(entry);
- }
-
- @Override
- public void onEntryRemoved(
- @Nullable NotificationEntry entry,
- NotificationVisibility visibility,
- boolean removedByUser,
- int reason) {
- // We're removing the notification, the smart controller can forget about it.
- mSmartReplyController.stopSending(entry);
- }
- });
}
/** Add a listener for various remote input events. Works with NEW pipeline only. */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
index f6c4a31..cb13fcf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
@@ -81,7 +81,6 @@
}
lateinit var root: View
- private var blurRoot: View? = null
private var keyguardAnimator: Animator? = null
private var notificationAnimator: Animator? = null
private var updateScheduled: Boolean = false
@@ -235,7 +234,7 @@
val opaque = scrimsVisible && !blursDisabledForAppLaunch
Trace.traceCounter(Trace.TRACE_TAG_APP, "shade_blur_radius", blur)
- blurUtils.applyBlur(blurRoot?.viewRootImpl ?: root.viewRootImpl, blur, opaque)
+ blurUtils.applyBlur(root.viewRootImpl, blur, opaque)
lastAppliedBlur = blur
wallpaperController.setNotificationShadeZoom(zoomOut)
listeners.forEach {
@@ -271,7 +270,6 @@
override fun onAnimationEnd(animation: Animator?) {
keyguardAnimator = null
wakeAndUnlockBlurRadius = 0f
- scheduleUpdate()
}
})
start()
@@ -302,7 +300,6 @@
override fun onDozeAmountChanged(linear: Float, eased: Float) {
wakeAndUnlockBlurRadius = blurUtils.blurRadiusOfRatio(eased)
- scheduleUpdate()
}
}
@@ -439,12 +436,11 @@
shadeAnimation.animateTo(blurUtils.blurRadiusOfRatio(targetBlurNormalized).toInt())
}
- private fun scheduleUpdate(viewToBlur: View? = null) {
+ private fun scheduleUpdate() {
if (updateScheduled) {
return
}
updateScheduled = true
- blurRoot = viewToBlur
choreographer.postFrameCallback(updateBlurCallback)
}
@@ -495,16 +491,11 @@
*/
private var pendingRadius = -1
- /**
- * View on {@link Surface} that wants depth.
- */
- private var view: View? = null
-
private var springAnimation = SpringAnimation(this, object :
FloatPropertyCompat<DepthAnimation>("blurRadius") {
override fun setValue(rect: DepthAnimation?, value: Float) {
radius = value
- scheduleUpdate(view)
+ scheduleUpdate()
}
override fun getValue(rect: DepthAnimation?): Float {
@@ -519,11 +510,10 @@
springAnimation.addEndListener { _, _, _, _ -> pendingRadius = -1 }
}
- fun animateTo(newRadius: Int, viewToBlur: View? = null) {
- if (pendingRadius == newRadius && view == viewToBlur) {
+ fun animateTo(newRadius: Int) {
+ if (pendingRadius == newRadius) {
return
}
- view = viewToBlur
pendingRadius = newRadius
springAnimation.animateToFinalPosition(newRadius.toFloat())
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index cea3deb..41c0367 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar;
+import static com.android.keyguard.BouncerPanelExpansionCalculator.aboutToShowBouncerProgress;
+
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -90,6 +92,12 @@
super(context, attrs);
}
+ @VisibleForTesting
+ public NotificationShelf(Context context, AttributeSet attrs, boolean showNotificationShelf) {
+ super(context, attrs);
+ mShowNotificationShelf = showNotificationShelf;
+ }
+
@Override
@VisibleForTesting
public void onFinishInflate() {
@@ -175,7 +183,11 @@
if (ambientState.isExpansionChanging() && !ambientState.isOnKeyguard()) {
float expansion = ambientState.getExpansionFraction();
- viewState.alpha = ShadeInterpolation.getContentAlpha(expansion);
+ if (ambientState.isBouncerInTransit()) {
+ viewState.alpha = aboutToShowBouncerProgress(expansion);
+ } else {
+ viewState.alpha = ShadeInterpolation.getContentAlpha(expansion);
+ }
} else {
viewState.alpha = 1f - ambientState.getHideAmount();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
index 6302ef1..bbff046 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
@@ -18,7 +18,7 @@
import android.animation.Animator
import android.animation.AnimatorListenerAdapter
-import android.animation.ObjectAnimator
+import android.animation.ValueAnimator
import android.content.Context
import android.content.res.Configuration
import android.os.PowerManager
@@ -28,6 +28,7 @@
import android.view.MotionEvent
import android.view.VelocityTracker
import android.view.ViewConfiguration
+import androidx.annotation.VisibleForTesting
import com.android.systemui.Dumpable
import com.android.systemui.Gefingerpoken
import com.android.systemui.R
@@ -276,15 +277,22 @@
}
}
- private fun reset(child: ExpandableView) {
+ @VisibleForTesting
+ fun reset(
+ child: ExpandableView,
+ animationDuration: Long = SPRING_BACK_ANIMATION_LENGTH_MS.toLong()
+ ) {
if (child.actualHeight == child.collapsedHeight) {
setUserLocked(child, false)
return
}
- val anim = ObjectAnimator.ofInt(child, "actualHeight",
- child.actualHeight, child.collapsedHeight)
+ val anim = ValueAnimator.ofInt(child.actualHeight, child.collapsedHeight)
anim.interpolator = Interpolators.FAST_OUT_SLOW_IN
- anim.duration = SPRING_BACK_ANIMATION_LENGTH_MS.toLong()
+ anim.duration = animationDuration
+ anim.addUpdateListener { animation: ValueAnimator ->
+ // don't use reflection, because the `actualHeight` field may be obfuscated
+ child.actualHeight = animation.animatedValue as Int
+ }
anim.addListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
setUserLocked(child, false)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
index a57d849b2..25c6dce 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
@@ -38,6 +38,7 @@
import com.android.systemui.DualToneHandler;
import com.android.systemui.R;
import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
+import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState;
import java.util.ArrayList;
@@ -64,6 +65,15 @@
/**
* Designated constructor
+ *
+ * This view is special, in that it is the only view in SystemUI that allows for a configuration
+ * override on a MCC/MNC-basis. This means that for every mobile view inflated, we have to
+ * construct a context with that override, since the resource system doesn't have a way to
+ * handle this for us.
+ *
+ * @param context A context with resources configured by MCC/MNC
+ * @param slot The string key defining which slot this icon refers to. Always "mobile" for the
+ * mobile icon
*/
public static StatusBarMobileView fromContext(
Context context,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/ui/MobileContextProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/ui/MobileContextProvider.kt
new file mode 100644
index 0000000..a02dd34
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/ui/MobileContextProvider.kt
@@ -0,0 +1,137 @@
+/*
+ * 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.connectivity.ui
+
+import android.content.Context
+import android.content.res.Configuration
+import android.os.Bundle
+import android.telephony.SubscriptionInfo
+import android.view.ContextThemeWrapper
+import com.android.systemui.Dumpable
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.demomode.DemoMode
+import com.android.systemui.demomode.DemoMode.COMMAND_NETWORK
+import com.android.systemui.demomode.DemoModeController
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.statusbar.connectivity.NetworkController
+import com.android.systemui.statusbar.connectivity.SignalCallback
+import java.io.PrintWriter
+import javax.inject.Inject
+
+/**
+ * Every subscriptionId can have its own CarrierConfig associated with it, so we have to create our
+ * own [Configuration] and track resources based on the full set of available mcc-mnc combinations.
+ *
+ * (for future reference: b/240555502 is the initiating bug for this)
+ */
+@SysUISingleton
+class MobileContextProvider
+@Inject
+constructor(
+ networkController: NetworkController,
+ dumpManager: DumpManager,
+ private val demoModeController: DemoModeController,
+) : Dumpable, DemoMode {
+ private val subscriptions = mutableMapOf<Int, SubscriptionInfo>()
+ private val signalCallback =
+ object : SignalCallback {
+ override fun setSubs(subs: List<SubscriptionInfo>) {
+ subscriptions.clear()
+ subs.forEach { info -> subscriptions[info.subscriptionId] = info }
+ }
+ }
+
+ // These should always be null when not in demo mode
+ private var demoMcc: Int? = null
+ private var demoMnc: Int? = null
+
+ init {
+ networkController.addCallback(signalCallback)
+ dumpManager.registerDumpable(this)
+ demoModeController.addCallback(this)
+ }
+
+ /**
+ * @return a context with the MCC/MNC [Configuration] values corresponding to this
+ * subscriptionId
+ */
+ fun getMobileContextForSub(subId: Int, context: Context): Context {
+ if (demoModeController.isInDemoMode) {
+ return createMobileContextForDemoMode(context)
+ }
+
+ // Fail back to the given context if no sub exists
+ val info = subscriptions[subId] ?: return context
+
+ return createCarrierConfigContext(context, info.mcc, info.mnc)
+ }
+
+ /** For Demo mode (for now), just apply the same MCC/MNC override for all subIds */
+ private fun createMobileContextForDemoMode(context: Context): Context {
+ return createCarrierConfigContext(context, demoMcc ?: 0, demoMnc ?: 0)
+ }
+
+ override fun dump(pw: PrintWriter, args: Array<out String>) {
+ pw.println(
+ "Subscriptions below will be inflated with a configuration context with " +
+ "MCC/MNC overrides"
+ )
+ subscriptions.forEach { (subId, info) ->
+ pw.println(" Subscription with subId($subId) with MCC/MNC(${info.mcc}/${info.mnc})")
+ }
+ pw.println(" MCC override: ${demoMcc ?: "(none)"}")
+ pw.println(" MNC override: ${demoMnc ?: "(none)"}")
+ }
+
+ override fun demoCommands(): List<String> {
+ return listOf(COMMAND_NETWORK)
+ }
+
+ override fun onDemoModeFinished() {
+ demoMcc = null
+ demoMnc = null
+ }
+
+ override fun dispatchDemoCommand(command: String, args: Bundle) {
+ val mccmnc = args.getString("mccmnc") ?: return
+ // Only length 5/6 strings are valid
+ if (!(mccmnc.length == 5 || mccmnc.length == 6)) {
+ return
+ }
+
+ // MCC is always the first 3 digits, and mnc is the last 2 or 3
+ demoMcc = mccmnc.subSequence(0, 3).toString().toInt()
+ demoMnc = mccmnc.subSequence(3, mccmnc.length).toString().toInt()
+ }
+
+ companion object {
+ /**
+ * Creates a context based on this [SubscriptionInfo]'s MCC/MNC values, allowing the overlay
+ * system to properly load different carrier's iconography
+ */
+ private fun createCarrierConfigContext(context: Context, mcc: Int, mnc: Int): Context {
+ // Copy the existing configuration
+ val c = Configuration(context.resources.configuration)
+ c.mcc = mcc
+ c.mnc = mnc
+
+ return ContextThemeWrapper(context, context.theme).also { ctx ->
+ ctx.applyOverrideConfiguration(c)
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java
index 8752f92..7cd79ca 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java
@@ -18,7 +18,6 @@
import android.app.IActivityManager;
import android.content.Context;
-import android.os.Handler;
import android.os.RemoteException;
import android.service.dreams.IDreamManager;
import android.util.Log;
@@ -42,14 +41,12 @@
import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationShadeWindowController;
-import com.android.systemui.statusbar.RemoteInputNotificationRebuilder;
import com.android.systemui.statusbar.SmartReplyController;
import com.android.systemui.statusbar.StatusBarStateControllerImpl;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.commandline.CommandRegistry;
import com.android.systemui.statusbar.gesture.SwipeStatusBarAwayGestureHandler;
import com.android.systemui.statusbar.notification.NotifPipelineFlags;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotifCollection;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
@@ -99,11 +96,8 @@
NotificationLockscreenUserManager lockscreenUserManager,
SmartReplyController smartReplyController,
NotificationVisibilityProvider visibilityProvider,
- NotificationEntryManager notificationEntryManager,
- RemoteInputNotificationRebuilder rebuilder,
Lazy<Optional<CentralSurfaces>> centralSurfacesOptionalLazy,
StatusBarStateController statusBarStateController,
- Handler mainHandler,
RemoteInputUriController remoteInputUriController,
NotificationClickNotifier clickNotifier,
ActionClickLogger actionClickLogger,
@@ -114,7 +108,6 @@
lockscreenUserManager,
smartReplyController,
visibilityProvider,
- notificationEntryManager,
centralSurfacesOptionalLazy,
statusBarStateController,
remoteInputUriController,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
deleted file mode 100644
index 54be9a6..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.notification;
-
-import android.service.notification.NotificationListenerService;
-import android.service.notification.StatusBarNotification;
-import android.util.ArrayMap;
-
-import androidx.annotation.NonNull;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
-import com.android.systemui.statusbar.notification.dagger.NotificationsModule;
-
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-
-/**
- * NotificationEntryManager is responsible for the adding, removing, and updating of
- * {@link NotificationEntry}s. It also handles tasks such as their inflation and their interaction
- * with other Notification.*Manager objects.
- *
- * We track notification entries through this lifecycle:
- * 1. Pending
- * 2. Active
- * 3. Sorted / filtered (visible)
- *
- * Every entry spends some amount of time in the pending state, while it is being inflated. Once
- * inflated, an entry moves into the active state, where it _could_ potentially be shown to the
- * user. After an entry makes its way into the active state, we sort and filter the entire set to
- * repopulate the visible set.
- */
-public class NotificationEntryManager {
-
- private final NotificationEntryManagerLogger mLogger;
-
- /** Pending notifications are ones awaiting inflation */
- @VisibleForTesting
- protected final HashMap<String, NotificationEntry> mPendingNotifications = new HashMap<>();
- /**
- * Active notifications have been inflated / prepared and could become visible, but may get
- * filtered out if for instance they are not for the current user
- */
- private final ArrayMap<String, NotificationEntry> mActiveNotifications = new ArrayMap<>();
- /** This is the list of "active notifications for this user in this context" */
- @VisibleForTesting
- protected final ArrayList<NotificationEntry> mSortedAndFiltered = new ArrayList<>();
- private final List<NotifCollectionListener> mNotifCollectionListeners = new ArrayList<>();
- private final List<NotificationEntryListener> mNotificationEntryListeners = new ArrayList<>();
-
- /**
- * Injected constructor. See {@link NotificationsModule}.
- */
- public NotificationEntryManager(NotificationEntryManagerLogger logger) {
- mLogger = logger;
- }
-
- /** Adds a {@link NotificationEntryListener}. */
- public void addNotificationEntryListener(NotificationEntryListener listener) {
- mNotificationEntryListeners.add(listener);
- }
-
- /**
- * Removes a {@link NotificationEntryListener} previously registered via
- * {@link #addNotificationEntryListener(NotificationEntryListener)}.
- */
- public void removeNotificationEntryListener(NotificationEntryListener listener) {
- mNotificationEntryListeners.remove(listener);
- }
-
- /**
- * Update the notifications
- * @param reason why the notifications are updating
- */
- public void updateNotifications(String reason) {
- mLogger.logUseWhileNewPipelineActive("updateNotifications", reason);
- }
-
- /*
- * -----
- * Annexed from NotificationData below:
- * Some of these methods may be redundant but require some reworking to remove. For now
- * we'll try to keep the behavior the same and can simplify these interfaces in another pass
- */
-
- /** Resorts / filters the current notification set with the current RankingMap */
- public void reapplyFilterAndSort(String reason) {
- mLogger.logUseWhileNewPipelineActive("reapplyFilterAndSort", reason);
- }
-
- /** dump the current active notification list. Called from CentralSurfaces */
- public void dump(PrintWriter pw, String indent) {
- pw.println("NotificationEntryManager (Legacy)");
- int filteredLen = mSortedAndFiltered.size();
- pw.print(indent);
- pw.println("active notifications: " + filteredLen);
- int active;
- for (active = 0; active < filteredLen; active++) {
- NotificationEntry e = mSortedAndFiltered.get(active);
- dumpEntry(pw, indent, active, e);
- }
- synchronized (mActiveNotifications) {
- int totalLen = mActiveNotifications.size();
- pw.print(indent);
- pw.println("inactive notifications: " + (totalLen - active));
- int inactiveCount = 0;
- for (int i = 0; i < totalLen; i++) {
- NotificationEntry entry = mActiveNotifications.valueAt(i);
- if (!mSortedAndFiltered.contains(entry)) {
- dumpEntry(pw, indent, inactiveCount, entry);
- inactiveCount++;
- }
- }
- }
- }
-
- private void dumpEntry(PrintWriter pw, String indent, int i, NotificationEntry e) {
- pw.print(indent);
- pw.println(" [" + i + "] key=" + e.getKey() + " icon=" + e.getIcons().getStatusBarIcon());
- StatusBarNotification n = e.getSbn();
- pw.print(indent);
- pw.println(" pkg=" + n.getPackageName() + " id=" + n.getId() + " importance="
- + e.getRanking().getImportance());
- pw.print(indent);
- pw.println(" notification=" + n.getNotification());
- }
-
- public void addCollectionListener(@NonNull NotifCollectionListener listener) {
- mNotifCollectionListeners.add(listener);
- }
-
- public void removeCollectionListener(@NonNull NotifCollectionListener listener) {
- mNotifCollectionListeners.remove(listener);
- }
-
- /*
- * End annexation
- * -----
- */
-
-
- /**
- * Provides access to keyguard state and user settings dependent data.
- */
- public interface KeyguardEnvironment {
- /** true if the device is provisioned (should always be true in practice) */
- boolean isDeviceProvisioned();
- /** true if the notification is for the current profiles */
- boolean isNotificationForCurrentProfiles(StatusBarNotification sbn);
- }
-
- /**
- * Used when a notification is removed and it doesn't have a reason that maps to one of the
- * reasons defined in NotificationListenerService
- * (e.g. {@link NotificationListenerService#REASON_CANCEL})
- */
- public static final int UNDEFINED_DISMISS_REASON = 0;
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManagerLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManagerLogger.kt
deleted file mode 100644
index 52dcf02..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManagerLogger.kt
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.notification
-
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
-import com.android.systemui.log.LogLevel.DEBUG
-import com.android.systemui.log.LogLevel.INFO
-import com.android.systemui.log.LogLevel.WARNING
-import com.android.systemui.log.LogMessage
-import com.android.systemui.log.dagger.NotificationLog
-import com.android.systemui.util.Compile
-import javax.inject.Inject
-
-/** Logger for [NotificationEntryManager]. */
-class NotificationEntryManagerLogger @Inject constructor(
- notifPipelineFlags: NotifPipelineFlags,
- @NotificationLog private val buffer: LogBuffer
-) {
- private val devLoggingEnabled by lazy { notifPipelineFlags.isDevLoggingEnabled() }
-
- private inline fun devLog(
- level: LogLevel,
- initializer: LogMessage.() -> Unit,
- noinline printer: LogMessage.() -> String
- ) {
- if (Compile.IS_DEBUG && devLoggingEnabled) buffer.log(TAG, level, initializer, printer)
- }
-
- fun logNotifAdded(key: String) {
- devLog(INFO, {
- str1 = key
- }, {
- "NOTIF ADDED $str1"
- })
- }
-
- fun logNotifUpdated(key: String) {
- devLog(INFO, {
- str1 = key
- }, {
- "NOTIF UPDATED $str1"
- })
- }
-
- fun logInflationAborted(key: String, status: String, reason: String) {
- devLog(DEBUG, {
- str1 = key
- str2 = status
- str3 = reason
- }, {
- "NOTIF INFLATION ABORTED $str1 notifStatus=$str2 reason=$str3"
- })
- }
-
- fun logNotifInflated(key: String, isNew: Boolean) {
- devLog(DEBUG, {
- str1 = key
- bool1 = isNew
- }, {
- "NOTIF INFLATED $str1 isNew=$bool1}"
- })
- }
-
- fun logRemovalIntercepted(key: String) {
- devLog(INFO, {
- str1 = key
- }, {
- "NOTIF REMOVE INTERCEPTED for $str1"
- })
- }
-
- fun logLifetimeExtended(key: String, extenderName: String, status: String) {
- devLog(INFO, {
- str1 = key
- str2 = extenderName
- str3 = status
- }, {
- "NOTIF LIFETIME EXTENDED $str1 extender=$str2 status=$str3"
- })
- }
-
- fun logNotifRemoved(key: String, removedByUser: Boolean) {
- devLog(INFO, {
- str1 = key
- bool1 = removedByUser
- }, {
- "NOTIF REMOVED $str1 removedByUser=$bool1"
- })
- }
-
- fun logFilterAndSort(reason: String) {
- devLog(INFO, {
- str1 = reason
- }, {
- "FILTER AND SORT reason=$str1"
- })
- }
-
- fun logUseWhileNewPipelineActive(method: String, reason: String) {
- buffer.log(TAG, WARNING, {
- str1 = method
- str2 = reason
- }, {
- "While running New Pipeline: $str1(reason=$str2)"
- })
- }
-}
-
-private const val TAG = "NotificationEntryMgr"
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/PipelineDumper.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/PipelineDumper.kt
index a10c745..0bcd3e4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/PipelineDumper.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/PipelineDumper.kt
@@ -26,10 +26,7 @@
class PipelineDumper(pw: PrintWriter) {
private val ipw = pw.asIndenting()
- fun print(a: Any?) = ipw.print(a)
fun println(a: Any?) = ipw.println(a)
- fun withIncreasedIndent(b: () -> Unit) = ipw.withIncreasedIndent(b)
- fun withIncreasedIndent(r: Runnable) = ipw.withIncreasedIndent(r)
fun dump(label: String, value: Any?) {
ipw.print("$label: ")
@@ -37,24 +34,26 @@
}
private fun dump(value: Any?) = when (value) {
- null, is String, is Int -> println(value)
+ null, is String, is Int -> ipw.println(value)
is Collection<*> -> dumpCollection(value)
else -> {
- println(value.fullPipelineName)
- withIncreasedIndent { (value as? PipelineDumpable)?.dumpPipeline(this) }
+ ipw.println(value.fullPipelineName)
+ (value as? PipelineDumpable)?.let {
+ ipw.withIncreasedIndent { it.dumpPipeline(this) }
+ }
}
}
private fun dumpCollection(values: Collection<Any?>) {
- println(values.size)
- withIncreasedIndent { values.forEach { dump(it) } }
+ ipw.println(values.size)
+ ipw.withIncreasedIndent { values.forEach { dump(it) } }
}
}
private val Any.bareClassName: String get() {
val className = javaClass.name
- val packageName = javaClass.`package`.name
- return className.substring(packageName.length + 1)
+ val packagePrefixLength = javaClass.`package`?.name?.length?.plus(1) ?: 0
+ return className.substring(packagePrefixLength)
}
private val Any.barePipelineName: String? get() = when (this) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java
index 3627b40..52f4c1c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java
@@ -144,11 +144,6 @@
public void invalidateNotifications(String reason) {
mNotifFilter.invalidateList(reason);
}
-
- @Override
- public void maybeCancelSummary(NotificationEntry entry) {
- // no-op
- }
};
private boolean isInterceptingDismissal(NotificationEntry entry) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SmartspaceDedupingCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SmartspaceDedupingCoordinator.kt
index 9d0f974..32150fc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SmartspaceDedupingCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SmartspaceDedupingCoordinator.kt
@@ -20,11 +20,9 @@
import android.os.Parcelable
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.plugins.statusbar.StatusBarStateController
-import com.android.systemui.statusbar.NotificationLockscreenUserManager
import com.android.systemui.statusbar.StatusBarState
import com.android.systemui.statusbar.SysuiStatusBarStateController
import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController
-import com.android.systemui.statusbar.notification.NotificationEntryManager
import com.android.systemui.statusbar.notification.collection.NotifPipeline
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope
@@ -44,14 +42,10 @@
* In addition, notifications that have recently alerted aren't filtered. Tracking this in a way
* that involves the fewest pipeline invalidations requires some unfortunately complex logic.
*/
-// This class is a singleton so that the same instance can be accessed by both the old and new
-// pipelines
@CoordinatorScope
class SmartspaceDedupingCoordinator @Inject constructor(
private val statusBarStateController: SysuiStatusBarStateController,
private val smartspaceController: LockscreenSmartspaceController,
- private val notificationEntryManager: NotificationEntryManager,
- private val notificationLockscreenUserManager: NotificationLockscreenUserManager,
private val notifPipeline: NotifPipeline,
@Main private val executor: DelayableExecutor,
private val clock: SystemClock
@@ -132,7 +126,6 @@
if (changed) {
filter.invalidateList("onNewSmartspaceTargets")
- notificationEntryManager.updateNotifications("Smartspace targets changed")
}
trackedSmartspaceTargets = newMap
@@ -169,7 +162,6 @@
target.cancelTimeoutRunnable = null
target.shouldFilter = true
filter.invalidateList("updateAlertException: ${entry.logKey}")
- notificationEntryManager.updateNotifications("deduping timeout expired")
}, alertExceptionExpires - now)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinder.java
index d52f3c6..cdfd2f7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinder.java
@@ -19,12 +19,11 @@
import android.annotation.NonNull;
import com.android.systemui.statusbar.notification.InflationException;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder;
/**
- * Used by the {@link NotificationEntryManager}. When notifications are added or updated, the binder
+ * Used by the {@link NotifInflater}. When notifications are added or updated, the binder
* is asked to (re)inflate and prepare their views. This inflation must occur off the main thread.
*/
public interface NotificationRowBinder {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/CommonNotifCollection.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/CommonNotifCollection.java
index 4ff6a64..fc7d682 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/CommonNotifCollection.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/CommonNotifCollection.java
@@ -19,7 +19,6 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -29,9 +28,8 @@
* A notification collection that manages the list of {@link NotificationEntry}s that will be
* rendered.
*
- * TODO: (b/145659174) Once we fully switch off {@link NotificationEntryManager} to
- * {@link NotifPipeline}, we probably won't need this, but having it for now makes it easy to
- * switch between the two.
+ * TODO: (b/145659174) Once we fully migrate to {@link NotifPipeline}, we probably won't need this,
+ * but having it for now makes it easy to switch between the two.
*/
public interface CommonNotifCollection {
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/RenderStageManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/RenderStageManager.kt
index 7a37846..3061522 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/RenderStageManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/RenderStageManager.kt
@@ -78,10 +78,10 @@
}
override fun dumpPipeline(d: PipelineDumper) = with(d) {
- dump("ViewRenderer", viewRenderer)
- dump("OnAfterRenderListListeners", onAfterRenderListListeners)
- dump("OnAfterRenderGroupListeners", onAfterRenderGroupListeners)
- dump("OnAfterRenderEntryListeners", onAfterRenderEntryListeners)
+ dump("viewRenderer", viewRenderer)
+ dump("onAfterRenderListListeners", onAfterRenderListListeners)
+ dump("onAfterRenderGroupListeners", onAfterRenderGroupListeners)
+ dump("onAfterRenderEntryListeners", onAfterRenderEntryListeners)
}
private fun dispatchOnAfterRenderList(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
index 9333c2a..da4cced 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
@@ -36,8 +36,6 @@
import com.android.systemui.shade.ShadeController;
import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.notification.AssistantFeedbackController;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.notification.NotificationEntryManagerLogger;
import com.android.systemui.statusbar.notification.collection.NotifInflaterImpl;
import com.android.systemui.statusbar.notification.collection.NotifLiveDataStore;
import com.android.systemui.statusbar.notification.collection.NotifLiveDataStoreImpl;
@@ -106,14 +104,6 @@
@Binds
StackScrollAlgorithm.BypassController bindBypassController(KeyguardBypassController impl);
- /** Provides an instance of {@link NotificationEntryManager} */
- @SysUISingleton
- @Provides
- static NotificationEntryManager provideNotificationEntryManager(
- NotificationEntryManagerLogger logger) {
- return new NotificationEntryManager(logger);
- }
-
/** Provides an instance of {@link NotificationGutsManager} */
@SysUISingleton
@Provides
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsController.kt
index 3dcd3cb..b2cb23b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsController.kt
@@ -23,7 +23,6 @@
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl
import com.android.systemui.statusbar.notification.collection.render.NotifStackController
import com.android.systemui.statusbar.notification.stack.NotificationListContainer
-import java.io.PrintWriter
/**
* The master controller for all notifications-related work
@@ -40,9 +39,7 @@
bindRowCallback: NotificationRowBinderImpl.BindRowCallback
)
- fun requestNotificationUpdate(reason: String)
fun resetUserExpandedStates()
fun setNotificationSnoozed(sbn: StatusBarNotification, snoozeOption: SnoozeOption)
fun getActiveNotificationsCount(): Int
- fun dump(pw: PrintWriter, args: Array<String>, dumpTruck: Boolean)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt
index d38b6f9..1aa0295 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.notification.init
import android.service.notification.StatusBarNotification
+import com.android.systemui.ForegroundServiceNotificationListener
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.people.widget.PeopleSpaceWidgetManager
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption
@@ -25,7 +26,6 @@
import com.android.systemui.statusbar.notification.AnimatedImageNotificationManager
import com.android.systemui.statusbar.notification.NotificationActivityStarter
import com.android.systemui.statusbar.notification.NotificationClicker
-import com.android.systemui.statusbar.notification.NotificationEntryManager
import com.android.systemui.statusbar.notification.collection.NotifLiveDataStore
import com.android.systemui.statusbar.notification.collection.NotifPipeline
import com.android.systemui.statusbar.notification.collection.NotificationEntry
@@ -41,7 +41,6 @@
import com.android.systemui.statusbar.phone.CentralSurfaces
import com.android.wm.shell.bubbles.Bubbles
import dagger.Lazy
-import java.io.PrintWriter
import java.util.Optional
import javax.inject.Inject
@@ -56,7 +55,6 @@
class NotificationsControllerImpl @Inject constructor(
private val centralSurfaces: Lazy<CentralSurfaces>,
private val notificationListener: NotificationListener,
- private val entryManager: NotificationEntryManager,
private val commonNotifCollection: Lazy<CommonNotifCollection>,
private val notifPipeline: Lazy<NotifPipeline>,
private val notifLiveDataStore: NotifLiveDataStore,
@@ -69,6 +67,7 @@
private val animatedImageNotificationManager: AnimatedImageNotificationManager,
private val peopleSpaceWidgetManager: PeopleSpaceWidgetManager,
private val bubblesOptional: Optional<Bubbles>,
+ private val fgsNotifListener: ForegroundServiceNotificationListener,
) : NotificationsController {
override fun initialize(
@@ -107,24 +106,11 @@
targetSdkResolver.initialize(notifPipeline.get())
peopleSpaceWidgetManager.attach(notificationListener)
- }
-
- override fun dump(
- pw: PrintWriter,
- args: Array<String>,
- dumpTruck: Boolean
- ) {
- if (dumpTruck) {
- entryManager.dump(pw, " ")
- }
+ fgsNotifListener.init()
}
// TODO: Convert all functions below this line into listeners instead of public methods
- override fun requestNotificationUpdate(reason: String) {
- entryManager.updateNotifications(reason)
- }
-
override fun resetUserExpandedStates() {
// TODO: this is a view thing that should be done through the views, but that means doing it
// both when this event is fired and any time a row is attached.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerStub.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerStub.kt
index 10da0d2..744166d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerStub.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerStub.kt
@@ -24,7 +24,6 @@
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl
import com.android.systemui.statusbar.notification.collection.render.NotifStackController
import com.android.systemui.statusbar.notification.stack.NotificationListContainer
-import java.io.PrintWriter
import javax.inject.Inject
/**
@@ -46,9 +45,6 @@
notificationListener.registerAsSystemService()
}
- override fun requestNotificationUpdate(reason: String) {
- }
-
override fun resetUserExpandedStates() {
}
@@ -58,14 +54,4 @@
override fun getActiveNotificationsCount(): Int {
return 0
}
-
- override fun dump(
- pw: PrintWriter,
- args: Array<String>,
- dumpTruck: Boolean
- ) {
- pw.println()
- pw.println("Notification handling disabled")
- pw.println()
- }
}
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 8574f87..6138265 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
@@ -3455,6 +3455,8 @@
pw.print("visibility: " + getVisibility());
pw.print(", alpha: " + getAlpha());
pw.print(", translation: " + getTranslation());
+ pw.print(", Entry isDismissable: " + mEntry.isDismissable());
+ pw.print(", mOnUserInteractionCallback null: " + (mOnUserInteractionCallback == null));
pw.print(", removed: " + isRemoved());
pw.print(", expandAnimationRunning: " + mExpandAnimationRunning);
NotificationContentView showingLayout = getShowingLayout();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
index ea28452..ce465bc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
@@ -23,6 +23,8 @@
import android.content.Context;
import android.util.MathUtils;
+import androidx.annotation.VisibleForTesting;
+
import com.android.systemui.Dumpable;
import com.android.systemui.R;
import com.android.systemui.dagger.SysUISingleton;
@@ -137,7 +139,17 @@
* True right after we swipe up on lockscreen and have not finished the fling down that follows.
* False when we stop flinging or leave lockscreen.
*/
- private boolean mNeedFlingAfterLockscreenSwipeUp = false;
+ private boolean mIsFlingRequiredAfterLockScreenSwipeUp = false;
+
+ @VisibleForTesting
+ public boolean isFlingRequiredAfterLockScreenSwipeUp() {
+ return mIsFlingRequiredAfterLockScreenSwipeUp;
+ }
+
+ @VisibleForTesting
+ public void setFlingRequiredAfterLockScreenSwipeUp(boolean value) {
+ mIsFlingRequiredAfterLockScreenSwipeUp = value;
+ }
/**
* @return Height of the notifications panel without top padding when expansion completes.
@@ -181,7 +193,7 @@
public void setSwipingUp(boolean isSwipingUp) {
if (!isSwipingUp && mIsSwipingUp) {
// Just stopped swiping up.
- mNeedFlingAfterLockscreenSwipeUp = true;
+ mIsFlingRequiredAfterLockScreenSwipeUp = true;
}
mIsSwipingUp = isSwipingUp;
}
@@ -196,10 +208,10 @@
/**
* @param isFlinging Whether we are flinging the shade open or closed.
*/
- public void setIsFlinging(boolean isFlinging) {
+ public void setFlinging(boolean isFlinging) {
if (isOnKeyguard() && !isFlinging && mIsFlinging) {
// Just stopped flinging.
- mNeedFlingAfterLockscreenSwipeUp = false;
+ mIsFlingRequiredAfterLockScreenSwipeUp = false;
}
mIsFlinging = isFlinging;
}
@@ -508,7 +520,7 @@
public void setStatusBarState(int statusBarState) {
if (mStatusBarState != StatusBarState.KEYGUARD) {
- mNeedFlingAfterLockscreenSwipeUp = false;
+ mIsFlingRequiredAfterLockScreenSwipeUp = false;
}
mStatusBarState = statusBarState;
}
@@ -576,7 +588,7 @@
* @return Whether we need to do a fling down after swiping up on lockscreen.
*/
public boolean isFlingingAfterSwipeUpOnLockscreen() {
- return mIsFlinging && mNeedFlingAfterLockscreenSwipeUp;
+ return mIsFlinging && mIsFlingRequiredAfterLockScreenSwipeUp;
}
/**
@@ -744,7 +756,8 @@
pw.println("mIsSwipingUp=" + mIsSwipingUp);
pw.println("mPanelTracking=" + mPanelTracking);
pw.println("mIsFlinging=" + mIsFlinging);
- pw.println("mNeedFlingAfterLockscreenSwipeUp=" + mNeedFlingAfterLockscreenSwipeUp);
+ pw.println("mIsFlingRequiredAfterLockScreenSwipeUp="
+ + mIsFlingRequiredAfterLockScreenSwipeUp);
pw.println("mZDistanceBetweenElements=" + mZDistanceBetweenElements);
pw.println("mBaseZHeight=" + mBaseZHeight);
}
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 1fb265f..5fbaa51 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
@@ -2794,10 +2794,9 @@
if (mDebugRemoveAnimation) {
Log.d(TAG, "generateRemove " + key
+ "\nmIsExpanded " + mIsExpanded
- + "\nmAnimationsEnabled " + mAnimationsEnabled
- + "\n!invisible group " + !isChildInInvisibleGroup(child));
+ + "\nmAnimationsEnabled " + mAnimationsEnabled);
}
- if (mIsExpanded && mAnimationsEnabled && !isChildInInvisibleGroup(child)) {
+ if (mIsExpanded && mAnimationsEnabled) {
if (!mChildrenToAddAnimated.contains(child)) {
if (mDebugRemoveAnimation) {
Log.d(TAG, "needsAnimation = true " + key);
@@ -2845,26 +2844,6 @@
return hasAddEvent && mAddedHeadsUpChildren.contains(child);
}
- // TODO (b/162832756): remove since this won't happen in new pipeline (we prune groups in
- // ShadeListBuilder)
- /**
- * @param child the child to query
- * @return whether a view is not a top level child but a child notification and that group is
- * not expanded
- */
- @ShadeViewRefactor(RefactorComponent.ADAPTER)
- private boolean isChildInInvisibleGroup(View child) {
- if (child instanceof ExpandableNotificationRow) {
- ExpandableNotificationRow row = (ExpandableNotificationRow) child;
- NotificationEntry groupSummary =
- mGroupMembershipManager.getGroupSummary(row.getEntry());
- if (groupSummary != null && groupSummary.getRow() != row) {
- return row.getVisibility() == View.INVISIBLE;
- }
- }
- return false;
- }
-
/**
* Updates the scroll position when a child was removed
*
@@ -5042,7 +5021,7 @@
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setPanelFlinging(boolean flinging) {
- mAmbientState.setIsFlinging(flinging);
+ mAmbientState.setFlinging(flinging);
if (!flinging) {
// re-calculate the stack height which was frozen while flinging
updateStackPosition();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index ec1e620..843a9ff 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
@@ -81,7 +81,6 @@
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.LaunchAnimationParameters;
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotifCollection;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -155,7 +154,6 @@
private final ScrimController mScrimController;
private final NotifPipeline mNotifPipeline;
private final NotifCollection mNotifCollection;
- private final NotificationEntryManager mNotificationEntryManager;
private final UiEventLogger mUiEventLogger;
private final NotificationRemoteInputManager mRemoteInputManager;
private final ShadeController mShadeController;
@@ -307,7 +305,6 @@
mView.updateSensitiveness(mStatusBarStateController.goingToFullShade(),
mLockscreenUserManager.isAnyProfilePublicMode());
mView.onStatePostChange(mStatusBarStateController.fromShadeLocked());
- mNotificationEntryManager.updateNotifications("CentralSurfaces state changed");
}
};
@@ -634,7 +631,6 @@
@SilentHeader SectionHeaderController silentHeaderController,
NotifPipeline notifPipeline,
NotifCollection notifCollection,
- NotificationEntryManager notificationEntryManager,
LockscreenShadeTransitionController lockscreenShadeTransitionController,
ShadeTransitionController shadeTransitionController,
UiEventLogger uiEventLogger,
@@ -676,7 +672,6 @@
mSilentHeaderController = silentHeaderController;
mNotifPipeline = notifPipeline;
mNotifCollection = notifCollection;
- mNotificationEntryManager = notificationEntryManager;
mUiEventLogger = uiEventLogger;
mRemoteInputManager = remoteInputManager;
mShadeController = shadeController;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
index 353355b..eeed070 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
@@ -163,7 +163,7 @@
// which is more expensive.
if (shelfState.hidden) {
// When the shelf is hidden, it won't clip views, so we don't hide rows
- return;
+ continue;
}
final float shelfTop = shelfState.yTranslation;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
index 8bd7886..1bbacca 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -177,7 +177,6 @@
private KeyguardViewMediator mKeyguardViewMediator;
private ScrimController mScrimController;
private PendingAuthenticated mPendingAuthenticated = null;
- private boolean mPendingShowBouncer;
private boolean mHasScreenTurnedOnSinceAuthenticating;
private boolean mFadedAwayAfterWakeAndUnlock;
private BiometricModeListener mBiometricModeListener;
@@ -474,31 +473,22 @@
break;
case MODE_UNLOCK_COLLAPSING:
Trace.beginSection("MODE_UNLOCK_COLLAPSING");
- if (!wasDeviceInteractive) {
- mPendingShowBouncer = true;
- } else {
- // If the keyguard unlock controller is going to handle the unlock animation, it
- // will fling the panel collapsed when it's ready.
- if (!mKeyguardUnlockAnimationController.willHandleUnlockAnimation()) {
- mShadeController.animateCollapsePanels(
- CommandQueue.FLAG_EXCLUDE_NONE,
- true /* force */,
- false /* delayed */,
- BIOMETRIC_COLLAPSE_SPEEDUP_FACTOR);
- }
- mPendingShowBouncer = false;
- mKeyguardViewController.notifyKeyguardAuthenticated(
- false /* strongAuth */);
+ // If the keyguard unlock controller is going to handle the unlock animation, it
+ // will fling the panel collapsed when it's ready.
+ if (!mKeyguardUnlockAnimationController.willHandleUnlockAnimation()) {
+ mShadeController.animateCollapsePanels(
+ CommandQueue.FLAG_EXCLUDE_NONE,
+ true /* force */,
+ false /* delayed */,
+ BIOMETRIC_COLLAPSE_SPEEDUP_FACTOR);
}
+ mKeyguardViewController.notifyKeyguardAuthenticated(
+ false /* strongAuth */);
Trace.endSection();
break;
case MODE_SHOW_BOUNCER:
Trace.beginSection("MODE_SHOW_BOUNCER");
- if (!wasDeviceInteractive) {
- mPendingShowBouncer = true;
- } else {
- showBouncer();
- }
+ mKeyguardViewController.showBouncer(true);
Trace.endSection();
break;
case MODE_WAKE_AND_UNLOCK_FROM_DREAM:
@@ -536,15 +526,6 @@
}
}
- private void showBouncer() {
- if (mMode == MODE_SHOW_BOUNCER) {
- mKeyguardViewController.showBouncer(true);
- }
- mShadeController.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE, true /* force */,
- false /* delayed */, BIOMETRIC_COLLAPSE_SPEEDUP_FACTOR);
- mPendingShowBouncer = false;
- }
-
public boolean hasPendingAuthentication() {
return mPendingAuthenticated != null
&& mUpdateMonitor
@@ -771,13 +752,6 @@
final WakefulnessLifecycle.Observer mWakefulnessObserver =
new WakefulnessLifecycle.Observer() {
@Override
- public void onFinishedWakingUp() {
- if (mPendingShowBouncer) {
- BiometricUnlockController.this.showBouncer();
- }
- }
-
- @Override
public void onStartedGoingToSleep() {
resetMode();
mFadedAwayAfterWakeAndUnlock = false;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
index 5a80508..f37243a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
@@ -40,6 +40,8 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.statusbar.RegisterStatusBarResult;
+import com.android.keyguard.AuthKeyguardMessageArea;
+import com.android.keyguard.FaceAuthApiRequestReason;
import com.android.systemui.Dumpable;
import com.android.systemui.animation.ActivityLaunchAnimator;
import com.android.systemui.animation.RemoteTransitionAdapter;
@@ -219,15 +221,21 @@
ViewGroup getBouncerContainer();
+ /** Get the Keyguard Message Area that displays auth messages. */
+ AuthKeyguardMessageArea getKeyguardMessageArea();
+
int getStatusBarHeight();
void updateQsExpansionEnabled();
boolean isShadeDisabled();
- void requestNotificationUpdate(String reason);
-
- void requestFaceAuth(boolean userInitiatedRequest);
+ /**
+ * Request face auth to initiated
+ * @param userInitiatedRequest Whether this was a user initiated request
+ * @param reason Reason why face auth was triggered.
+ */
+ void requestFaceAuth(boolean userInitiatedRequest, @FaceAuthApiRequestReason String reason);
@Override
void startActivity(Intent intent, boolean onlyProvisioned, boolean dismissShade,
@@ -386,8 +394,6 @@
void fadeKeyguardAfterLaunchTransition(Runnable beforeFading,
Runnable endRunnable, Runnable cancelRunnable);
- void fadeKeyguardWhilePulsing();
-
void animateKeyguardUnoccluding();
void startLaunchTransitionTimeout();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index 2031f36..820f6e4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -100,11 +100,14 @@
import android.view.ThreadedRenderer;
import android.view.View;
import android.view.ViewGroup;
+import android.view.ViewRootImpl;
import android.view.WindowInsetsController.Appearance;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import android.view.accessibility.AccessibilityManager;
import android.widget.DateTimeView;
+import android.window.OnBackInvokedCallback;
+import android.window.OnBackInvokedDispatcher;
import androidx.annotation.NonNull;
import androidx.lifecycle.Lifecycle;
@@ -120,6 +123,8 @@
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.RegisterStatusBarResult;
+import com.android.keyguard.AuthKeyguardMessageArea;
+import com.android.keyguard.FaceAuthApiRequestReason;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.keyguard.ViewMediatorCallback;
@@ -203,7 +208,6 @@
import com.android.systemui.statusbar.core.StatusBarInitializer;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationLaunchAnimatorControllerProvider;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
import com.android.systemui.statusbar.notification.init.NotificationsController;
@@ -508,7 +512,6 @@
private boolean mExpandedVisible;
- protected final NotificationEntryManager mEntryManager;
private final NotificationGutsManager mGutsManager;
private final NotificationLogger mNotificationLogger;
private final PanelExpansionStateManager mPanelExpansionStateManager;
@@ -526,10 +529,17 @@
private CentralSurfacesComponent mCentralSurfacesComponent;
// Flags for disabling the status bar
- // Two variables becaseu the first one evidently ran out of room for new flags.
+ // Two variables because the first one evidently ran out of room for new flags.
private int mDisabled1 = 0;
private int mDisabled2 = 0;
+ /**
+ * This keeps track of whether we have (or haven't) registered the predictive back callback.
+ * Since we can have visible -> visible transitions, we need to avoid
+ * double-registering (or double-unregistering) our callback.
+ */
+ private boolean mIsBackCallbackRegistered = false;
+
/** @see android.view.WindowInsetsController#setSystemBarsAppearance(int, int) */
private @Appearance int mAppearance;
@@ -653,6 +663,12 @@
private final InteractionJankMonitor mJankMonitor;
+ private final OnBackInvokedCallback mOnBackInvokedCallback = () -> {
+ if (DEBUG) {
+ Log.d(TAG, "mOnBackInvokedCallback() called");
+ }
+ onBackPressed();
+ };
/**
* Public constructor for CentralSurfaces.
@@ -681,7 +697,6 @@
FalsingManager falsingManager,
FalsingCollector falsingCollector,
BroadcastDispatcher broadcastDispatcher,
- NotificationEntryManager notificationEntryManager,
NotificationGutsManager notificationGutsManager,
NotificationLogger notificationLogger,
NotificationInterruptStateProvider notificationInterruptStateProvider,
@@ -768,7 +783,6 @@
mFalsingCollector = falsingCollector;
mFalsingManager = falsingManager;
mBroadcastDispatcher = broadcastDispatcher;
- mEntryManager = notificationEntryManager;
mGutsManager = notificationGutsManager;
mNotificationLogger = notificationLogger;
mNotificationInterruptStateProvider = notificationInterruptStateProvider;
@@ -839,11 +853,8 @@
mPanelExpansionStateManager.addExpansionListener(this::onPanelExpansionChanged);
- mBubbleExpandListener =
- (isExpanding, key) -> mContext.getMainExecutor().execute(() -> {
- mNotificationsController.requestNotificationUpdate("onBubbleExpandChanged");
- updateScrimController();
- });
+ mBubbleExpandListener = (isExpanding, key) ->
+ mContext.getMainExecutor().execute(this::updateScrimController);
mActivityIntentHelper = new ActivityIntentHelper(mContext);
mActivityLaunchAnimator = activityLaunchAnimator;
@@ -1588,6 +1599,11 @@
}
@Override
+ public AuthKeyguardMessageArea getKeyguardMessageArea() {
+ return mNotificationShadeWindowViewController.getKeyguardMessageArea();
+ }
+
+ @Override
public int getStatusBarHeight() {
return mStatusBarWindowController.getStatusBarHeight();
}
@@ -1616,21 +1632,14 @@
}
/**
- * Request a notification update
- * @param reason why we're requesting a notification update
- */
- @Override
- public void requestNotificationUpdate(String reason) {
- mNotificationsController.requestNotificationUpdate(reason);
- }
-
- /**
* Asks {@link KeyguardUpdateMonitor} to run face auth.
*/
@Override
- public void requestFaceAuth(boolean userInitiatedRequest) {
+ public void requestFaceAuth(boolean userInitiatedRequest,
+ @FaceAuthApiRequestReason String reason) {
if (!mKeyguardStateController.canDismissLockScreen()) {
- mKeyguardUpdateMonitor.requestFaceAuth(userInitiatedRequest);
+ mKeyguardUpdateMonitor.requestFaceAuth(
+ userInitiatedRequest, reason);
}
}
@@ -2328,8 +2337,6 @@
mStatusBarKeyguardViewManager.dump(pw);
}
- mNotificationsController.dump(pw, args, DUMPTRUCK);
-
if (DEBUG_GESTURES) {
pw.print(" status bar gestures: ");
mGestureRec.dump(pw, args);
@@ -2760,9 +2767,38 @@
if (visibleToUser) {
handleVisibleToUserChangedImpl(visibleToUser);
mNotificationLogger.startNotificationLogging();
+
+ if (!mIsBackCallbackRegistered) {
+ ViewRootImpl viewRootImpl = getViewRootImpl();
+ if (viewRootImpl != null) {
+ viewRootImpl.getOnBackInvokedDispatcher()
+ .registerOnBackInvokedCallback(OnBackInvokedDispatcher.PRIORITY_DEFAULT,
+ mOnBackInvokedCallback);
+ mIsBackCallbackRegistered = true;
+ if (DEBUG) Log.d(TAG, "is now VISIBLE to user AND callback registered");
+ }
+ } else {
+ if (DEBUG) Log.d(TAG, "is now VISIBLE to user, BUT callback ALREADY unregistered");
+ }
} else {
mNotificationLogger.stopNotificationLogging();
handleVisibleToUserChangedImpl(visibleToUser);
+
+ if (mIsBackCallbackRegistered) {
+ ViewRootImpl viewRootImpl = getViewRootImpl();
+ if (viewRootImpl != null) {
+ viewRootImpl.getOnBackInvokedDispatcher()
+ .unregisterOnBackInvokedCallback(mOnBackInvokedCallback);
+ mIsBackCallbackRegistered = false;
+ if (DEBUG) Log.d(TAG, "is NOT VISIBLE to user, AND callback unregistered");
+ }
+ } else {
+ if (DEBUG) {
+ Log.d(TAG,
+ "is NOT VISIBLE to user, BUT NO callback (or callback ALREADY "
+ + "unregistered)");
+ }
+ }
}
}
@@ -3034,19 +3070,6 @@
}
/**
- * Fades the content of the Keyguard while we are dozing and makes it invisible when finished
- * fading.
- */
- @Override
- public void fadeKeyguardWhilePulsing() {
- mNotificationPanelViewController.fadeOut(0, FADE_KEYGUARD_DURATION_PULSING,
- ()-> {
- hideKeyguard();
- mStatusBarKeyguardViewManager.onKeyguardFadedAway();
- }).start();
- }
-
- /**
* Plays the animation when an activity that was occluding Keyguard goes away.
*/
@Override
@@ -3335,14 +3358,12 @@
// show the bouncer/lockscreen.
if (!mKeyguardViewMediator.isHiding()
&& !mKeyguardUnlockAnimationController.isPlayingCannedUnlockAnimation()) {
- if (mState == StatusBarState.SHADE_LOCKED
- && mKeyguardUpdateMonitor.isUdfpsEnrolled()) {
+ if (mState == StatusBarState.SHADE_LOCKED) {
// shade is showing while locked on the keyguard, so go back to showing the
// lock screen where users can use the UDFPS affordance to enter the device
mStatusBarKeyguardViewManager.reset(true);
- } else if ((mState == StatusBarState.KEYGUARD
- && !mStatusBarKeyguardViewManager.bouncerIsOrWillBeShowing())
- || mState == StatusBarState.SHADE_LOCKED) {
+ } else if (mState == StatusBarState.KEYGUARD
+ && !mStatusBarKeyguardViewManager.bouncerIsOrWillBeShowing()) {
mStatusBarKeyguardViewManager.showGenericBouncer(true /* scrimmed */);
}
}
@@ -3488,6 +3509,12 @@
return mNotificationPanelViewController.getKeyguardBottomAreaView();
}
+ protected ViewRootImpl getViewRootImpl() {
+ NotificationShadeWindowView nswv = getNotificationShadeWindowView();
+ if (nswv != null) return nswv.getViewRootImpl();
+
+ return null;
+ }
/**
* Propagation of the bouncer state, indicating that it's fully visible.
*/
@@ -3805,6 +3832,12 @@
updateScrimController();
}
+ @VisibleForTesting
+ public void setNotificationShadeWindowViewController(
+ NotificationShadeWindowViewController nswvc) {
+ mNotificationShadeWindowViewController = nswvc;
+ }
+
/**
* Set the amount of progress we are currently in if we're transitioning to the full shade.
* 0.0f means we're not transitioning yet, while 1 means we're all the way in the full
@@ -4233,14 +4266,6 @@
maybeEscalateHeadsUp();
}
}
-
- // TODO: (b/145659174) remove when moving to NewNotifPipeline. Replaced by
- // KeyguardCoordinator
- @Override
- public void onStrongAuthStateChanged(int userId) {
- super.onStrongAuthStateChanged(userId);
- mNotificationsController.requestNotificationUpdate("onStrongAuthStateChanged");
- }
};
@@ -4429,7 +4454,6 @@
updateQsExpansionEnabled();
mKeyguardViewMediator.setDozing(mDozing);
- mNotificationsController.requestNotificationUpdate("onDozingChanged");
updateDozingState();
mDozeServiceHost.updateDozing();
updateScrimController();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
index deb6150..1169d3f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.phone;
+import android.content.Context;
+import android.content.res.Configuration;
import android.graphics.Rect;
import android.graphics.drawable.Icon;
import android.os.Bundle;
@@ -29,13 +31,13 @@
import com.android.internal.statusbar.StatusBarIcon;
import com.android.systemui.R;
import com.android.systemui.demomode.DemoMode;
-import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.statusbar.StatusBarMobileView;
import com.android.systemui.statusbar.StatusBarWifiView;
import com.android.systemui.statusbar.StatusIconDisplayable;
+import com.android.systemui.statusbar.connectivity.ui.MobileContextProvider;
import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState;
import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.WifiIconState;
@@ -49,7 +51,6 @@
private final LinearLayout mStatusIcons;
private final ArrayList<StatusBarMobileView> mMobileViews = new ArrayList<>();
private final int mIconSize;
- private final FeatureFlags mFeatureFlags;
private StatusBarWifiView mWifiView;
private boolean mDemoMode;
@@ -57,14 +58,12 @@
public DemoStatusIcons(
LinearLayout statusIcons,
- int iconSize,
- FeatureFlags featureFlags
+ int iconSize
) {
super(statusIcons.getContext());
mStatusIcons = statusIcons;
mIconSize = iconSize;
mColor = DarkIconDispatcher.DEFAULT_ICON_TINT;
- mFeatureFlags = featureFlags;
if (statusIcons instanceof StatusIconContainer) {
setShouldRestrictIcons(((StatusIconContainer) statusIcons).isRestrictingIcons());
@@ -253,9 +252,13 @@
}
}
- public void addMobileView(MobileIconState state) {
+ /**
+ * Add a new mobile icon view
+ */
+ public void addMobileView(MobileIconState state, Context mobileContext) {
Log.d(TAG, "addMobileView: ");
- StatusBarMobileView view = StatusBarMobileView.fromContext(mContext, state.slot);
+ StatusBarMobileView view = StatusBarMobileView
+ .fromContext(mobileContext, state.slot);
view.applyMobileState(state);
view.setStaticDrawableColor(mColor);
@@ -265,19 +268,24 @@
addView(view, getChildCount(), createLayoutParams());
}
- public void updateMobileState(MobileIconState state) {
- Log.d(TAG, "updateMobileState: ");
- // If the view for this subId exists already, use it
+ /**
+ * Apply an update to a mobile icon view for the given {@link MobileIconState}. For
+ * compatibility with {@link MobileContextProvider}, we have to recreate the view every time we
+ * update it, since the context (and thus the {@link Configuration}) may have changed
+ */
+ public void updateMobileState(MobileIconState state, Context mobileContext) {
+ Log.d(TAG, "updateMobileState: " + state);
+
+ // The mobile config provided by MobileContextProvider could have changed; always recreate
for (int i = 0; i < mMobileViews.size(); i++) {
StatusBarMobileView view = mMobileViews.get(i);
if (view.getState().subId == state.subId) {
- view.applyMobileState(state);
- return;
+ removeView(view);
}
}
- // Else we have to add it
- addMobileView(state);
+ // Add the replacement or new icon
+ addMobileView(state, mobileContext);
}
public void onRemoveIcon(StatusIconDisplayable view) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
index 80c3e6c..24ce5e9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
@@ -28,8 +28,6 @@
import android.view.MotionEvent;
import android.view.View;
-import androidx.annotation.Nullable;
-
import com.android.internal.annotations.VisibleForTesting;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.assist.AssistManager;
@@ -50,11 +48,9 @@
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
-import com.android.systemui.unfold.FoldAodAnimationController;
-import com.android.systemui.unfold.SysUIUnfoldComponent;
+import com.android.systemui.util.Assert;
import java.util.ArrayList;
-import java.util.Optional;
import javax.inject.Inject;
@@ -80,8 +76,6 @@
private final WakefulnessLifecycle mWakefulnessLifecycle;
private final SysuiStatusBarStateController mStatusBarStateController;
private final DeviceProvisionedController mDeviceProvisionedController;
- @Nullable
- private final FoldAodAnimationController mFoldAodAnimationController;
private final HeadsUpManagerPhone mHeadsUpManagerPhone;
private final BatteryController mBatteryController;
private final ScrimController mScrimController;
@@ -114,7 +108,6 @@
Lazy<AssistManager> assistManagerLazy,
DozeScrimController dozeScrimController, KeyguardUpdateMonitor keyguardUpdateMonitor,
PulseExpansionHandler pulseExpansionHandler,
- Optional<SysUIUnfoldComponent> sysUIUnfoldComponent,
NotificationShadeWindowController notificationShadeWindowController,
NotificationWakeUpCoordinator notificationWakeUpCoordinator,
AuthController authController,
@@ -138,8 +131,6 @@
mNotificationWakeUpCoordinator = notificationWakeUpCoordinator;
mAuthController = authController;
mNotificationIconAreaController = notificationIconAreaController;
- mFoldAodAnimationController = sysUIUnfoldComponent
- .map(SysUIUnfoldComponent::getFoldAodAnimationController).orElse(null);
}
// TODO: we should try to not pass status bar in here if we can avoid it.
@@ -167,6 +158,7 @@
}
void firePowerSaveChanged(boolean active) {
+ Assert.isMainThread();
for (Callback callback : mCallbacks) {
callback.onPowerSaveChanged(active);
}
@@ -177,6 +169,7 @@
entry.setPulseSuppressed(true);
mNotificationIconAreaController.updateAodNotificationIcons();
};
+ Assert.isMainThread();
for (Callback callback : mCallbacks) {
callback.onNotificationAlerted(pulseSuppressedListener);
}
@@ -193,11 +186,13 @@
@Override
public void addCallback(@NonNull Callback callback) {
+ Assert.isMainThread();
mCallbacks.add(callback);
}
@Override
public void removeCallback(@NonNull Callback callback) {
+ Assert.isMainThread();
mCallbacks.remove(callback);
}
@@ -212,12 +207,10 @@
}
void updateDozing() {
- // When in wake-and-unlock while pulsing, keep dozing state until fully unlocked.
- boolean
- dozing =
- mDozingRequested && mStatusBarStateController.getState() == StatusBarState.KEYGUARD
- || mBiometricUnlockControllerLazy.get().getMode()
- == BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING;
+ Assert.isMainThread();
+
+ boolean dozing =
+ mDozingRequested && mStatusBarStateController.getState() == StatusBarState.KEYGUARD;
// When in wake-and-unlock we may not have received a change to StatusBarState
// but we still should not be dozing, manually set to false.
if (mBiometricUnlockControllerLazy.get().getMode()
@@ -225,11 +218,10 @@
dozing = false;
}
- mStatusBarStateController.setIsDozing(dozing);
- mNotificationShadeWindowViewController.setDozing(dozing);
- if (mFoldAodAnimationController != null) {
- mFoldAodAnimationController.setIsDozing(dozing);
+ for (Callback callback : mCallbacks) {
+ callback.onDozingChanged(dozing);
}
+ mStatusBarStateController.setIsDozing(dozing);
}
@Override
@@ -310,7 +302,6 @@
public void dozeTimeTick() {
mNotificationPanel.dozeTimeTick();
mAuthController.dozeTimeTick();
- mNotificationShadeWindowViewController.dozeTimeTick();
if (mAmbientIndicationContainer instanceof DozeReceiver) {
((DozeReceiver) mAmbientIndicationContainer).dozeTimeTick();
}
@@ -454,6 +445,7 @@
return;
}
mAlwaysOnSuppressed = suppressed;
+ Assert.isMainThread();
for (Callback callback : mCallbacks) {
callback.onAlwaysOnSuppressedChanged(suppressed);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
index 6bfb0da..90d0b69 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
@@ -115,9 +115,7 @@
mInitialTouchY = y;
int startHeight = (int) (mPickedChild.getActualHeight()
+ mPickedChild.getTranslationY());
- float maxPanelHeight = mPanel.getMaxPanelHeight();
- mPanel.setPanelScrimMinFraction(maxPanelHeight > 0f
- ? (float) startHeight / maxPanelHeight : 0f);
+ mPanel.setHeadsUpDraggingStartingHeight(startHeight);
mPanel.startExpandMotion(x, y, true /* startTracking */, startHeight);
// This call needs to be after the expansion start otherwise we will get a
// flicker of one frame as it's not expanded yet.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
deleted file mode 100644
index dc77d10..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ /dev/null
@@ -1,682 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui.statusbar.phone;
-
-import static com.android.internal.util.Preconditions.checkNotNull;
-import static com.android.systemui.controls.dagger.ControlsComponent.Visibility.AVAILABLE;
-import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset;
-import static com.android.systemui.wallet.controller.QuickAccessWalletController.WalletChangeEvent.DEFAULT_PAYMENT_APP_CHANGE;
-import static com.android.systemui.wallet.controller.QuickAccessWalletController.WalletChangeEvent.WALLET_PREFERENCE_CHANGE;
-
-import android.app.ActivityTaskManager;
-import android.app.admin.DevicePolicyManager;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.res.ColorStateList;
-import android.content.res.Configuration;
-import android.graphics.drawable.Drawable;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.service.quickaccesswallet.GetWalletCardsError;
-import android.service.quickaccesswallet.GetWalletCardsResponse;
-import android.service.quickaccesswallet.QuickAccessWalletClient;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.util.TypedValue;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewPropertyAnimator;
-import android.view.WindowInsets;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import com.android.settingslib.Utils;
-import com.android.systemui.Dependency;
-import com.android.systemui.R;
-import com.android.systemui.animation.ActivityLaunchAnimator;
-import com.android.systemui.animation.Interpolators;
-import com.android.systemui.controls.dagger.ControlsComponent;
-import com.android.systemui.controls.management.ControlsListingController;
-import com.android.systemui.controls.ui.ControlsActivity;
-import com.android.systemui.controls.ui.ControlsUiController;
-import com.android.systemui.keyguard.ui.binder.KeyguardBottomAreaViewBinder;
-import com.android.systemui.keyguard.ui.viewmodel.KeyguardBottomAreaViewModel;
-import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.plugins.FalsingManager;
-import com.android.systemui.qrcodescanner.controller.QRCodeScannerController;
-import com.android.systemui.statusbar.policy.KeyguardStateController;
-import com.android.systemui.wallet.controller.QuickAccessWalletController;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Implementation for the bottom area of the Keyguard, including camera/phone affordance and status
- * text.
- */
-public class KeyguardBottomAreaView extends FrameLayout {
-
- private static final String TAG = "CentralSurfaces/KeyguardBottomAreaView";
- private static final int DOZE_ANIMATION_ELEMENT_DURATION = 250;
-
- private ImageView mWalletButton;
- private ImageView mQRCodeScannerButton;
- private ImageView mControlsButton;
- private boolean mHasCard = false;
- private final WalletCardRetriever mCardRetriever = new WalletCardRetriever();
- private QuickAccessWalletController mQuickAccessWalletController;
- private QRCodeScannerController mQRCodeScannerController;
- private ControlsComponent mControlsComponent;
- private boolean mControlServicesAvailable = false;
-
- @Nullable private View mAmbientIndicationArea;
- private ViewGroup mIndicationArea;
- private TextView mIndicationText;
- private TextView mIndicationTextBottom;
- private ViewGroup mOverlayContainer;
-
- private ActivityStarter mActivityStarter;
- private KeyguardStateController mKeyguardStateController;
- private FalsingManager mFalsingManager;
-
- private boolean mDozing;
- private int mIndicationBottomMargin;
- private int mIndicationPadding;
- private float mDarkAmount;
- private int mBurnInXOffset;
- private int mBurnInYOffset;
-
- private final ControlsListingController.ControlsListingCallback mListingCallback =
- serviceInfos -> post(() -> {
- boolean available = !serviceInfos.isEmpty();
-
- if (available != mControlServicesAvailable) {
- mControlServicesAvailable = available;
- updateControlsVisibility();
- updateAffordanceColors();
- }
- });
-
- private final KeyguardStateController.Callback mKeyguardStateCallback =
- new KeyguardStateController.Callback() {
- @Override
- public void onKeyguardShowingChanged() {
- if (mKeyguardStateController.isShowing()) {
- if (mQuickAccessWalletController != null) {
- mQuickAccessWalletController.queryWalletCards(mCardRetriever);
- }
- }
- }
- };
-
- @Nullable private KeyguardBottomAreaViewBinder.Binding mBinding;
- private boolean mUsesBinder;
-
- public KeyguardBottomAreaView(Context context) {
- this(context, null);
- }
-
- public KeyguardBottomAreaView(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public KeyguardBottomAreaView(Context context, AttributeSet attrs, int defStyleAttr) {
- this(context, attrs, defStyleAttr, 0);
- }
-
- public KeyguardBottomAreaView(Context context, AttributeSet attrs, int defStyleAttr,
- int defStyleRes) {
- super(context, attrs, defStyleAttr, defStyleRes);
- }
-
- /**
- * Initializes the view.
- */
- public void init(
- final KeyguardBottomAreaViewModel viewModel,
- final FalsingManager falsingManager) {
- Log.i(TAG, System.identityHashCode(this) + " initialized with a binder");
- mUsesBinder = true;
- mBinding = KeyguardBottomAreaViewBinder.bind(this, viewModel, falsingManager);
- }
-
- /**
- * Initializes the {@link KeyguardBottomAreaView} with the given dependencies
- *
- * @deprecated Use
- * {@link #init(KeyguardBottomAreaViewModel, FalsingManager)} instead
- */
- @Deprecated
- public void init(
- FalsingManager falsingManager,
- QuickAccessWalletController controller,
- ControlsComponent controlsComponent,
- QRCodeScannerController qrCodeScannerController) {
- if (mUsesBinder) {
- return;
- }
-
- Log.i(TAG, "initialized without a binder");
- mFalsingManager = falsingManager;
-
- mQuickAccessWalletController = controller;
- mQuickAccessWalletController.setupWalletChangeObservers(
- mCardRetriever, WALLET_PREFERENCE_CHANGE, DEFAULT_PAYMENT_APP_CHANGE);
- mQuickAccessWalletController.updateWalletPreference();
- mQuickAccessWalletController.queryWalletCards(mCardRetriever);
- updateWalletVisibility();
-
- mControlsComponent = controlsComponent;
- mControlsComponent.getControlsListingController().ifPresent(
- c -> c.addCallback(mListingCallback));
-
- mQRCodeScannerController = qrCodeScannerController;
- mQRCodeScannerController.registerQRCodeScannerChangeObservers(
- QRCodeScannerController.DEFAULT_QR_CODE_SCANNER_CHANGE,
- QRCodeScannerController.QR_CODE_SCANNER_PREFERENCE_CHANGE);
- updateQRCodeButtonVisibility();
-
- updateAffordanceColors();
- }
-
- /**
- * Initializes this instance of {@link KeyguardBottomAreaView} based on the given instance of
- * another {@link KeyguardBottomAreaView}
- */
- public void initFrom(KeyguardBottomAreaView oldBottomArea) {
- if (mUsesBinder) {
- return;
- }
-
- // if it exists, continue to use the original ambient indication container
- // instead of the newly inflated one
- if (mAmbientIndicationArea != null) {
- // remove old ambient indication from its parent
- View originalAmbientIndicationView =
- oldBottomArea.findViewById(R.id.ambient_indication_container);
- ((ViewGroup) originalAmbientIndicationView.getParent())
- .removeView(originalAmbientIndicationView);
-
- // remove current ambient indication from its parent (discard)
- ViewGroup ambientIndicationParent = (ViewGroup) mAmbientIndicationArea.getParent();
- int ambientIndicationIndex =
- ambientIndicationParent.indexOfChild(mAmbientIndicationArea);
- ambientIndicationParent.removeView(mAmbientIndicationArea);
-
- // add the old ambient indication to this view
- ambientIndicationParent.addView(originalAmbientIndicationView, ambientIndicationIndex);
- mAmbientIndicationArea = originalAmbientIndicationView;
-
- // update burn-in offsets
- dozeTimeTick();
- }
- }
-
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
- if (mUsesBinder) {
- return;
- }
-
- mOverlayContainer = findViewById(R.id.overlay_container);
- mWalletButton = findViewById(R.id.wallet_button);
- mQRCodeScannerButton = findViewById(R.id.qr_code_scanner_button);
- mControlsButton = findViewById(R.id.controls_button);
- mIndicationArea = findViewById(R.id.keyguard_indication_area);
- mAmbientIndicationArea = findViewById(R.id.ambient_indication_container);
- mIndicationText = findViewById(R.id.keyguard_indication_text);
- mIndicationTextBottom = findViewById(R.id.keyguard_indication_text_bottom);
- mIndicationBottomMargin = getResources().getDimensionPixelSize(
- R.dimen.keyguard_indication_margin_bottom);
- mBurnInYOffset = getResources().getDimensionPixelSize(
- R.dimen.default_burn_in_prevention_offset);
- mKeyguardStateController = Dependency.get(KeyguardStateController.class);
- mKeyguardStateController.addCallback(mKeyguardStateCallback);
- setClipChildren(false);
- setClipToPadding(false);
- mActivityStarter = Dependency.get(ActivityStarter.class);
-
- mIndicationPadding = getResources().getDimensionPixelSize(
- R.dimen.keyguard_indication_area_padding);
- updateWalletVisibility();
- updateQRCodeButtonVisibility();
- updateControlsVisibility();
- }
-
- @Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
- if (mUsesBinder) {
- return;
- }
-
- final IntentFilter filter = new IntentFilter();
- filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
- mKeyguardStateController.addCallback(mKeyguardStateCallback);
- }
-
- @Override
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- if (mUsesBinder) {
- return;
- }
-
- mKeyguardStateController.removeCallback(mKeyguardStateCallback);
-
- if (mQuickAccessWalletController != null) {
- mQuickAccessWalletController.unregisterWalletChangeObservers(
- WALLET_PREFERENCE_CHANGE, DEFAULT_PAYMENT_APP_CHANGE);
- }
-
- if (mQRCodeScannerController != null) {
- mQRCodeScannerController.unregisterQRCodeScannerChangeObservers(
- QRCodeScannerController.DEFAULT_QR_CODE_SCANNER_CHANGE,
- QRCodeScannerController.QR_CODE_SCANNER_PREFERENCE_CHANGE);
- }
-
- if (mControlsComponent != null) {
- mControlsComponent.getControlsListingController().ifPresent(
- c -> c.removeCallback(mListingCallback));
- }
- }
-
- @Override
- protected void onConfigurationChanged(Configuration newConfig) {
- super.onConfigurationChanged(newConfig);
- if (mUsesBinder) {
- if (mBinding != null) {
- mBinding.onConfigurationChanged();
- }
- return;
- }
-
- mIndicationBottomMargin = getResources().getDimensionPixelSize(
- R.dimen.keyguard_indication_margin_bottom);
- mBurnInYOffset = getResources().getDimensionPixelSize(
- R.dimen.default_burn_in_prevention_offset);
- MarginLayoutParams mlp = (MarginLayoutParams) mIndicationArea.getLayoutParams();
- if (mlp.bottomMargin != mIndicationBottomMargin) {
- mlp.bottomMargin = mIndicationBottomMargin;
- mIndicationArea.setLayoutParams(mlp);
- }
-
- // Respect font size setting.
- mIndicationTextBottom.setTextSize(TypedValue.COMPLEX_UNIT_PX,
- getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.text_size_small_material));
- mIndicationText.setTextSize(TypedValue.COMPLEX_UNIT_PX,
- getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.text_size_small_material));
-
- ViewGroup.LayoutParams lp = mWalletButton.getLayoutParams();
- lp.width = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_width);
- lp.height = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_height);
- mWalletButton.setLayoutParams(lp);
-
- lp = mQRCodeScannerButton.getLayoutParams();
- lp.width = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_width);
- lp.height = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_height);
- mQRCodeScannerButton.setLayoutParams(lp);
-
- lp = mControlsButton.getLayoutParams();
- lp.width = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_width);
- lp.height = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_height);
- mControlsButton.setLayoutParams(lp);
-
- mIndicationPadding = getResources().getDimensionPixelSize(
- R.dimen.keyguard_indication_area_padding);
-
- updateWalletVisibility();
- updateQRCodeButtonVisibility();
- updateAffordanceColors();
- }
-
- private void updateWalletVisibility() {
- if (mUsesBinder) {
- return;
- }
-
- if (mDozing
- || mQuickAccessWalletController == null
- || !mQuickAccessWalletController.isWalletEnabled()
- || !mHasCard) {
- mWalletButton.setVisibility(GONE);
-
- if (mControlsButton.getVisibility() == GONE) {
- mIndicationArea.setPadding(0, 0, 0, 0);
- }
- } else {
- mWalletButton.setVisibility(VISIBLE);
- mWalletButton.setOnClickListener(this::onWalletClick);
- mIndicationArea.setPadding(mIndicationPadding, 0, mIndicationPadding, 0);
- }
- }
-
- private void updateControlsVisibility() {
- if (mUsesBinder) {
- return;
- }
-
- if (mControlsComponent == null) return;
-
- mControlsButton.setImageResource(mControlsComponent.getTileImageId());
- mControlsButton.setContentDescription(getContext()
- .getString(mControlsComponent.getTileTitleId()));
- updateAffordanceColors();
-
- boolean hasFavorites = mControlsComponent.getControlsController()
- .map(c -> c.getFavorites().size() > 0)
- .orElse(false);
- if (mDozing
- || !hasFavorites
- || !mControlServicesAvailable
- || mControlsComponent.getVisibility() != AVAILABLE) {
- mControlsButton.setVisibility(GONE);
- if (mWalletButton.getVisibility() == GONE) {
- mIndicationArea.setPadding(0, 0, 0, 0);
- }
- } else {
- mControlsButton.setVisibility(VISIBLE);
- mControlsButton.setOnClickListener(this::onControlsClick);
- mIndicationArea.setPadding(mIndicationPadding, 0, mIndicationPadding, 0);
- }
- }
-
- public void setDarkAmount(float darkAmount) {
- if (mUsesBinder) {
- return;
- }
-
- if (darkAmount == mDarkAmount) {
- return;
- }
- mDarkAmount = darkAmount;
- dozeTimeTick();
- }
-
- /**
- * Returns a list of animators to use to animate the indication areas.
- */
- public List<ViewPropertyAnimator> getIndicationAreaAnimators() {
- if (mUsesBinder) {
- return checkNotNull(mBinding).getIndicationAreaAnimators();
- }
-
- List<ViewPropertyAnimator> animators =
- new ArrayList<>(mAmbientIndicationArea != null ? 2 : 1);
- animators.add(mIndicationArea.animate());
- if (mAmbientIndicationArea != null) {
- animators.add(mAmbientIndicationArea.animate());
- }
- return animators;
- }
-
- @Override
- public boolean hasOverlappingRendering() {
- return false;
- }
-
- private void startFinishDozeAnimation() {
- long delay = 0;
- if (mWalletButton.getVisibility() == View.VISIBLE) {
- startFinishDozeAnimationElement(mWalletButton, delay);
- }
- if (mQRCodeScannerButton.getVisibility() == View.VISIBLE) {
- startFinishDozeAnimationElement(mQRCodeScannerButton, delay);
- }
- if (mControlsButton.getVisibility() == View.VISIBLE) {
- startFinishDozeAnimationElement(mControlsButton, delay);
- }
- }
-
- private void startFinishDozeAnimationElement(View element, long delay) {
- element.setAlpha(0f);
- element.setTranslationY(element.getHeight() / 2);
- element.animate()
- .alpha(1f)
- .translationY(0f)
- .setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN)
- .setStartDelay(delay)
- .setDuration(DOZE_ANIMATION_ELEMENT_DURATION);
- }
-
- public void setDozing(boolean dozing, boolean animate) {
- if (mUsesBinder) {
- return;
- }
-
- mDozing = dozing;
-
- updateWalletVisibility();
- updateControlsVisibility();
- updateQRCodeButtonVisibility();
-
- if (dozing) {
- mOverlayContainer.setVisibility(INVISIBLE);
- } else {
- mOverlayContainer.setVisibility(VISIBLE);
- if (animate) {
- startFinishDozeAnimation();
- }
- }
- }
-
- public void dozeTimeTick() {
- if (mUsesBinder) {
- return;
- }
-
- int burnInYOffset = getBurnInOffset(mBurnInYOffset * 2, false /* xAxis */)
- - mBurnInYOffset;
- mIndicationArea.setTranslationY(burnInYOffset * mDarkAmount);
- if (mAmbientIndicationArea != null) {
- mAmbientIndicationArea.setTranslationY(burnInYOffset * mDarkAmount);
- }
- }
-
- public void setAntiBurnInOffsetX(int burnInXOffset) {
- if (mUsesBinder) {
- return;
- }
-
- if (mBurnInXOffset == burnInXOffset) {
- return;
- }
- mBurnInXOffset = burnInXOffset;
- mIndicationArea.setTranslationX(burnInXOffset);
- if (mAmbientIndicationArea != null) {
- mAmbientIndicationArea.setTranslationX(burnInXOffset);
- }
- }
-
- /**
- * Sets the alpha of various sub-components, for example the indication areas and bottom quick
- * action buttons. Does not set the alpha of the lock icon.
- */
- public void setComponentAlphas(float alpha) {
- if (mUsesBinder) {
- return;
- }
-
- setImportantForAccessibility(
- alpha == 0f
- ? View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
- : View.IMPORTANT_FOR_ACCESSIBILITY_AUTO);
- if (mAmbientIndicationArea != null) {
- mAmbientIndicationArea.setAlpha(alpha);
- }
- mIndicationArea.setAlpha(alpha);
- mWalletButton.setAlpha(alpha);
- mQRCodeScannerButton.setAlpha(alpha);
- mControlsButton.setAlpha(alpha);
- }
-
- @Override
- public WindowInsets onApplyWindowInsets(WindowInsets insets) {
- int bottom = insets.getDisplayCutout() != null
- ? insets.getDisplayCutout().getSafeInsetBottom() : 0;
- if (isPaddingRelative()) {
- setPaddingRelative(getPaddingStart(), getPaddingTop(), getPaddingEnd(), bottom);
- } else {
- setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(), bottom);
- }
- return insets;
- }
-
- private void updateQRCodeButtonVisibility() {
- if (mUsesBinder) {
- return;
- }
-
- if (mQuickAccessWalletController != null
- && mQuickAccessWalletController.isWalletEnabled()) {
- // Don't enable if quick access wallet is enabled
- return;
- }
-
- if (mQRCodeScannerController != null
- && mQRCodeScannerController.isEnabledForLockScreenButton()) {
- mQRCodeScannerButton.setVisibility(VISIBLE);
- mQRCodeScannerButton.setOnClickListener(this::onQRCodeScannerClicked);
- mIndicationArea.setPadding(mIndicationPadding, 0, mIndicationPadding, 0);
- } else {
- mQRCodeScannerButton.setVisibility(GONE);
- if (mControlsButton.getVisibility() == GONE) {
- mIndicationArea.setPadding(0, 0, 0, 0);
- }
- }
- }
-
- private void onQRCodeScannerClicked(View view) {
- if (mUsesBinder) {
- return;
- }
-
- Intent intent = mQRCodeScannerController.getIntent();
- if (intent != null) {
- try {
- ActivityTaskManager.getService().startActivityAsUser(
- null, getContext().getBasePackageName(),
- getContext().getAttributionTag(), intent,
- intent.resolveTypeIfNeeded(getContext().getContentResolver()),
- null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null, null,
- UserHandle.CURRENT.getIdentifier());
- } catch (RemoteException e) {
- // This is unexpected. Nonetheless, just log the error and prevent the UI from
- // crashing
- Log.e(TAG, "Unexpected intent: " + intent
- + " when the QR code scanner button was clicked");
- }
- }
- }
-
- private void updateAffordanceColors() {
- if (mUsesBinder) {
- return;
- }
-
- int iconColor = Utils.getColorAttrDefaultColor(
- mContext,
- com.android.internal.R.attr.textColorPrimary);
- mWalletButton.getDrawable().setTint(iconColor);
- mControlsButton.getDrawable().setTint(iconColor);
- mQRCodeScannerButton.getDrawable().setTint(iconColor);
-
- ColorStateList bgColor = Utils.getColorAttr(
- mContext,
- com.android.internal.R.attr.colorSurface);
- mWalletButton.setBackgroundTintList(bgColor);
- mControlsButton.setBackgroundTintList(bgColor);
- mQRCodeScannerButton.setBackgroundTintList(bgColor);
- }
-
- private void onWalletClick(View v) {
- if (mUsesBinder) {
- return;
- }
-
- // More coming here; need to inform the user about how to proceed
- if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
- return;
- }
-
- ActivityLaunchAnimator.Controller animationController = createLaunchAnimationController(v);
- mQuickAccessWalletController.startQuickAccessUiIntent(
- mActivityStarter, animationController, mHasCard);
- }
-
- protected ActivityLaunchAnimator.Controller createLaunchAnimationController(View view) {
- return ActivityLaunchAnimator.Controller.fromView(view, null);
- }
-
- private void onControlsClick(View v) {
- if (mUsesBinder) {
- return;
- }
-
- if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
- return;
- }
-
- Intent intent = new Intent(mContext, ControlsActivity.class)
- .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK)
- .putExtra(ControlsUiController.EXTRA_ANIMATE, true);
-
- ActivityLaunchAnimator.Controller controller =
- v != null ? ActivityLaunchAnimator.Controller.fromView(v, null /* cujType */)
- : null;
- if (mControlsComponent.getVisibility() == AVAILABLE) {
- mActivityStarter.startActivity(intent, true /* dismissShade */, controller,
- true /* showOverLockscreenWhenLocked */);
- } else {
- mActivityStarter.postStartActivityDismissingKeyguard(intent, 0 /* delay */, controller);
- }
- }
-
- private class WalletCardRetriever implements
- QuickAccessWalletClient.OnWalletCardsRetrievedCallback {
-
- @Override
- public void onWalletCardsRetrieved(@NonNull GetWalletCardsResponse response) {
- mHasCard = !response.getWalletCards().isEmpty();
- Drawable tileIcon = mQuickAccessWalletController.getWalletClient().getTileIcon();
- if (tileIcon != null) {
- mWalletButton.setImageDrawable(tileIcon);
- }
- post(() -> {
- updateWalletVisibility();
- updateAffordanceColors();
- });
- }
-
- @Override
- public void onWalletCardRetrievalError(@NonNull GetWalletCardsError error) {
- mHasCard = false;
- post(() -> {
- updateWalletVisibility();
- updateAffordanceColors();
- });
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.kt
new file mode 100644
index 0000000..4897c52
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.kt
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+package com.android.systemui.statusbar.phone
+
+import android.content.Context
+import android.content.res.Configuration
+import android.util.AttributeSet
+import android.view.View
+import android.view.ViewGroup
+import android.view.ViewPropertyAnimator
+import android.view.WindowInsets
+import android.widget.FrameLayout
+import com.android.systemui.R
+import com.android.systemui.keyguard.ui.binder.KeyguardBottomAreaViewBinder
+import com.android.systemui.keyguard.ui.binder.KeyguardBottomAreaViewBinder.bind
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardBottomAreaViewModel
+import com.android.systemui.plugins.FalsingManager
+
+/**
+ * Renders the bottom area of the lock-screen. Concerned primarily with the quick affordance UI
+ * elements. A secondary concern is the interaction of the quick affordance elements with the
+ * indication area between them, though the indication area is primarily controlled elsewhere.
+ */
+class KeyguardBottomAreaView
+@JvmOverloads
+constructor(
+ context: Context,
+ attrs: AttributeSet? = null,
+ defStyleAttr: Int = 0,
+ defStyleRes: Int = 0,
+) :
+ FrameLayout(
+ context,
+ attrs,
+ defStyleAttr,
+ defStyleRes,
+ ) {
+
+ private var ambientIndicationArea: View? = null
+ private lateinit var binding: KeyguardBottomAreaViewBinder.Binding
+
+ /** Initializes the view. */
+ fun init(
+ viewModel: KeyguardBottomAreaViewModel,
+ falsingManager: FalsingManager,
+ ) {
+ binding = bind(this, viewModel, falsingManager)
+ }
+
+ /**
+ * Initializes this instance of [KeyguardBottomAreaView] based on the given instance of another
+ * [KeyguardBottomAreaView]
+ */
+ fun initFrom(oldBottomArea: KeyguardBottomAreaView) {
+ // if it exists, continue to use the original ambient indication container
+ // instead of the newly inflated one
+ ambientIndicationArea?.let { nonNullAmbientIndicationArea ->
+ // remove old ambient indication from its parent
+ val originalAmbientIndicationView =
+ oldBottomArea.findViewById<View>(R.id.ambient_indication_container)
+ (originalAmbientIndicationView.parent as ViewGroup).removeView(
+ originalAmbientIndicationView
+ )
+
+ // remove current ambient indication from its parent (discard)
+ val ambientIndicationParent = nonNullAmbientIndicationArea.parent as ViewGroup
+ val ambientIndicationIndex =
+ ambientIndicationParent.indexOfChild(nonNullAmbientIndicationArea)
+ ambientIndicationParent.removeView(nonNullAmbientIndicationArea)
+
+ // add the old ambient indication to this view
+ ambientIndicationParent.addView(originalAmbientIndicationView, ambientIndicationIndex)
+ ambientIndicationArea = originalAmbientIndicationView
+ }
+ }
+
+ override fun onFinishInflate() {
+ super.onFinishInflate()
+ ambientIndicationArea = findViewById(R.id.ambient_indication_container)
+ }
+
+ override fun onConfigurationChanged(newConfig: Configuration) {
+ super.onConfigurationChanged(newConfig)
+ binding.onConfigurationChanged()
+ }
+
+ /** Returns a list of animators to use to animate the indication areas. */
+ val indicationAreaAnimators: List<ViewPropertyAnimator>
+ get() = binding.getIndicationAreaAnimators()
+
+ override fun hasOverlappingRendering(): Boolean {
+ return false
+ }
+
+ override fun onApplyWindowInsets(insets: WindowInsets): WindowInsets {
+ val bottom = insets.displayCutout?.safeInsetBottom ?: 0
+ if (isPaddingRelative) {
+ setPaddingRelative(paddingStart, paddingTop, paddingEnd, bottom)
+ } else {
+ setPadding(paddingLeft, paddingTop, paddingRight, bottom)
+ }
+ return insets
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardEnvironmentImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardEnvironmentImpl.java
deleted file mode 100644
index 2c4fc6c..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardEnvironmentImpl.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the specific language governing
- * permissions and limitations under the License.
- */
-
-package com.android.systemui.statusbar.phone;
-
-import static com.android.systemui.statusbar.phone.CentralSurfaces.DEBUG;
-import static com.android.systemui.statusbar.phone.CentralSurfaces.MULTIUSER_DEBUG;
-
-import android.service.notification.StatusBarNotification;
-import android.util.Log;
-
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.statusbar.NotificationLockscreenUserManager;
-import com.android.systemui.statusbar.notification.NotificationEntryManager.KeyguardEnvironment;
-import com.android.systemui.statusbar.policy.DeviceProvisionedController;
-
-import javax.inject.Inject;
-
-@SysUISingleton
-public class KeyguardEnvironmentImpl implements KeyguardEnvironment {
-
- private static final String TAG = "KeyguardEnvironmentImpl";
-
- private final NotificationLockscreenUserManager mLockscreenUserManager;
- private final DeviceProvisionedController mDeviceProvisionedController;
-
- @Inject
- public KeyguardEnvironmentImpl(
- NotificationLockscreenUserManager notificationLockscreenUserManager,
- DeviceProvisionedController deviceProvisionedController) {
- mLockscreenUserManager = notificationLockscreenUserManager;
- mDeviceProvisionedController = deviceProvisionedController;
- }
-
- @Override // NotificationEntryManager.KeyguardEnvironment
- public boolean isDeviceProvisioned() {
- return mDeviceProvisionedController.isDeviceProvisioned();
- }
-
- @Override // NotificationEntryManager.KeyguardEnvironment
- public boolean isNotificationForCurrentProfiles(StatusBarNotification n) {
- final int notificationUserId = n.getUserId();
- if (DEBUG && MULTIUSER_DEBUG) {
- Log.v(TAG, String.format("%s: current userid: %d, notification userid: %d", n,
- mLockscreenUserManager.getCurrentUserId(), notificationUserId));
- }
- return mLockscreenUserManager.isCurrentProfile(notificationUserId);
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt
index 3f8e97f1..b58dbe2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt
@@ -22,6 +22,7 @@
import android.hardware.TriggerEvent
import android.hardware.TriggerEventListener
import com.android.keyguard.ActiveUnlockConfig
+import com.android.keyguard.FaceAuthApiRequestReason
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.KeyguardUpdateMonitorCallback
import com.android.systemui.CoreStartable
@@ -71,7 +72,10 @@
// Not listening anymore since trigger events unregister themselves
isListening = false
updateListeningState()
- keyguardUpdateMonitor.requestFaceAuth(true)
+ keyguardUpdateMonitor.requestFaceAuth(
+ true,
+ FaceAuthApiRequestReason.PICK_UP_GESTURE_TRIGGERED
+ )
keyguardUpdateMonitor.requestActiveUnlock(
ActiveUnlockConfig.ACTIVE_UNLOCK_REQUEST_ORIGIN.WAKE,
"KeyguardLiftController")
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index 290df3e..48e58fc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -33,6 +33,7 @@
import android.content.res.Resources;
import android.media.AudioManager;
import android.os.Handler;
+import android.os.Looper;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
@@ -127,7 +128,7 @@
private final DateFormatUtil mDateFormatUtil;
private final TelecomManager mTelecomManager;
- private final Handler mHandler = new Handler();
+ private final Handler mHandler;
private final CastController mCast;
private final HotspotController mHotspot;
private final NextAlarmController mNextAlarmController;
@@ -166,7 +167,7 @@
@Inject
public PhoneStatusBarPolicy(StatusBarIconController iconController,
CommandQueue commandQueue, BroadcastDispatcher broadcastDispatcher,
- @UiBackground Executor uiBgExecutor, @Main Resources resources,
+ @UiBackground Executor uiBgExecutor, @Main Looper looper, @Main Resources resources,
CastController castController, HotspotController hotspotController,
BluetoothController bluetoothController, NextAlarmController nextAlarmController,
UserInfoController userInfoController, RotationLockController rotationLockController,
@@ -185,6 +186,7 @@
mIconController = iconController;
mCommandQueue = commandQueue;
mBroadcastDispatcher = broadcastDispatcher;
+ mHandler = new Handler(looper);
mResources = resources;
mCast = castController;
mHotspot = hotspotController;
@@ -332,6 +334,7 @@
mRotationLockController.addCallback(this);
mBluetooth.addCallback(this);
mProvisionedController.addCallback(this);
+ mCurrentUserSetup = mProvisionedController.isCurrentUserSetup();
mZenController.addCallback(this);
mCast.addCallback(mCastCallback);
mHotspot.addCallback(mHotspotCallback);
@@ -562,6 +565,7 @@
mHandler.post(() -> {
updateAlarm();
updateManagedProfile();
+ onUserSetupChanged();
});
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index cb0a148..4d1c361 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -259,11 +259,17 @@
private boolean mKeyguardOccluded;
@Inject
- public ScrimController(LightBarController lightBarController, DozeParameters dozeParameters,
- AlarmManager alarmManager, KeyguardStateController keyguardStateController,
- DelayedWakeLock.Builder delayedWakeLockBuilder, Handler handler,
- KeyguardUpdateMonitor keyguardUpdateMonitor, DockManager dockManager,
- ConfigurationController configurationController, @Main Executor mainExecutor,
+ public ScrimController(
+ LightBarController lightBarController,
+ DozeParameters dozeParameters,
+ AlarmManager alarmManager,
+ KeyguardStateController keyguardStateController,
+ DelayedWakeLock.Builder delayedWakeLockBuilder,
+ Handler handler,
+ KeyguardUpdateMonitor keyguardUpdateMonitor,
+ DockManager dockManager,
+ ConfigurationController configurationController,
+ @Main Executor mainExecutor,
ScreenOffAnimationController screenOffAnimationController,
KeyguardUnlockAnimationController keyguardUnlockAnimationController,
StatusBarKeyguardViewManager statusBarKeyguardViewManager) {
@@ -826,20 +832,15 @@
mBehindTint = Color.BLACK;
} else {
mBehindAlpha = behindAlpha;
- if (mState == ScrimState.SHADE_LOCKED) {
+ if (mState == ScrimState.KEYGUARD && mTransitionToFullShadeProgress > 0.0f) {
+ mNotificationsAlpha = MathUtils
+ .saturate(mTransitionToLockScreenFullShadeNotificationsProgress);
+ } else if (mState == ScrimState.SHADE_LOCKED) {
// going from KEYGUARD to SHADE_LOCKED state
mNotificationsAlpha = getInterpolatedFraction();
} else {
mNotificationsAlpha = Math.max(1.0f - getInterpolatedFraction(), mQsExpansion);
}
- if (mState == ScrimState.KEYGUARD
- && mTransitionToLockScreenFullShadeNotificationsProgress > 0.0f) {
- // Interpolate the notification alpha when transitioning!
- mNotificationsAlpha = MathUtils.lerp(
- mNotificationsAlpha,
- getInterpolatedFraction(),
- mTransitionToLockScreenFullShadeNotificationsProgress);
- }
mNotificationsTint = mState.getNotifTint();
mBehindTint = behindTint;
}
@@ -1430,6 +1431,8 @@
pw.print(mNotificationsAlpha);
pw.print(" tint=0x");
pw.println(Integer.toHexString(mNotificationsScrim.getTint()));
+ pw.print(" expansionProgress=");
+ pw.println(mTransitionToLockScreenFullShadeNotificationsProgress);
pw.print(" mTracking=");
pw.println(mTracking);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java
index ebfbf54..ae201e3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java
@@ -120,7 +120,6 @@
@Override
public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) {
- mNotificationsController.requestNotificationUpdate("onHeadsUpStateChanged");
if (mStatusBarStateController.isDozing() && isHeadsUp) {
entry.setPulseSuppressed(false);
mDozeServiceHost.fireNotificationPulse(entry);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
index 8273d57..bd99713 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
@@ -36,7 +36,6 @@
import com.android.systemui.R;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.demomode.DemoModeCommandReceiver;
-import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
import com.android.systemui.statusbar.BaseStatusBarWifiView;
@@ -44,6 +43,7 @@
import com.android.systemui.statusbar.StatusBarMobileView;
import com.android.systemui.statusbar.StatusBarWifiView;
import com.android.systemui.statusbar.StatusIconDisplayable;
+import com.android.systemui.statusbar.connectivity.ui.MobileContextProvider;
import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.CallIndicatorIconState;
import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState;
import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.WifiIconState;
@@ -70,6 +70,7 @@
void addIconGroup(IconManager iconManager);
/** */
void removeIconGroup(IconManager iconManager);
+
/** Refresh the state of an IconManager by recreating the views */
void refreshIconGroup(IconManager iconManager);
/** */
@@ -82,21 +83,25 @@
void setSignalIcon(String slot, WifiIconState state);
/** */
void setMobileIcons(String slot, List<MobileIconState> states);
+
/**
* Display the no calling & SMS icons.
*/
void setCallStrengthIcons(String slot, List<CallIndicatorIconState> states);
+
/**
* Display the no calling & SMS icons.
*/
void setNoCallingIcons(String slot, List<CallIndicatorIconState> states);
+
public void setIconVisibility(String slot, boolean b);
/**
* Sets the live region mode for the icon
- * @see android.view.View#setAccessibilityLiveRegion(int)
- * @param slot Icon slot to set region for
+ *
+ * @param slot Icon slot to set region for
* @param accessibilityLiveRegion live region mode for the icon
+ * @see android.view.View#setAccessibilityLiveRegion(int)
*/
void setIconAccessibilityLiveRegion(String slot, int accessibilityLiveRegion);
@@ -115,8 +120,8 @@
static ArraySet<String> getIconHideList(Context context, String hideListStr) {
ArraySet<String> ret = new ArraySet<>();
String[] hideList = hideListStr == null
- ? context.getResources().getStringArray(R.array.config_statusBarIconsToExclude)
- : hideListStr.split(",");
+ ? context.getResources().getStringArray(R.array.config_statusBarIconsToExclude)
+ : hideListStr.split(",");
for (String slot : hideList) {
if (!TextUtils.isEmpty(slot)) {
ret.add(slot);
@@ -134,11 +139,14 @@
public DarkIconManager(
LinearLayout linearLayout,
- FeatureFlags featureFlags,
StatusBarPipelineFlags statusBarPipelineFlags,
Provider<WifiViewModel> wifiViewModelProvider,
+ MobileContextProvider mobileContextProvider,
DarkIconDispatcher darkIconDispatcher) {
- super(linearLayout, featureFlags, statusBarPipelineFlags, wifiViewModelProvider);
+ super(linearLayout,
+ statusBarPipelineFlags,
+ wifiViewModelProvider,
+ mobileContextProvider);
mIconHPadding = mContext.getResources().getDimensionPixelSize(
R.dimen.status_bar_icon_padding);
mDarkIconDispatcher = darkIconDispatcher;
@@ -195,41 +203,49 @@
@SysUISingleton
public static class Factory {
- private final FeatureFlags mFeatureFlags;
private final StatusBarPipelineFlags mStatusBarPipelineFlags;
private final Provider<WifiViewModel> mWifiViewModelProvider;
+ private final MobileContextProvider mMobileContextProvider;
private final DarkIconDispatcher mDarkIconDispatcher;
@Inject
public Factory(
- FeatureFlags featureFlags,
StatusBarPipelineFlags statusBarPipelineFlags,
Provider<WifiViewModel> wifiViewModelProvider,
+ MobileContextProvider mobileContextProvider,
DarkIconDispatcher darkIconDispatcher) {
- mFeatureFlags = featureFlags;
mStatusBarPipelineFlags = statusBarPipelineFlags;
mWifiViewModelProvider = wifiViewModelProvider;
+ mMobileContextProvider = mobileContextProvider;
mDarkIconDispatcher = darkIconDispatcher;
}
public DarkIconManager create(LinearLayout group) {
return new DarkIconManager(
- group, mFeatureFlags, mStatusBarPipelineFlags, mWifiViewModelProvider,
+ group,
+ mStatusBarPipelineFlags,
+ mWifiViewModelProvider,
+ mMobileContextProvider,
mDarkIconDispatcher);
}
}
}
- /** */
+ /**
+ *
+ */
class TintedIconManager extends IconManager {
private int mColor;
public TintedIconManager(
ViewGroup group,
- FeatureFlags featureFlags,
StatusBarPipelineFlags statusBarPipelineFlags,
- Provider<WifiViewModel> wifiViewModelProvider) {
- super(group, featureFlags, statusBarPipelineFlags, wifiViewModelProvider);
+ Provider<WifiViewModel> wifiViewModelProvider,
+ MobileContextProvider mobileContextProvider) {
+ super(group,
+ statusBarPipelineFlags,
+ wifiViewModelProvider,
+ mobileContextProvider);
}
@Override
@@ -261,23 +277,26 @@
@SysUISingleton
public static class Factory {
- private final FeatureFlags mFeatureFlags;
private final StatusBarPipelineFlags mStatusBarPipelineFlags;
private final Provider<WifiViewModel> mWifiViewModelProvider;
+ private final MobileContextProvider mMobileContextProvider;
@Inject
public Factory(
- FeatureFlags featureFlags,
StatusBarPipelineFlags statusBarPipelineFlags,
- Provider<WifiViewModel> wifiViewModelProvider) {
- mFeatureFlags = featureFlags;
+ Provider<WifiViewModel> wifiViewModelProvider,
+ MobileContextProvider mobileContextProvider) {
mStatusBarPipelineFlags = statusBarPipelineFlags;
mWifiViewModelProvider = wifiViewModelProvider;
+ mMobileContextProvider = mobileContextProvider;
}
public TintedIconManager create(ViewGroup group) {
return new TintedIconManager(
- group, mFeatureFlags, mStatusBarPipelineFlags, mWifiViewModelProvider);
+ group,
+ mStatusBarPipelineFlags,
+ mWifiViewModelProvider,
+ mMobileContextProvider);
}
}
}
@@ -287,9 +306,9 @@
*/
class IconManager implements DemoModeCommandReceiver {
protected final ViewGroup mGroup;
- private final FeatureFlags mFeatureFlags;
private final StatusBarPipelineFlags mStatusBarPipelineFlags;
private final Provider<WifiViewModel> mWifiViewModelProvider;
+ private final MobileContextProvider mMobileContextProvider;
protected final Context mContext;
protected final int mIconSize;
// Whether or not these icons show up in dumpsys
@@ -305,13 +324,13 @@
public IconManager(
ViewGroup group,
- FeatureFlags featureFlags,
StatusBarPipelineFlags statusBarPipelineFlags,
- Provider<WifiViewModel> wifiViewModelProvider) {
+ Provider<WifiViewModel> wifiViewModelProvider,
+ MobileContextProvider mobileContextProvider) {
mGroup = group;
- mFeatureFlags = featureFlags;
mStatusBarPipelineFlags = statusBarPipelineFlags;
mWifiViewModelProvider = wifiViewModelProvider;
+ mMobileContextProvider = mobileContextProvider;
mContext = group.getContext();
mIconSize = mContext.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.status_bar_icon_size);
@@ -403,12 +422,15 @@
@VisibleForTesting
protected StatusBarMobileView addMobileIcon(int index, String slot, MobileIconState state) {
- StatusBarMobileView view = onCreateStatusBarMobileView(slot);
+ // Use the `subId` field as a key to query for the correct context
+ StatusBarMobileView view = onCreateStatusBarMobileView(state.subId, slot);
view.applyMobileState(state);
mGroup.addView(view, index, onCreateLayoutParams());
if (mIsInDemoMode) {
- mDemoStatusIcons.addMobileView(state);
+ Context mobileContext = mMobileContextProvider
+ .getMobileContextForSub(state.subId, mContext);
+ mDemoStatusIcons.addMobileView(state, mobileContext);
}
return view;
}
@@ -427,8 +449,10 @@
mContext, slot, mWifiViewModelProvider.get());
}
- private StatusBarMobileView onCreateStatusBarMobileView(String slot) {
- StatusBarMobileView view = StatusBarMobileView.fromContext(mContext, slot);
+ private StatusBarMobileView onCreateStatusBarMobileView(int subId, String slot) {
+ Context mobileContext = mMobileContextProvider.getMobileContextForSub(subId, mContext);
+ StatusBarMobileView view = StatusBarMobileView
+ .fromContext(mobileContext, slot);
return view;
}
@@ -516,7 +540,9 @@
}
if (mIsInDemoMode) {
- mDemoStatusIcons.updateMobileState(state);
+ Context mobileContext = mMobileContextProvider
+ .getMobileContextForSub(state.subId, mContext);
+ mDemoStatusIcons.updateMobileState(state, mobileContext);
}
}
@@ -553,7 +579,7 @@
}
protected DemoStatusIcons createDemoStatusIcons() {
- return new DemoStatusIcons((LinearLayout) mGroup, mIconSize, mFeatureFlags);
+ return new DemoStatusIcons((LinearLayout) mGroup, mIconSize);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index d5c6f89..4c5c23c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -44,7 +44,7 @@
import com.android.internal.util.LatencyTracker;
import com.android.internal.widget.LockPatternUtils;
-import com.android.keyguard.KeyguardMessageArea;
+import com.android.keyguard.AuthKeyguardMessageArea;
import com.android.keyguard.KeyguardMessageAreaController;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
@@ -122,7 +122,7 @@
private final DreamOverlayStateController mDreamOverlayStateController;
@Nullable
private final FoldAodAnimationController mFoldAodAnimationController;
- private KeyguardMessageAreaController mKeyguardMessageAreaController;
+ private KeyguardMessageAreaController<AuthKeyguardMessageArea> mKeyguardMessageAreaController;
private final Lazy<com.android.systemui.shade.ShadeController> mShadeController;
private final BouncerExpansionCallback mExpansionCallback = new BouncerExpansionCallback() {
@@ -311,7 +311,7 @@
mBypassController = bypassController;
mNotificationContainer = notificationContainer;
mKeyguardMessageAreaController = mKeyguardMessageAreaFactory.create(
- KeyguardMessageArea.findSecurityMessageDisplay(container));
+ centralSurfaces.getKeyguardMessageArea());
registerListeners();
}
@@ -378,11 +378,9 @@
return;
} else if (mNotificationPanelViewController.isUnlockHintRunning()) {
mBouncer.setExpansion(KeyguardBouncer.EXPANSION_HIDDEN);
- } else if (mStatusBarStateController.getState() == StatusBarState.SHADE_LOCKED
- && mKeyguardUpdateManager.isUdfpsEnrolled()) {
+ } else if (mStatusBarStateController.getState() == StatusBarState.SHADE_LOCKED) {
// Don't expand to the bouncer. Instead transition back to the lock screen (see
- // CentralSurfaces#showBouncerOrLockScreenIfKeyguard) where the user can use the UDFPS
- // affordance to enter the device (or swipe up to the input bouncer)
+ // CentralSurfaces#showBouncerOrLockScreenIfKeyguard)
return;
} else if (bouncerNeedsScrimming()) {
mBouncer.setExpansion(KeyguardBouncer.EXPANSION_VISIBLE);
@@ -589,7 +587,7 @@
public void reset(boolean hideBouncerWhenShowing) {
if (mShowing) {
// Hide quick settings.
- mNotificationPanelViewController.resetViews(/* animate= */ true);
+ mNotificationPanelViewController.resetViews(/* animate= */ !mOccluded);
// Hide bouncer and quick-quick settings.
if (mOccluded && !mDozing) {
mCentralSurfaces.hideKeyguard();
@@ -616,7 +614,8 @@
private void updateAlternateAuthShowing(boolean updateScrim) {
final boolean isShowingAltAuth = isShowingAlternateAuth();
if (mKeyguardMessageAreaController != null) {
- mKeyguardMessageAreaController.setAltBouncerShowing(isShowingAltAuth);
+ mKeyguardMessageAreaController.setIsVisible(isShowingAltAuth);
+ mKeyguardMessageAreaController.setMessage("");
}
mBypassController.setAltBouncerShowing(isShowingAltAuth);
mKeyguardUpdateManager.setUdfpsBouncerShowing(isShowingAltAuth);
@@ -837,30 +836,24 @@
});
} else {
executeAfterKeyguardGoneAction();
- boolean wakeUnlockPulsing =
- mBiometricUnlockController.getMode() == MODE_WAKE_AND_UNLOCK_PULSING;
mCentralSurfaces.setKeyguardFadingAway(startTime, delay, fadeoutDuration);
mBiometricUnlockController.startKeyguardFadingAway();
hideBouncer(true /* destroyView */);
- if (wakeUnlockPulsing) {
- mCentralSurfaces.fadeKeyguardWhilePulsing();
+
+ boolean staying = mStatusBarStateController.leaveOpenOnKeyguardHide();
+ if (!staying) {
+ mNotificationShadeWindowController.setKeyguardFadingAway(true);
+ mCentralSurfaces.hideKeyguard();
+ // hide() will happen asynchronously and might arrive after the scrims
+ // were already hidden, this means that the transition callback won't
+ // be triggered anymore and StatusBarWindowController will be forever in
+ // the fadingAway state.
+ mCentralSurfaces.updateScrimController();
wakeAndUnlockDejank();
} else {
- boolean staying = mStatusBarStateController.leaveOpenOnKeyguardHide();
- if (!staying) {
- mNotificationShadeWindowController.setKeyguardFadingAway(true);
- mCentralSurfaces.hideKeyguard();
- // hide() will happen asynchronously and might arrive after the scrims
- // were already hidden, this means that the transition callback won't
- // be triggered anymore and StatusBarWindowController will be forever in
- // the fadingAway state.
- mCentralSurfaces.updateScrimController();
- wakeAndUnlockDejank();
- } else {
- mCentralSurfaces.hideKeyguard();
- mCentralSurfaces.finishKeyguardFadingAway();
- mBiometricUnlockController.finishKeyguardFadingAway();
- }
+ mCentralSurfaces.hideKeyguard();
+ mCentralSurfaces.finishKeyguardFadingAway();
+ mBiometricUnlockController.finishKeyguardFadingAway();
}
updateStates();
@@ -1043,7 +1036,6 @@
if (bouncerShowing != mLastBouncerShowing || mFirstUpdate) {
mNotificationShadeWindowController.setBouncerShowing(bouncerShowing);
mCentralSurfaces.setBouncerShowing(bouncerShowing);
- mKeyguardMessageAreaController.setBouncerShowing(bouncerShowing);
}
if (occluded != mLastOccluded || mFirstUpdate) {
@@ -1192,7 +1184,8 @@
}
}
- public void showBouncerMessage(String message, ColorStateList colorState) {
+ /** Display security message to relevant KeyguardMessageArea. */
+ public void setKeyguardMessage(String message, ColorStateList colorState) {
if (isShowingAlternateAuth()) {
if (mKeyguardMessageAreaController != null) {
mKeyguardMessageAreaController.setMessage(message);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
index 6996ee7..64ca2705 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
@@ -33,8 +33,6 @@
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.statusbar.IStatusBarService;
-import com.android.systemui.Dependency;
-import com.android.systemui.ForegroundServiceNotificationListener;
import com.android.systemui.InitController;
import com.android.systemui.R;
import com.android.systemui.plugins.ActivityStarter;
@@ -184,10 +182,6 @@
mMediaManager.setUpWithPresenter(this);
mGutsManager.setUpWithPresenter(
this, mNotifListContainer, mOnSettingsClickListener);
- // ForegroundServiceNotificationListener adds its listener in its constructor
- // but we need to request it here in order for it to be instantiated.
- // TODO: figure out how to do this correctly once Dependency.get() is gone.
- Dependency.get(ForegroundServiceNotificationListener.class);
onUserSwitched(mLockscreenUserManager.getCurrentUserId());
});
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/panelstate/PanelExpansionStateManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/panelstate/PanelExpansionStateManager.kt
index a6160aa..6b7c42e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/panelstate/PanelExpansionStateManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/panelstate/PanelExpansionStateManager.kt
@@ -114,8 +114,8 @@
"end state=${state.panelStateToString()} " +
"f=$fraction " +
"expanded=$expanded " +
- "tracking=$tracking" +
- "drawDownPxAmount=$dragDownPxAmount " +
+ "tracking=$tracking " +
+ "dragDownPxAmount=$dragDownPxAmount " +
"${if (fullyOpened) " fullyOpened" else ""} " +
if (fullyClosed) " fullyClosed" else ""
)
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 88eccb5..681dc6f 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
@@ -18,6 +18,8 @@
import com.android.systemui.CoreStartable
import com.android.systemui.statusbar.pipeline.ConnectivityInfoProcessor
+import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepository
+import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepositoryImpl
import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository
import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepositoryImpl
import dagger.Binds
@@ -34,5 +36,8 @@
abstract fun bindConnectivityInfoProcessor(cip: ConnectivityInfoProcessor): CoreStartable
@Binds
+ abstract fun connectivityRepository(impl: ConnectivityRepositoryImpl): ConnectivityRepository
+
+ @Binds
abstract fun wifiRepository(impl: WifiRepositoryImpl): WifiRepository
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLogger.kt
index 2a89309..88d8a86 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLogger.kt
@@ -34,7 +34,7 @@
/**
* Logs a change in one of the **raw inputs** to the connectivity pipeline.
*/
- fun logInputChange(callbackName: String, changeInfo: String) {
+ fun logInputChange(callbackName: String, changeInfo: String?) {
buffer.log(
SB_LOGGING_TAG,
LogLevel.INFO,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/data/model/ConnectivitySlots.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/data/model/ConnectivitySlots.kt
new file mode 100644
index 0000000..d52d0fb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/data/model/ConnectivitySlots.kt
@@ -0,0 +1,56 @@
+/*
+ * 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.shared.data.model
+
+import android.content.Context
+import com.android.internal.R
+import com.android.systemui.dagger.SysUISingleton
+import javax.inject.Inject
+
+/**
+ * A container for all the different types of connectivity slots: wifi, mobile, etc.
+ */
+@SysUISingleton
+class ConnectivitySlots @Inject constructor(context: Context) {
+ private val airplaneSlot: String = context.getString(R.string.status_bar_airplane)
+ private val mobileSlot: String = context.getString(R.string.status_bar_mobile)
+ private val wifiSlot: String = context.getString(R.string.status_bar_wifi)
+ private val ethernetSlot: String = context.getString(R.string.status_bar_ethernet)
+
+ private val slotByName: Map<String, ConnectivitySlot> = mapOf(
+ airplaneSlot to ConnectivitySlot.AIRPLANE,
+ mobileSlot to ConnectivitySlot.MOBILE,
+ wifiSlot to ConnectivitySlot.WIFI,
+ ethernetSlot to ConnectivitySlot.ETHERNET
+ )
+
+ /**
+ * Given a string name of a slot, returns the instance of [ConnectivitySlot] that it corresponds
+ * to, or null if we couldn't find that slot name.
+ */
+ fun getSlotFromName(slotName: String): ConnectivitySlot? {
+ return slotByName[slotName]
+ }
+}
+
+/** The different types of connectivity slots. */
+enum class ConnectivitySlot {
+ AIRPLANE,
+ ETHERNET,
+ MOBILE,
+ WIFI,
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepository.kt
new file mode 100644
index 0000000..6b1750d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepository.kt
@@ -0,0 +1,120 @@
+/*
+ * 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.shared.data.repository
+
+import android.content.Context
+import androidx.annotation.ArrayRes
+import androidx.annotation.VisibleForTesting
+import com.android.systemui.Dumpable
+import com.android.systemui.R
+import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.statusbar.phone.StatusBarIconController
+import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
+import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.SB_LOGGING_TAG
+import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot
+import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlots
+import com.android.systemui.tuner.TunerService
+import java.io.PrintWriter
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.stateIn
+
+/**
+ * Provides data related to the connectivity state that needs to be shared across multiple different
+ * types of connectivity (wifi, mobile, ethernet, etc.)
+ */
+interface ConnectivityRepository {
+ /**
+ * Observable for the current set of connectivity icons that should be force-hidden.
+ */
+ val forceHiddenSlots: StateFlow<Set<ConnectivitySlot>>
+}
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SysUISingleton
+class ConnectivityRepositoryImpl @Inject constructor(
+ private val connectivitySlots: ConnectivitySlots,
+ context: Context,
+ dumpManager: DumpManager,
+ logger: ConnectivityPipelineLogger,
+ @Application scope: CoroutineScope,
+ tunerService: TunerService,
+) : ConnectivityRepository, Dumpable {
+ init {
+ dumpManager.registerDumpable("$SB_LOGGING_TAG:ConnectivityRepository", this)
+ }
+
+ // The default set of hidden icons to use if we don't get any from [TunerService].
+ private val defaultHiddenIcons: Set<ConnectivitySlot> =
+ context.resources.getStringArray(DEFAULT_HIDDEN_ICONS_RESOURCE)
+ .asList()
+ .toSlotSet(connectivitySlots)
+
+ override val forceHiddenSlots: StateFlow<Set<ConnectivitySlot>> = conflatedCallbackFlow {
+ val callback = object : TunerService.Tunable {
+ override fun onTuningChanged(key: String, newHideList: String?) {
+ if (key != HIDDEN_ICONS_TUNABLE_KEY) {
+ return
+ }
+ logger.logInputChange("onTuningChanged", newHideList)
+
+ val outputList = newHideList?.split(",")?.toSlotSet(connectivitySlots)
+ ?: defaultHiddenIcons
+ trySend(outputList)
+ }
+ }
+ tunerService.addTunable(callback, HIDDEN_ICONS_TUNABLE_KEY)
+
+ awaitClose { tunerService.removeTunable(callback) }
+ }
+ .stateIn(
+ scope,
+ started = SharingStarted.WhileSubscribed(),
+ initialValue = defaultHiddenIcons
+ )
+
+ override fun dump(pw: PrintWriter, args: Array<out String>) {
+ pw.apply {
+ println("defaultHiddenIcons=$defaultHiddenIcons")
+ }
+ }
+
+ companion object {
+ @VisibleForTesting
+ internal const val HIDDEN_ICONS_TUNABLE_KEY = StatusBarIconController.ICON_HIDE_LIST
+ @VisibleForTesting
+ @ArrayRes
+ internal val DEFAULT_HIDDEN_ICONS_RESOURCE = R.array.config_statusBarIconsToExclude
+
+ /** Converts a list of string slot names to a set of [ConnectivitySlot] instances. */
+ private fun List<String>.toSlotSet(
+ connectivitySlots: ConnectivitySlots
+ ): Set<ConnectivitySlot> {
+ return this
+ .filter { it.isNotBlank() }
+ .mapNotNull { connectivitySlots.getSlotFromName(it) }
+ .toSet()
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractor.kt
index afe19af..952525d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractor.kt
@@ -18,6 +18,8 @@
import android.net.wifi.WifiManager
import com.android.systemui.dagger.SysUISingleton
+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.pipeline.wifi.data.model.WifiNetworkModel
import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository
import javax.inject.Inject
@@ -33,9 +35,10 @@
*/
@SysUISingleton
class WifiInteractor @Inject constructor(
- repository: WifiRepository,
+ connectivityRepository: ConnectivityRepository,
+ wifiRepository: WifiRepository,
) {
- private val ssid: Flow<String?> = repository.wifiNetwork.map { info ->
+ private val ssid: Flow<String?> = wifiRepository.wifiNetwork.map { info ->
when (info) {
is WifiNetworkModel.Inactive -> null
is WifiNetworkModel.CarrierMerged -> null
@@ -49,10 +52,16 @@
}
/** Our current wifi network. See [WifiNetworkModel]. */
- val wifiNetwork: Flow<WifiNetworkModel> = repository.wifiNetwork
+ val wifiNetwork: Flow<WifiNetworkModel> = wifiRepository.wifiNetwork
+
+ /** True if we're configured to force-hide the wifi icon and false otherwise. */
+ val isForceHidden: Flow<Boolean> = connectivityRepository.forceHiddenSlots.map {
+ it.contains(ConnectivitySlot.WIFI)
+ }
/** True if our wifi network has activity in (download), and false otherwise. */
- val hasActivityIn: Flow<Boolean> = combine(repository.wifiActivity, ssid) { activity, ssid ->
+ val hasActivityIn: Flow<Boolean> =
+ combine(wifiRepository.wifiActivity, ssid) { activity, ssid ->
activity.hasActivityIn && ssid != null
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/binder/WifiViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/binder/WifiViewBinder.kt
index 7607ddf..4fad327 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/binder/WifiViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/binder/WifiViewBinder.kt
@@ -24,6 +24,7 @@
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
import com.android.systemui.R
+import com.android.systemui.common.ui.binder.IconViewBinder
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.WifiViewModel
import kotlinx.coroutines.InternalCoroutinesApi
@@ -54,14 +55,15 @@
view.repeatWhenAttached {
repeatOnLifecycle(Lifecycle.State.STARTED) {
launch {
- viewModel.wifiIconResId.distinctUntilChanged().collect { iconResId ->
- iconView.setImageDrawable(
- if (iconResId != null && iconResId > 0) {
- iconView.context.getDrawable(iconResId)
- } else {
- null
- }
- )
+ viewModel.wifiIcon.distinctUntilChanged().collect { wifiIcon ->
+ // TODO(b/238425913): Right now, if !isVisible, there's just an empty space
+ // where the wifi icon would be. We need to pipe isVisible through to
+ // [ModernStatusBarWifiView.isIconVisible], which is what actually makes
+ // the view GONE.
+ view.isVisible = wifiIcon != null
+ wifiIcon?.let {
+ IconViewBinder.bind(wifiIcon, iconView)
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt
index 4fdcc44..3c243ac 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt
@@ -16,8 +16,16 @@
package com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel
+import android.content.Context
import android.graphics.Color
import androidx.annotation.DrawableRes
+import androidx.annotation.StringRes
+import androidx.annotation.VisibleForTesting
+import com.android.settingslib.AccessibilityContentDescriptions.WIFI_CONNECTION_STRENGTH
+import com.android.settingslib.AccessibilityContentDescriptions.WIFI_NO_CONNECTION
+import com.android.systemui.R
+import com.android.systemui.common.shared.model.ContentDescription
+import com.android.systemui.common.shared.model.Icon
import com.android.systemui.statusbar.connectivity.WifiIcons.WIFI_FULL_ICONS
import com.android.systemui.statusbar.connectivity.WifiIcons.WIFI_NO_INTERNET_ICONS
import com.android.systemui.statusbar.connectivity.WifiIcons.WIFI_NO_NETWORK
@@ -29,6 +37,7 @@
import com.android.systemui.statusbar.pipeline.wifi.shared.WifiConstants
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
@@ -39,6 +48,7 @@
class WifiViewModel @Inject constructor(
statusBarPipelineFlags: StatusBarPipelineFlags,
private val constants: WifiConstants,
+ private val context: Context,
private val logger: ConnectivityPipelineLogger,
private val interactor: WifiInteractor,
) {
@@ -46,7 +56,7 @@
* The drawable resource ID to use for the wifi icon. Null if we shouldn't display any icon.
*/
@DrawableRes
- val wifiIconResId: Flow<Int?> = interactor.wifiNetwork.map {
+ private val iconResId: Flow<Int?> = interactor.wifiNetwork.map {
when (it) {
is WifiNetworkModel.CarrierMerged -> null
is WifiNetworkModel.Inactive -> WIFI_NO_NETWORK
@@ -59,6 +69,49 @@
}
}
+ /** The content description for the wifi icon. */
+ private val contentDescription: Flow<ContentDescription?> = interactor.wifiNetwork.map {
+ when (it) {
+ is WifiNetworkModel.CarrierMerged -> null
+ is WifiNetworkModel.Inactive ->
+ ContentDescription.Loaded(
+ "${context.getString(WIFI_NO_CONNECTION)},${context.getString(NO_INTERNET)}"
+ )
+ is WifiNetworkModel.Active ->
+ when (it.level) {
+ null -> null
+ else -> {
+ val levelDesc = context.getString(WIFI_CONNECTION_STRENGTH[it.level])
+ when {
+ it.isValidated -> ContentDescription.Loaded(levelDesc)
+ else -> ContentDescription.Loaded(
+ "$levelDesc,${context.getString(NO_INTERNET)}"
+ )
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * The wifi icon that should be displayed. Null if we shouldn't display any icon.
+ */
+ val wifiIcon: Flow<Icon?> = combine(
+ interactor.isForceHidden,
+ iconResId,
+ contentDescription,
+ ) { isForceHidden, iconResId, contentDescription ->
+ when {
+ isForceHidden ||
+ iconResId == null ||
+ iconResId <= 0 -> null
+ else -> Icon.Resource(iconResId, contentDescription)
+ }
+ }
+
+ /**
+ * True if the activity in icon should be displayed and false otherwise.
+ */
val isActivityInVisible: Flow<Boolean>
get() =
if (!constants.shouldShowActivityConfig) {
@@ -74,4 +127,10 @@
} else {
flowOf(Color.CYAN)
}
+
+ companion object {
+ @StringRes
+ @VisibleForTesting
+ internal val NO_INTERNET = R.string.data_connection_no_internet
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
index bdac888..f4d08e0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
@@ -31,6 +31,7 @@
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
+import com.android.keyguard.logging.KeyguardUpdateMonitorLogger;
import com.android.systemui.Dumpable;
import com.android.systemui.R;
import com.android.systemui.dagger.SysUISingleton;
@@ -60,6 +61,7 @@
private final KeyguardUpdateMonitorCallback mKeyguardUpdateMonitorCallback =
new UpdateMonitorCallback();
private final Lazy<KeyguardUnlockAnimationController> mUnlockAnimationControllerLazy;
+ private final KeyguardUpdateMonitorLogger mLogger;
private boolean mCanDismissLockScreen;
private boolean mShowing;
@@ -107,8 +109,10 @@
KeyguardUpdateMonitor keyguardUpdateMonitor,
LockPatternUtils lockPatternUtils,
Lazy<KeyguardUnlockAnimationController> keyguardUnlockAnimationController,
+ KeyguardUpdateMonitorLogger logger,
DumpManager dumpManager) {
mContext = context;
+ mLogger = logger;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mLockPatternUtils = lockPatternUtils;
mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateMonitorCallback);
@@ -245,6 +249,8 @@
mTrusted = trusted;
mTrustManaged = trustManaged;
mFaceAuthEnabled = faceAuthEnabled;
+ mLogger.logKeyguardStateUpdate(
+ mSecure, mCanDismissLockScreen, mTrusted, mTrustManaged);
notifyUnlockedChanged();
}
Trace.endSection();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index a5bcb53..62bda2c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -86,6 +86,7 @@
import com.android.systemui.telephony.TelephonyListenerManager;
import com.android.systemui.user.CreateUserActivity;
import com.android.systemui.user.data.source.UserRecord;
+import com.android.systemui.user.legacyhelper.ui.LegacyUserUiHelper;
import com.android.systemui.util.settings.GlobalSettings;
import com.android.systemui.util.settings.SecureSettings;
@@ -100,14 +101,20 @@
import javax.inject.Inject;
+import kotlinx.coroutines.flow.Flow;
+import kotlinx.coroutines.flow.MutableStateFlow;
+import kotlinx.coroutines.flow.StateFlowKt;
+
/**
* Keeps a list of all users on the device for user switching.
*/
@SysUISingleton
public class UserSwitcherController implements Dumpable {
- public static final float USER_SWITCH_ENABLED_ALPHA = 1.0f;
- public static final float USER_SWITCH_DISABLED_ALPHA = 0.38f;
+ public static final float USER_SWITCH_ENABLED_ALPHA =
+ LegacyUserUiHelper.USER_SWITCHER_USER_VIEW_SELECTABLE_ALPHA;
+ public static final float USER_SWITCH_DISABLED_ALPHA =
+ LegacyUserUiHelper.USER_SWITCHER_USER_VIEW_NOT_SELECTABLE_ALPHA;
private static final String TAG = "UserSwitcherController";
private static final boolean DEBUG = false;
@@ -155,7 +162,8 @@
private boolean mSimpleUserSwitcher;
// When false, there won't be any visual affordance to add a new user from the keyguard even if
// the user is unlocked
- private boolean mAddUsersFromLockScreen;
+ private final MutableStateFlow<Boolean> mAddUsersFromLockScreen =
+ StateFlowKt.MutableStateFlow(false);
private boolean mUserSwitcherEnabled;
@VisibleForTesting
boolean mPauseRefreshUsers;
@@ -258,8 +266,11 @@
@Override
public void onChange(boolean selfChange) {
mSimpleUserSwitcher = shouldUseSimpleUserSwitcher();
- mAddUsersFromLockScreen = mGlobalSettings.getIntForUser(
- Settings.Global.ADD_USERS_WHEN_LOCKED, 0, UserHandle.USER_SYSTEM) != 0;
+ mAddUsersFromLockScreen.setValue(
+ mGlobalSettings.getIntForUser(
+ Settings.Global.ADD_USERS_WHEN_LOCKED,
+ 0,
+ UserHandle.USER_SYSTEM) != 0);
mUserSwitcherEnabled = mGlobalSettings.getIntForUser(
Settings.Global.USER_SWITCHER_ENABLED, 0, UserHandle.USER_SYSTEM) != 0;
refreshUsers(UserHandle.USER_NULL);
@@ -323,7 +334,6 @@
}
mForcePictureLoadForUserId.clear();
- final boolean addUsersWhenLocked = mAddUsersFromLockScreen;
mBgExecutor.execute(() -> {
List<UserInfo> infos = mUserManager.getAliveUsers();
if (infos == null) {
@@ -434,7 +444,7 @@
}
boolean anyoneCanCreateUsers() {
- return systemCanCreateUsers() && mAddUsersFromLockScreen;
+ return systemCanCreateUsers() && mAddUsersFromLockScreen.getValue();
}
boolean canCreateGuest(boolean hasExistingGuest) {
@@ -450,7 +460,7 @@
}
boolean createIsRestricted() {
- return !mAddUsersFromLockScreen;
+ return !mAddUsersFromLockScreen.getValue();
}
boolean canCreateSupervisedUser() {
@@ -516,17 +526,48 @@
return null;
}
+ /**
+ * Notifies that a user has been selected.
+ *
+ * <p>This will trigger the right user journeys to create a guest user, switch users, and/or
+ * navigate to the correct destination.
+ *
+ * <p>If a user with the given ID is not found, this method is a no-op.
+ *
+ * @param userId The ID of the user to switch to.
+ * @param dialogShower An optional {@link DialogShower} in case we need to show dialogs.
+ */
+ public void onUserSelected(int userId, @Nullable DialogShower dialogShower) {
+ UserRecord userRecord = mUsers.stream()
+ .filter(x -> x.resolveId() == userId)
+ .findFirst()
+ .orElse(null);
+ if (userRecord == null) {
+ return;
+ }
+
+ onUserListItemClicked(userRecord, dialogShower);
+ }
+
+ /** Whether it is allowed to add users while the device is locked. */
+ public Flow<Boolean> getAddUsersFromLockScreen() {
+ return mAddUsersFromLockScreen;
+ }
+
+ /** Returns {@code true} if the guest user is configured to always be present on the device. */
+ public boolean isGuestUserAutoCreated() {
+ return mGuestUserAutoCreated;
+ }
+
+ /** Returns {@code true} if the guest user is currently being reset. */
+ public boolean isGuestUserResetting() {
+ return mGuestIsResetting.get();
+ }
+
@VisibleForTesting
void onUserListItemClicked(UserRecord record, DialogShower dialogShower) {
if (record.isGuest && record.info == null) {
- // No guest user. Create one.
- createGuestAsync(guestId -> {
- // guestId may be USER_NULL if we haven't reloaded the user list yet.
- if (guestId != UserHandle.USER_NULL) {
- mUiEventLogger.log(QSUserSwitcherEvent.QS_USER_GUEST_ADD);
- onUserListItemClicked(guestId, record, dialogShower);
- }
- });
+ createAndSwitchToGuestUser(dialogShower);
} else if (record.isAddUser) {
showAddUserDialog(dialogShower);
} else if (record.isAddSupervisedUser) {
@@ -604,7 +645,23 @@
}
}
- private void showAddUserDialog(DialogShower dialogShower) {
+ /**
+ * Creates and switches to the guest user.
+ */
+ public void createAndSwitchToGuestUser(@Nullable DialogShower dialogShower) {
+ createGuestAsync(guestId -> {
+ // guestId may be USER_NULL if we haven't reloaded the user list yet.
+ if (guestId != UserHandle.USER_NULL) {
+ mUiEventLogger.log(QSUserSwitcherEvent.QS_USER_GUEST_ADD);
+ onUserListItemClicked(guestId, UserRecord.createForGuest(), dialogShower);
+ }
+ });
+ }
+
+ /**
+ * Shows the add user dialog.
+ */
+ public void showAddUserDialog(@Nullable DialogShower dialogShower) {
if (mAddUserDialog != null && mAddUserDialog.isShowing()) {
mAddUserDialog.cancel();
}
@@ -620,7 +677,10 @@
}
}
- private void startSupervisedUserActivity() {
+ /**
+ * Starts an activity to add a supervised user to the device.
+ */
+ public void startSupervisedUserActivity() {
final Intent intent = new Intent()
.setAction(UserManager.ACTION_CREATE_SUPERVISED_USER)
.setPackage(mCreateSupervisedUserPackage)
@@ -772,7 +832,7 @@
* Removes guest user and switches to target user. The guest must be the current user and its id
* must be {@code guestUserId}.
*
- * <p>If {@code targetUserId} is {@link UserHandle.USER_NULL}, then create a new guest user in
+ * <p>If {@code targetUserId} is {@link UserHandle#USER_NULL}, then create a new guest user in
* the foreground, and immediately switch to it. This is used for wiping the current guest and
* replacing it with a new one.
*
@@ -782,11 +842,11 @@
* <p>If device is configured with {@link
* com.android.internal.R.bool.config_guestUserAutoCreated}, then after guest user is removed, a
* new one is created in the background. This has no effect if {@code targetUserId} is {@link
- * UserHandle.USER_NULL}.
+ * UserHandle#USER_NULL}.
*
* @param guestUserId id of the guest user to remove
* @param targetUserId id of the user to switch to after guest is removed. If {@link
- * UserHandle.USER_NULL}, then switch immediately to the newly created guest user.
+ * UserHandle#USER_NULL}, then switch immediately to the newly created guest user.
*/
public void removeGuestUser(@UserIdInt int guestUserId, @UserIdInt int targetUserId) {
UserInfo currentUser = mUserTracker.getUserInfo();
@@ -839,7 +899,7 @@
* user.
*
* @param guestUserId user id of the guest user to exit
- * @param targetUserId user id of the guest user to exit, set to UserHandle.USER_NULL when
+ * @param targetUserId user id of the guest user to exit, set to UserHandle#USER_NULL when
* target user id is not known
* @param forceRemoveGuestOnExit true: remove guest before switching user,
* false: remove guest only if its ephemeral, else keep guest
@@ -952,7 +1012,7 @@
* {@link UserManager} to create a new one.
*
* @return The multi-user user ID of the newly created guest user, or
- * {@link UserHandle.USER_NULL} if the guest couldn't be created.
+ * {@link UserHandle#USER_NULL} if the guest couldn't be created.
*/
public @UserIdInt int createGuest() {
UserInfo guest;
@@ -1062,38 +1122,11 @@
}
public String getName(Context context, UserRecord item) {
- if (item.isGuest) {
- if (item.isCurrent) {
- return context.getString(
- com.android.settingslib.R.string.guest_exit_quick_settings_button);
- } else {
- if (item.info != null) {
- return context.getString(com.android.internal.R.string.guest_name);
- } else {
- if (mController.mGuestUserAutoCreated) {
- // If mGuestIsResetting=true, we expect the guest user to be created
- // shortly, so display a "Resetting guest..." as an indicator that we
- // are busy. Otherwise, if mGuestIsResetting=false, we probably failed
- // to create a guest at some point. In this case, always show guest
- // nickname instead of "Add guest" to make it seem as though the device
- // always has a guest ready for use.
- return context.getString(
- mController.mGuestIsResetting.get()
- ? com.android.settingslib.R.string.guest_resetting
- : com.android.internal.R.string.guest_name);
- } else {
- // we always show "guest" as string, instead of "add guest"
- return context.getString(com.android.internal.R.string.guest_name);
- }
- }
- }
- } else if (item.isAddUser) {
- return context.getString(com.android.settingslib.R.string.user_add_user);
- } else if (item.isAddSupervisedUser) {
- return context.getString(R.string.add_user_supervised);
- } else {
- return item.info.name;
- }
+ return LegacyUserUiHelper.getUserRecordName(
+ context,
+ item,
+ mController.isGuestUserAutoCreated(),
+ mController.isGuestUserResetting());
}
protected static ColorFilter getDisabledUserAvatarColorFilter() {
@@ -1103,17 +1136,8 @@
}
protected static Drawable getIconDrawable(Context context, UserRecord item) {
- int iconRes;
- if (item.isAddUser) {
- iconRes = R.drawable.ic_add;
- } else if (item.isGuest) {
- iconRes = R.drawable.ic_account_circle;
- } else if (item.isAddSupervisedUser) {
- iconRes = R.drawable.ic_add_supervised_user;
- } else {
- iconRes = R.drawable.ic_avatar_user;
- }
-
+ int iconRes = LegacyUserUiHelper.getUserSwitcherActionIconResourceId(
+ item.isAddUser, item.isGuest, item.isAddSupervisedUser);
return context.getDrawable(iconRes);
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt
similarity index 64%
rename from packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt
rename to packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt
index 3a0ac1b..734eeec 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt
+++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.media.taptotransfer.common
+package com.android.systemui.temporarydisplay
import android.annotation.LayoutRes
import android.annotation.SuppressLint
@@ -37,30 +37,30 @@
import com.android.settingslib.Utils
import com.android.systemui.R
import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.media.taptotransfer.common.MediaTttLogger
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.util.concurrency.DelayableExecutor
-import com.android.systemui.util.view.ViewUtil
/**
- * A superclass controller that provides common functionality for showing chips on the sender device
- * and the receiver device.
+ * A generic controller that can temporarily display a new view in a new window.
*
- * Subclasses need to override and implement [updateChipView], which is where they can control what
+ * Subclasses need to override and implement [updateView], which is where they can control what
* gets displayed to the user.
*
* The generic type T is expected to contain all the information necessary for the subclasses to
- * display the chip in a certain state, since they receive <T> in [updateChipView].
+ * display the view in a certain state, since they receive <T> in [updateView].
+ *
+ * TODO(b/245610654): Remove all the media-specific logic from this class.
*/
-abstract class MediaTttChipControllerCommon<T : ChipInfoCommon>(
- internal val context: Context,
- internal val logger: MediaTttLogger,
- internal val windowManager: WindowManager,
- private val viewUtil: ViewUtil,
- @Main private val mainExecutor: DelayableExecutor,
- private val accessibilityManager: AccessibilityManager,
- private val configurationController: ConfigurationController,
- private val powerManager: PowerManager,
- @LayoutRes private val chipLayoutRes: Int,
+abstract class TemporaryViewDisplayController<T : TemporaryViewInfo>(
+ internal val context: Context,
+ internal val logger: MediaTttLogger,
+ internal val windowManager: WindowManager,
+ @Main private val mainExecutor: DelayableExecutor,
+ private val accessibilityManager: AccessibilityManager,
+ private val configurationController: ConfigurationController,
+ private val powerManager: PowerManager,
+ @LayoutRes private val viewLayoutRes: Int,
) {
/**
* Window layout params that will be used as a starting point for the [windowLayoutParams] of
@@ -85,31 +85,31 @@
*/
internal abstract val windowLayoutParams: WindowManager.LayoutParams
- /** The chip view currently being displayed. Null if the chip is not being displayed. */
- private var chipView: ViewGroup? = null
+ /** The view currently being displayed. Null if the view is not being displayed. */
+ private var view: ViewGroup? = null
- /** The chip info currently being displayed. Null if the chip is not being displayed. */
- internal var chipInfo: T? = null
+ /** The info currently being displayed. Null if the view is not being displayed. */
+ internal var info: T? = null
- /** A [Runnable] that, when run, will cancel the pending timeout of the chip. */
- private var cancelChipViewTimeout: Runnable? = null
+ /** A [Runnable] that, when run, will cancel the pending timeout of the view. */
+ private var cancelViewTimeout: Runnable? = null
/**
- * Displays the chip with the provided [newChipInfo].
+ * Displays the view with the provided [newInfo].
*
- * This method handles inflating and attaching the view, then delegates to [updateChipView] to
- * display the correct information in the chip.
+ * This method handles inflating and attaching the view, then delegates to [updateView] to
+ * display the correct information in the view.
*/
- fun displayChip(newChipInfo: T) {
- val currentChipView = chipView
+ fun displayView(newInfo: T) {
+ val currentView = view
- if (currentChipView != null) {
- updateChipView(newChipInfo, currentChipView)
+ if (currentView != null) {
+ updateView(newInfo, currentView)
} else {
- // The chip is new, so set up all our callbacks and inflate the view
+ // The view is new, so set up all our callbacks and inflate the view
configurationController.addCallback(displayScaleListener)
- // Wake the screen if necessary so the user will see the chip. (Per b/239426653, we want
- // the chip to show over the dream state, so we should only wake up if the screen is
+ // Wake the screen if necessary so the user will see the view. (Per b/239426653, we want
+ // the view to show over the dream state, so we should only wake up if the screen is
// completely off.)
if (!powerManager.isScreenOn) {
powerManager.wakeUp(
@@ -119,79 +119,79 @@
)
}
- inflateAndUpdateChip(newChipInfo)
+ inflateAndUpdateView(newInfo)
}
- // Cancel and re-set the chip timeout each time we get a new state.
+ // Cancel and re-set the view timeout each time we get a new state.
val timeout = accessibilityManager.getRecommendedTimeoutMillis(
- newChipInfo.getTimeoutMs().toInt(),
- // Not all chips have controls so FLAG_CONTENT_CONTROLS might be superfluous, but
+ newInfo.getTimeoutMs().toInt(),
+ // Not all views have controls so FLAG_CONTENT_CONTROLS might be superfluous, but
// include it just to be safe.
FLAG_CONTENT_ICONS or FLAG_CONTENT_TEXT or FLAG_CONTENT_CONTROLS
)
- cancelChipViewTimeout?.run()
- cancelChipViewTimeout = mainExecutor.executeDelayed(
- { removeChip(MediaTttRemovalReason.REASON_TIMEOUT) },
+ cancelViewTimeout?.run()
+ cancelViewTimeout = mainExecutor.executeDelayed(
+ { removeView(TemporaryDisplayRemovalReason.REASON_TIMEOUT) },
timeout.toLong()
)
}
- /** Inflates a new chip view, updates it with [newChipInfo], and adds the view to the window. */
- private fun inflateAndUpdateChip(newChipInfo: T) {
- val newChipView = LayoutInflater
+ /** Inflates a new view, updates it with [newInfo], and adds the view to the window. */
+ private fun inflateAndUpdateView(newInfo: T) {
+ val newView = LayoutInflater
.from(context)
- .inflate(chipLayoutRes, null) as ViewGroup
- chipView = newChipView
- updateChipView(newChipInfo, newChipView)
- windowManager.addView(newChipView, windowLayoutParams)
- animateChipIn(newChipView)
+ .inflate(viewLayoutRes, null) as ViewGroup
+ view = newView
+ updateView(newInfo, newView)
+ windowManager.addView(newView, windowLayoutParams)
+ animateViewIn(newView)
}
- /** Removes then re-inflates the chip. */
- private fun reinflateChip() {
- val currentChipInfo = chipInfo
- if (chipView == null || currentChipInfo == null) { return }
+ /** Removes then re-inflates the view. */
+ private fun reinflateView() {
+ val currentInfo = info
+ if (view == null || currentInfo == null) { return }
- windowManager.removeView(chipView)
- inflateAndUpdateChip(currentChipInfo)
+ windowManager.removeView(view)
+ inflateAndUpdateView(currentInfo)
}
private val displayScaleListener = object : ConfigurationController.ConfigurationListener {
override fun onDensityOrFontScaleChanged() {
- reinflateChip()
+ reinflateView()
}
}
/**
- * Hides the chip.
+ * Hides the view.
*
- * @param removalReason a short string describing why the chip was removed (timeout, state
+ * @param removalReason a short string describing why the view was removed (timeout, state
* change, etc.)
*/
- open fun removeChip(removalReason: String) {
- if (chipView == null) { return }
+ open fun removeView(removalReason: String) {
+ if (view == null) { return }
logger.logChipRemoval(removalReason)
configurationController.removeCallback(displayScaleListener)
- windowManager.removeView(chipView)
- chipView = null
- chipInfo = null
- // No need to time the chip out since it's already gone
- cancelChipViewTimeout?.run()
+ windowManager.removeView(view)
+ view = null
+ info = null
+ // No need to time the view out since it's already gone
+ cancelViewTimeout?.run()
}
/**
- * A method implemented by subclasses to update [currentChipView] based on [newChipInfo].
+ * A method implemented by subclasses to update [currentView] based on [newInfo].
*/
@CallSuper
- open fun updateChipView(newChipInfo: T, currentChipView: ViewGroup) {
- chipInfo = newChipInfo
+ open fun updateView(newInfo: T, currentView: ViewGroup) {
+ info = newInfo
}
/**
- * A method that can be implemented by subclcasses to do custom animations for when the chip
+ * A method that can be implemented by subclasses to do custom animations for when the view
* appears.
*/
- open fun animateChipIn(chipView: ViewGroup) {}
+ open fun animateViewIn(view: ViewGroup) {}
/**
* Returns the size that the icon should be, or null if no size override is needed.
@@ -209,12 +209,12 @@
* @return the content description of the icon.
*/
internal fun setIcon(
- currentChipView: ViewGroup,
+ currentView: ViewGroup,
appPackageName: String?,
appIconDrawableOverride: Drawable? = null,
appNameOverride: CharSequence? = null,
): CharSequence {
- val appIconView = currentChipView.requireViewById<CachingIconView>(R.id.app_icon)
+ val appIconView = currentView.requireViewById<CachingIconView>(R.id.app_icon)
val iconInfo = getIconInfo(appPackageName)
getIconSize(iconInfo.isAppIcon)?.let { size ->
@@ -264,9 +264,9 @@
// Used in CTS tests UpdateMediaTapToTransferSenderDisplayTest and
// UpdateMediaTapToTransferReceiverDisplayTest
private const val WINDOW_TITLE = "Media Transfer Chip View"
-private val TAG = MediaTttChipControllerCommon::class.simpleName!!
+private val TAG = TemporaryViewDisplayController::class.simpleName!!
-object MediaTttRemovalReason {
+object TemporaryDisplayRemovalReason {
const val REASON_TIMEOUT = "TIMEOUT"
const val REASON_SCREEN_TAP = "SCREEN_TAP"
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/ChipInfoCommon.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewInfo.kt
similarity index 73%
rename from packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/ChipInfoCommon.kt
rename to packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewInfo.kt
index a29c588..4fe753a 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/ChipInfoCommon.kt
+++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewInfo.kt
@@ -14,17 +14,17 @@
* limitations under the License.
*/
-package com.android.systemui.media.taptotransfer.common
+package com.android.systemui.temporarydisplay
/**
- * A superclass chip state that will be subclassed by the sender chip and receiver chip.
+ * A superclass view state used with [TemporaryViewDisplayController].
*/
-interface ChipInfoCommon {
+interface TemporaryViewInfo {
/**
- * Returns the amount of time the given chip state should display on the screen before it times
+ * Returns the amount of time the given view state should display on the screen before it times
* out and disappears.
*/
- fun getTimeoutMs(): Long
+ fun getTimeoutMs(): Long = DEFAULT_TIMEOUT_MILLIS
}
const val DEFAULT_TIMEOUT_MILLIS = 10000L
diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java
index abffe555..27746c0 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java
@@ -56,13 +56,11 @@
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationLockscreenUserManagerImpl;
import com.android.systemui.statusbar.NotificationShadeWindowController;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider;
import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
import com.android.systemui.statusbar.phone.DozeServiceHost;
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
-import com.android.systemui.statusbar.phone.KeyguardEnvironmentImpl;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
import com.android.systemui.statusbar.policy.BatteryController;
@@ -152,10 +150,6 @@
abstract DockManager bindDockManager(DockManagerImpl dockManager);
@Binds
- abstract NotificationEntryManager.KeyguardEnvironment bindKeyguardEnvironment(
- KeyguardEnvironmentImpl keyguardEnvironment);
-
- @Binds
abstract ShadeController provideShadeController(ShadeControllerImpl shadeController);
@SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/unfold/FoldAodAnimationController.kt b/packages/SystemUI/src/com/android/systemui/unfold/FoldAodAnimationController.kt
index 8f127fd..0f06144 100644
--- a/packages/SystemUI/src/com/android/systemui/unfold/FoldAodAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/unfold/FoldAodAnimationController.kt
@@ -18,22 +18,31 @@
import android.content.Context
import android.hardware.devicestate.DeviceStateManager
-import android.os.Handler
import android.os.PowerManager
import android.provider.Settings
+import androidx.annotation.VisibleForTesting
import androidx.core.view.OneShotPreDrawListener
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.repeatOnLifecycle
import com.android.internal.util.LatencyTracker
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.keyguard.WakefulnessLifecycle
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
+import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.statusbar.LightRevealScrim
import com.android.systemui.statusbar.phone.CentralSurfaces
import com.android.systemui.statusbar.phone.ScreenOffAnimation
import com.android.systemui.statusbar.policy.CallbackController
import com.android.systemui.unfold.FoldAodAnimationController.FoldAodAnimationStatus
+import com.android.systemui.util.concurrency.DelayableExecutor
import com.android.systemui.util.settings.GlobalSettings
-import java.util.concurrent.Executor
+import dagger.Lazy
import java.util.function.Consumer
import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.flow.collect
+import kotlinx.coroutines.launch
/**
* Controls folding to AOD animation: when AOD is enabled and foldable device is folded we play a
@@ -43,16 +52,16 @@
class FoldAodAnimationController
@Inject
constructor(
- @Main private val handler: Handler,
- @Main private val executor: Executor,
+ @Main private val executor: DelayableExecutor,
private val context: Context,
private val deviceStateManager: DeviceStateManager,
private val wakefulnessLifecycle: WakefulnessLifecycle,
private val globalSettings: GlobalSettings,
private val latencyTracker: LatencyTracker,
+ private val keyguardInteractor: Lazy<KeyguardInteractor>,
) : CallbackController<FoldAodAnimationStatus>, ScreenOffAnimation, WakefulnessLifecycle.Observer {
- private lateinit var mCentralSurfaces: CentralSurfaces
+ private lateinit var centralSurfaces: CentralSurfaces
private var isFolded = false
private var isFoldHandled = true
@@ -64,12 +73,13 @@
private var shouldPlayAnimation = false
private var isAnimationPlaying = false
+ private var cancelAnimation: Runnable? = null
private val statusListeners = arrayListOf<FoldAodAnimationStatus>()
private val foldToAodLatencyTracker = FoldToAodLatencyTracker()
private val startAnimationRunnable = Runnable {
- mCentralSurfaces.notificationPanelViewController.startFoldToAodAnimation(
+ centralSurfaces.notificationPanelViewController.startFoldToAodAnimation(
/* startAction= */ { foldToAodLatencyTracker.onAnimationStarted() },
/* endAction= */ { setAnimationState(playing = false) },
/* cancelAction= */ { setAnimationState(playing = false) },
@@ -77,10 +87,14 @@
}
override fun initialize(centralSurfaces: CentralSurfaces, lightRevealScrim: LightRevealScrim) {
- this.mCentralSurfaces = centralSurfaces
+ this.centralSurfaces = centralSurfaces
deviceStateManager.registerCallback(executor, FoldListener())
wakefulnessLifecycle.addObserver(this)
+
+ centralSurfaces.notificationPanelViewController.view.repeatWhenAttached {
+ repeatOnLifecycle(Lifecycle.State.STARTED) { listenForDozing(this) }
+ }
}
/** Returns true if we should run fold to AOD animation */
@@ -94,7 +108,7 @@
override fun startAnimation(): Boolean =
if (shouldStartAnimation()) {
setAnimationState(playing = true)
- mCentralSurfaces.notificationPanelViewController.prepareFoldToAodAnimation()
+ centralSurfaces.notificationPanelViewController.prepareFoldToAodAnimation()
true
} else {
setAnimationState(playing = false)
@@ -104,8 +118,8 @@
override fun onStartedWakingUp() {
if (isAnimationPlaying) {
foldToAodLatencyTracker.cancel()
- handler.removeCallbacks(startAnimationRunnable)
- mCentralSurfaces.notificationPanelViewController.cancelFoldToAodAnimation()
+ cancelAnimation?.run()
+ centralSurfaces.notificationPanelViewController.cancelFoldToAodAnimation()
}
setAnimationState(playing = false)
@@ -138,13 +152,13 @@
// We should play the folding to AOD animation
setAnimationState(playing = true)
- mCentralSurfaces.notificationPanelViewController.prepareFoldToAodAnimation()
+ centralSurfaces.notificationPanelViewController.prepareFoldToAodAnimation()
// We don't need to wait for the scrim as it is already displayed
// but we should wait for the initial animation preparations to be drawn
// (setting initial alpha/translation)
OneShotPreDrawListener.add(
- mCentralSurfaces.notificationPanelViewController.view,
+ centralSurfaces.notificationPanelViewController.view,
onReady
)
} else {
@@ -165,18 +179,14 @@
fun onScreenTurnedOn() {
if (shouldPlayAnimation) {
- handler.removeCallbacks(startAnimationRunnable)
+ cancelAnimation?.run()
// Post starting the animation to the next frame to avoid junk due to inset changes
- handler.post(startAnimationRunnable)
+ cancelAnimation = executor.executeDelayed(startAnimationRunnable, /* delayMillis= */ 0)
shouldPlayAnimation = false
}
}
- fun setIsDozing(dozing: Boolean) {
- isDozing = dozing
- }
-
override fun isAnimationPlaying(): Boolean = isAnimationPlaying
override fun isKeyguardHideDelayed(): Boolean = isAnimationPlaying()
@@ -204,6 +214,11 @@
statusListeners.remove(listener)
}
+ @VisibleForTesting
+ internal suspend fun listenForDozing(scope: CoroutineScope): Job {
+ return scope.launch { keyguardInteractor.get().isDozing.collect { isDozing = it } }
+ }
+
interface FoldAodAnimationStatus {
fun onFoldToAodAnimationChanged()
}
diff --git a/packages/SystemUI/src/com/android/systemui/user/UserModule.java b/packages/SystemUI/src/com/android/systemui/user/UserModule.java
index 469d54f..5b522dc 100644
--- a/packages/SystemUI/src/com/android/systemui/user/UserModule.java
+++ b/packages/SystemUI/src/com/android/systemui/user/UserModule.java
@@ -19,6 +19,7 @@
import android.app.Activity;
import com.android.settingslib.users.EditUserInfoController;
+import com.android.systemui.user.data.repository.UserRepositoryModule;
import dagger.Binds;
import dagger.Module;
@@ -29,7 +30,11 @@
/**
* Dagger module for User related classes.
*/
-@Module
+@Module(
+ includes = {
+ UserRepositoryModule.class,
+ }
+)
public abstract class UserModule {
private static final String FILE_PROVIDER_AUTHORITY = "com.android.systemui.fileprovider";
diff --git a/packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt b/packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt
index ff0f0d4..d43f739 100644
--- a/packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt
@@ -27,6 +27,7 @@
import android.os.Bundle
import android.os.UserManager
import android.provider.Settings
+import android.util.Log
import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.View
@@ -35,8 +36,11 @@
import android.widget.ArrayAdapter
import android.widget.ImageView
import android.widget.TextView
+import android.window.OnBackInvokedCallback
+import android.window.OnBackInvokedDispatcher
import androidx.activity.ComponentActivity
import androidx.constraintlayout.helper.widget.Flow
+import androidx.lifecycle.ViewModelProvider
import com.android.internal.annotations.VisibleForTesting
import com.android.internal.util.UserIcons
import com.android.settingslib.Utils
@@ -44,6 +48,8 @@
import com.android.systemui.R
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.classifier.FalsingCollector
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.plugins.FalsingManager.LOW_PENALTY
import com.android.systemui.settings.UserTracker
@@ -52,6 +58,9 @@
import com.android.systemui.statusbar.policy.UserSwitcherController.USER_SWITCH_DISABLED_ALPHA
import com.android.systemui.statusbar.policy.UserSwitcherController.USER_SWITCH_ENABLED_ALPHA
import com.android.systemui.user.data.source.UserRecord
+import com.android.systemui.user.ui.binder.UserSwitcherViewBinder
+import com.android.systemui.user.ui.viewmodel.UserSwitcherViewModel
+import dagger.Lazy
import javax.inject.Inject
import kotlin.math.ceil
@@ -60,14 +69,15 @@
/**
* Support a fullscreen user switcher
*/
-class UserSwitcherActivity @Inject constructor(
+open class UserSwitcherActivity @Inject constructor(
private val userSwitcherController: UserSwitcherController,
private val broadcastDispatcher: BroadcastDispatcher,
- private val layoutInflater: LayoutInflater,
private val falsingCollector: FalsingCollector,
private val falsingManager: FalsingManager,
private val userManager: UserManager,
- private val userTracker: UserTracker
+ private val userTracker: UserTracker,
+ private val flags: FeatureFlags,
+ private val viewModelFactory: Lazy<UserSwitcherViewModel.Factory>,
) : ComponentActivity() {
private lateinit var parent: UserSwitcherRootView
@@ -75,6 +85,7 @@
private var popupMenu: UserSwitcherPopupMenu? = null
private lateinit var addButton: View
private var addUserRecords = mutableListOf<UserRecord>()
+ private val onBackCallback = OnBackInvokedCallback { finish() }
private val userSwitchedCallback: UserTracker.Callback = object : UserTracker.Callback {
override fun onUserChanged(newUser: Int, userContext: Context) {
finish()
@@ -93,119 +104,35 @@
false /* isAddSupervisedUser */
)
- private val adapter = object : BaseUserAdapter(userSwitcherController) {
- override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
- val item = getItem(position)
- var view = convertView as ViewGroup?
- if (view == null) {
- view = layoutInflater.inflate(
- R.layout.user_switcher_fullscreen_item,
- parent,
- false
- ) as ViewGroup
- }
- (view.getChildAt(0) as ImageView).apply {
- setImageDrawable(getDrawable(item))
- }
- (view.getChildAt(1) as TextView).apply {
- setText(getName(getContext(), item))
- }
-
- view.setEnabled(item.isSwitchToEnabled)
- view.setAlpha(
- if (view.isEnabled()) {
- USER_SWITCH_ENABLED_ALPHA
- } else {
- USER_SWITCH_DISABLED_ALPHA
- }
- )
- view.setTag(USER_VIEW)
- return view
- }
-
- override fun getName(context: Context, item: UserRecord): String {
- return if (item == manageUserRecord) {
- getString(R.string.manage_users)
- } else {
- super.getName(context, item)
- }
- }
-
- fun findUserIcon(item: UserRecord): Drawable {
- if (item == manageUserRecord) {
- return getDrawable(R.drawable.ic_manage_users)
- }
- if (item.info == null) {
- return getIconDrawable(this@UserSwitcherActivity, item)
- }
- val userIcon = userManager.getUserIcon(item.info.id)
- if (userIcon != null) {
- return BitmapDrawable(userIcon)
- }
- return UserIcons.getDefaultUserIcon(resources, item.info.id, false)
- }
-
- fun getTotalUserViews(): Int {
- return users.count { item ->
- !doNotRenderUserView(item)
- }
- }
-
- fun doNotRenderUserView(item: UserRecord): Boolean {
- return item.isAddUser ||
- item.isAddSupervisedUser ||
- item.isGuest && item.info == null
- }
-
- private fun getDrawable(item: UserRecord): Drawable {
- var drawable = if (item.isGuest) {
- getDrawable(R.drawable.ic_account_circle)
- } else {
- findUserIcon(item)
- }
- drawable.mutate()
-
- if (!item.isCurrent && !item.isSwitchToEnabled) {
- drawable.setTint(
- resources.getColor(
- R.color.kg_user_switcher_restricted_avatar_icon_color,
- getTheme()
- )
- )
- }
-
- val ld = getDrawable(R.drawable.user_switcher_icon_large).mutate()
- as LayerDrawable
- if (item == userSwitcherController.getCurrentUserRecord()) {
- (ld.findDrawableByLayerId(R.id.ring) as GradientDrawable).apply {
- val stroke = resources
- .getDimensionPixelSize(R.dimen.user_switcher_icon_selected_width)
- val color = Utils.getColorAttrDefaultColor(
- this@UserSwitcherActivity,
- com.android.internal.R.attr.colorAccentPrimary
- )
-
- setStroke(stroke, color)
- }
- }
-
- ld.setDrawableByLayerId(R.id.user_avatar, drawable)
- return ld
- }
-
- override fun notifyDataSetChanged() {
- super.notifyDataSetChanged()
- buildUserViews()
- }
- }
+ private val adapter: UserAdapter by lazy { UserAdapter() }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
+ createActivity()
+ }
+ @VisibleForTesting
+ fun createActivity() {
setContentView(R.layout.user_switcher_fullscreen)
- window.decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
- or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
- or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION)
+ window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+ or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+ or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION)
+ if (isUsingModernArchitecture()) {
+ Log.d(TAG, "Using modern architecture.")
+ val viewModel = ViewModelProvider(
+ this, viewModelFactory.get())[UserSwitcherViewModel::class.java]
+ UserSwitcherViewBinder.bind(
+ view = requireViewById(R.id.user_switcher_root),
+ viewModel = viewModel,
+ lifecycleOwner = this,
+ layoutInflater = layoutInflater,
+ falsingCollector = falsingCollector,
+ onFinish = this::finish,
+ )
+ return
+ } else {
+ Log.d(TAG, "Not using modern architecture.")
+ }
parent = requireViewById<UserSwitcherRootView>(R.id.user_switcher_root)
@@ -228,6 +155,9 @@
}
}
+ onBackInvokedDispatcher.registerOnBackInvokedCallback(
+ OnBackInvokedDispatcher.PRIORITY_DEFAULT, onBackCallback)
+
userSwitcherController.init(parent)
initBroadcastReceiver()
@@ -346,12 +276,24 @@
}
override fun onBackPressed() {
+ if (isUsingModernArchitecture()) {
+ return super.onBackPressed()
+ }
+
finish()
}
override fun onDestroy() {
super.onDestroy()
+ if (isUsingModernArchitecture()) {
+ return
+ }
+ destroyActivity()
+ }
+ @VisibleForTesting
+ fun destroyActivity() {
+ onBackInvokedDispatcher.unregisterOnBackInvokedCallback(onBackCallback)
broadcastDispatcher.unregisterReceiver(broadcastReceiver)
userTracker.removeCallback(userSwitchedCallback)
}
@@ -376,6 +318,10 @@
return if (userCount < 5) 4 else ceil(userCount / 2.0).toInt()
}
+ private fun isUsingModernArchitecture(): Boolean {
+ return flags.isEnabled(Flags.MODERN_USER_SWITCHER_ACTIVITY)
+ }
+
private class ItemAdapter(
val parentContext: Context,
val resource: Int,
@@ -398,4 +344,114 @@
return view
}
}
+
+ private inner class UserAdapter : BaseUserAdapter(userSwitcherController) {
+ override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
+ val item = getItem(position)
+ var view = convertView as ViewGroup?
+ if (view == null) {
+ view = layoutInflater.inflate(
+ R.layout.user_switcher_fullscreen_item,
+ parent,
+ false
+ ) as ViewGroup
+ }
+ (view.getChildAt(0) as ImageView).apply {
+ setImageDrawable(getDrawable(item))
+ }
+ (view.getChildAt(1) as TextView).apply {
+ setText(getName(getContext(), item))
+ }
+
+ view.setEnabled(item.isSwitchToEnabled)
+ view.setAlpha(
+ if (view.isEnabled()) {
+ USER_SWITCH_ENABLED_ALPHA
+ } else {
+ USER_SWITCH_DISABLED_ALPHA
+ }
+ )
+ view.setTag(USER_VIEW)
+ return view
+ }
+
+ override fun getName(context: Context, item: UserRecord): String {
+ return if (item == manageUserRecord) {
+ getString(R.string.manage_users)
+ } else {
+ super.getName(context, item)
+ }
+ }
+
+ fun findUserIcon(item: UserRecord): Drawable {
+ if (item == manageUserRecord) {
+ return getDrawable(R.drawable.ic_manage_users)
+ }
+ if (item.info == null) {
+ return getIconDrawable(this@UserSwitcherActivity, item)
+ }
+ val userIcon = userManager.getUserIcon(item.info.id)
+ if (userIcon != null) {
+ return BitmapDrawable(userIcon)
+ }
+ return UserIcons.getDefaultUserIcon(resources, item.info.id, false)
+ }
+
+ fun getTotalUserViews(): Int {
+ return users.count { item ->
+ !doNotRenderUserView(item)
+ }
+ }
+
+ fun doNotRenderUserView(item: UserRecord): Boolean {
+ return item.isAddUser ||
+ item.isAddSupervisedUser ||
+ item.isGuest && item.info == null
+ }
+
+ private fun getDrawable(item: UserRecord): Drawable {
+ var drawable = if (item.isGuest) {
+ getDrawable(R.drawable.ic_account_circle)
+ } else {
+ findUserIcon(item)
+ }
+ drawable.mutate()
+
+ if (!item.isCurrent && !item.isSwitchToEnabled) {
+ drawable.setTint(
+ resources.getColor(
+ R.color.kg_user_switcher_restricted_avatar_icon_color,
+ getTheme()
+ )
+ )
+ }
+
+ val ld = getDrawable(R.drawable.user_switcher_icon_large).mutate()
+ as LayerDrawable
+ if (item == userSwitcherController.getCurrentUserRecord()) {
+ (ld.findDrawableByLayerId(R.id.ring) as GradientDrawable).apply {
+ val stroke = resources
+ .getDimensionPixelSize(R.dimen.user_switcher_icon_selected_width)
+ val color = Utils.getColorAttrDefaultColor(
+ this@UserSwitcherActivity,
+ com.android.internal.R.attr.colorAccentPrimary
+ )
+
+ setStroke(stroke, color)
+ }
+ }
+
+ ld.setDrawableByLayerId(R.id.user_avatar, drawable)
+ return ld
+ }
+
+ override fun notifyDataSetChanged() {
+ super.notifyDataSetChanged()
+ buildUserViews()
+ }
+ }
+
+ companion object {
+ private const val TAG = "UserSwitcherActivity"
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt b/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt
new file mode 100644
index 0000000..305b5ee
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt
@@ -0,0 +1,166 @@
+/*
+ * 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.user.data.repository
+
+import android.content.Context
+import android.graphics.drawable.BitmapDrawable
+import android.graphics.drawable.Drawable
+import android.os.UserManager
+import androidx.appcompat.content.res.AppCompatResources
+import com.android.internal.util.UserIcons
+import com.android.systemui.R
+import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
+import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
+import com.android.systemui.common.shared.model.Text
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.statusbar.policy.UserSwitcherController
+import com.android.systemui.user.data.source.UserRecord
+import com.android.systemui.user.legacyhelper.ui.LegacyUserUiHelper
+import com.android.systemui.user.shared.model.UserActionModel
+import com.android.systemui.user.shared.model.UserModel
+import javax.inject.Inject
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.map
+
+/**
+ * Acts as source of truth for user related data.
+ *
+ * Abstracts-away data sources and their schemas so the rest of the app doesn't need to worry about
+ * upstream changes.
+ */
+interface UserRepository {
+ /** List of all users on the device. */
+ val users: Flow<List<UserModel>>
+
+ /** The currently-selected user. */
+ val selectedUser: Flow<UserModel>
+
+ /** List of available user-related actions. */
+ val actions: Flow<List<UserActionModel>>
+
+ /** Whether actions are available even when locked. */
+ val isActionableWhenLocked: Flow<Boolean>
+
+ /** Whether the device is configured to always have a guest user available. */
+ val isGuestUserAutoCreated: Boolean
+
+ /** Whether the guest user is currently being reset. */
+ val isGuestUserResetting: Boolean
+}
+
+@SysUISingleton
+class UserRepositoryImpl
+@Inject
+constructor(
+ @Application private val appContext: Context,
+ private val manager: UserManager,
+ controller: UserSwitcherController,
+) : UserRepository {
+
+ private val userRecords: Flow<List<UserRecord>> = conflatedCallbackFlow {
+ fun send() {
+ trySendWithFailureLogging(
+ controller.users,
+ TAG,
+ )
+ }
+
+ val callback = UserSwitcherController.UserSwitchCallback { send() }
+
+ controller.addUserSwitchCallback(callback)
+ send()
+
+ awaitClose { controller.removeUserSwitchCallback(callback) }
+ }
+
+ override val users: Flow<List<UserModel>> =
+ userRecords.map { records -> records.filter { it.isUser() }.map { it.toUserModel() } }
+
+ override val selectedUser: Flow<UserModel> =
+ users.map { users -> users.first { user -> user.isSelected } }
+
+ override val actions: Flow<List<UserActionModel>> =
+ userRecords.map { records -> records.filter { it.isNotUser() }.map { it.toActionModel() } }
+
+ override val isActionableWhenLocked: Flow<Boolean> = controller.addUsersFromLockScreen
+
+ override val isGuestUserAutoCreated: Boolean = controller.isGuestUserAutoCreated
+
+ override val isGuestUserResetting: Boolean = controller.isGuestUserResetting
+
+ private fun UserRecord.isUser(): Boolean {
+ return when {
+ isAddUser -> false
+ isAddSupervisedUser -> false
+ isGuest -> info != null
+ else -> true
+ }
+ }
+
+ private fun UserRecord.isNotUser(): Boolean {
+ return !isUser()
+ }
+
+ private fun UserRecord.toUserModel(): UserModel {
+ return UserModel(
+ id = resolveId(),
+ name = getUserName(this),
+ image = getUserImage(this),
+ isSelected = isCurrent,
+ isSelectable = isSwitchToEnabled || isGuest,
+ )
+ }
+
+ private fun UserRecord.toActionModel(): UserActionModel {
+ return when {
+ isAddUser -> UserActionModel.ADD_USER
+ isAddSupervisedUser -> UserActionModel.ADD_SUPERVISED_USER
+ isGuest -> UserActionModel.ENTER_GUEST_MODE
+ else -> error("Don't know how to convert to UserActionModel: $this")
+ }
+ }
+
+ private fun getUserName(record: UserRecord): Text {
+ val resourceId: Int? = LegacyUserUiHelper.getGuestUserRecordNameResourceId(record)
+ return if (resourceId != null) {
+ Text.Resource(resourceId)
+ } else {
+ Text.Loaded(checkNotNull(record.info).name)
+ }
+ }
+
+ private fun getUserImage(record: UserRecord): Drawable {
+ if (record.isGuest) {
+ return checkNotNull(
+ AppCompatResources.getDrawable(appContext, R.drawable.ic_account_circle)
+ )
+ }
+
+ val userId = checkNotNull(record.info?.id)
+ return manager.getUserIcon(userId)?.let { userSelectedIcon ->
+ BitmapDrawable(userSelectedIcon)
+ }
+ ?: UserIcons.getDefaultUserIcon(appContext.resources, userId, /* light= */ false)
+ }
+
+ companion object {
+ private const val TAG = "UserRepository"
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeConstants.java b/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepositoryModule.kt
similarity index 61%
copy from libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeConstants.java
copy to packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepositoryModule.kt
index e62a63a..18ae107 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeConstants.java
+++ b/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepositoryModule.kt
@@ -12,20 +12,15 @@
* WITHOUT 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.desktopmode;
+package com.android.systemui.user.data.repository
-import android.os.SystemProperties;
+import dagger.Binds
+import dagger.Module
-/**
- * Constants for desktop mode feature
- */
-public class DesktopModeConstants {
-
- /**
- * Flag to indicate whether desktop mode is available on the device
- */
- public static final boolean IS_FEATURE_ENABLED = SystemProperties.getBoolean(
- "persist.wm.debug.desktop_mode", false);
+@Module
+interface UserRepositoryModule {
+ @Binds fun bindRepository(impl: UserRepositoryImpl): UserRepository
}
diff --git a/packages/SystemUI/src/com/android/systemui/user/data/source/UserRecord.kt b/packages/SystemUI/src/com/android/systemui/user/data/source/UserRecord.kt
index 6ab6d7d..cf6da9a 100644
--- a/packages/SystemUI/src/com/android/systemui/user/data/source/UserRecord.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/data/source/UserRecord.kt
@@ -20,38 +20,29 @@
import android.graphics.Bitmap
import android.os.UserHandle
-/**
- * Encapsulates raw data for a user or an option item related to managing users on the device.
- */
+/** Encapsulates raw data for a user or an option item related to managing users on the device. */
data class UserRecord(
/** Relevant user information. If `null`, this record is not a user but an option item. */
- @JvmField
- val info: UserInfo?,
+ @JvmField val info: UserInfo? = null,
/** An image representing the user. */
- @JvmField
- val picture: Bitmap?,
+ @JvmField val picture: Bitmap? = null,
/** Whether this record represents an option to switch to a guest user. */
- @JvmField
- val isGuest: Boolean,
+ @JvmField val isGuest: Boolean = false,
/** Whether this record represents the currently-selected user. */
- @JvmField
- val isCurrent: Boolean,
+ @JvmField val isCurrent: Boolean = false,
/** Whether this record represents an option to add another user to the device. */
- @JvmField
- val isAddUser: Boolean,
- /** If true, the record is only visible to the owner and only when unlocked. */
- @JvmField
- val isRestricted: Boolean,
- /** Whether it is possible to switch to this user. */
- @JvmField
- val isSwitchToEnabled: Boolean,
- /** Whether this record represents an option to add another supervised user to the device. */
- @JvmField
- val isAddSupervisedUser: Boolean,
-) {
+ @JvmField val isAddUser: Boolean = false,
/**
- * Returns a new instance of [UserRecord] with its [isCurrent] set to the given value.
+ * If true, the record is only available if unlocked or if the user has granted permission to
+ * access this user action whilst on the device is locked.
*/
+ @JvmField val isRestricted: Boolean = false,
+ /** Whether it is possible to switch to this user. */
+ @JvmField val isSwitchToEnabled: Boolean = false,
+ /** Whether this record represents an option to add another supervised user to the device. */
+ @JvmField val isAddSupervisedUser: Boolean = false,
+) {
+ /** Returns a new instance of [UserRecord] with its [isCurrent] set to the given value. */
fun copyWithIsCurrent(isCurrent: Boolean): UserRecord {
return copy(isCurrent = isCurrent)
}
@@ -67,4 +58,11 @@
info.id
}
}
+
+ companion object {
+ @JvmStatic
+ fun createForGuest(): UserRecord {
+ return UserRecord(isGuest = true)
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt
new file mode 100644
index 0000000..3c5b969
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt
@@ -0,0 +1,110 @@
+/*
+ * 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.user.domain.interactor
+
+import android.content.Intent
+import android.provider.Settings
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
+import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.statusbar.policy.UserSwitcherController
+import com.android.systemui.user.data.repository.UserRepository
+import com.android.systemui.user.shared.model.UserActionModel
+import com.android.systemui.user.shared.model.UserModel
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.map
+
+/** Encapsulates business logic to interact with user data and systems. */
+@SysUISingleton
+class UserInteractor
+@Inject
+constructor(
+ repository: UserRepository,
+ private val controller: UserSwitcherController,
+ private val activityStarter: ActivityStarter,
+ keyguardInteractor: KeyguardInteractor,
+) {
+ /** List of current on-device users to select from. */
+ val users: Flow<List<UserModel>> = repository.users
+
+ /** The currently-selected user. */
+ val selectedUser: Flow<UserModel> = repository.selectedUser
+
+ /** List of user-switcher related actions that are available. */
+ val actions: Flow<List<UserActionModel>> =
+ combine(
+ repository.isActionableWhenLocked,
+ keyguardInteractor.isKeyguardShowing,
+ ) { isActionableWhenLocked, isLocked ->
+ isActionableWhenLocked || !isLocked
+ }
+ .flatMapLatest { isActionable ->
+ if (isActionable) {
+ repository.actions.map { actions ->
+ actions +
+ if (actions.isNotEmpty()) {
+ // If we have actions, we add NAVIGATE_TO_USER_MANAGEMENT because
+ // that's a user
+ // switcher specific action that is not known to the our data source
+ // or other
+ // features.
+ listOf(UserActionModel.NAVIGATE_TO_USER_MANAGEMENT)
+ } else {
+ // If no actions, don't add the navigate action.
+ emptyList()
+ }
+ }
+ } else {
+ // If not actionable it means that we're not allowed to show actions when locked
+ // and we
+ // are locked. Therefore, we should show no actions.
+ flowOf(emptyList())
+ }
+ }
+
+ /** Whether the device is configured to always have a guest user available. */
+ val isGuestUserAutoCreated: Boolean = repository.isGuestUserAutoCreated
+
+ /** Whether the guest user is currently being reset. */
+ val isGuestUserResetting: Boolean = repository.isGuestUserResetting
+
+ /** Switches to the user with the given user ID. */
+ fun selectUser(
+ userId: Int,
+ ) {
+ controller.onUserSelected(userId, /* dialogShower= */ null)
+ }
+
+ /** Executes the given action. */
+ fun executeAction(action: UserActionModel) {
+ when (action) {
+ UserActionModel.ENTER_GUEST_MODE -> controller.createAndSwitchToGuestUser(null)
+ UserActionModel.ADD_USER -> controller.showAddUserDialog(null)
+ UserActionModel.ADD_SUPERVISED_USER -> controller.startSupervisedUserActivity()
+ UserActionModel.NAVIGATE_TO_USER_MANAGEMENT ->
+ activityStarter.startActivity(
+ Intent(Settings.ACTION_USER_SETTINGS),
+ /* dismissShade= */ false,
+ )
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/user/legacyhelper/ui/LegacyUserUiHelper.kt b/packages/SystemUI/src/com/android/systemui/user/legacyhelper/ui/LegacyUserUiHelper.kt
new file mode 100644
index 0000000..18369d9
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/user/legacyhelper/ui/LegacyUserUiHelper.kt
@@ -0,0 +1,130 @@
+/*
+ * 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.user.legacyhelper.ui
+
+import android.content.Context
+import androidx.annotation.DrawableRes
+import androidx.annotation.StringRes
+import com.android.systemui.R
+import com.android.systemui.user.data.source.UserRecord
+import kotlin.math.ceil
+
+/**
+ * Defines utility functions for helping with legacy UI code for users.
+ *
+ * We need these to avoid code duplication between logic inside the UserSwitcherController and in
+ * modern architecture classes such as repositories, interactors, and view-models. If we ever
+ * simplify UserSwitcherController (or delete it), the code here could be moved into its call-sites.
+ */
+object LegacyUserUiHelper {
+
+ /** Returns the maximum number of columns for user items in the user switcher. */
+ fun getMaxUserSwitcherItemColumns(userCount: Int): Int {
+ // TODO(b/243844097): remove this once we remove the old user switcher implementation.
+ return if (userCount < 5) {
+ 4
+ } else {
+ ceil(userCount / 2.0).toInt()
+ }
+ }
+
+ @JvmStatic
+ @DrawableRes
+ fun getUserSwitcherActionIconResourceId(
+ isAddUser: Boolean,
+ isGuest: Boolean,
+ isAddSupervisedUser: Boolean,
+ ): Int {
+ return if (isAddUser) {
+ R.drawable.ic_add
+ } else if (isGuest) {
+ R.drawable.ic_account_circle
+ } else if (isAddSupervisedUser) {
+ R.drawable.ic_add_supervised_user
+ } else {
+ R.drawable.ic_avatar_user
+ }
+ }
+
+ @JvmStatic
+ fun getUserRecordName(
+ context: Context,
+ record: UserRecord,
+ isGuestUserAutoCreated: Boolean,
+ isGuestUserResetting: Boolean,
+ ): String {
+ val resourceId: Int? = getGuestUserRecordNameResourceId(record)
+ return when {
+ resourceId != null -> context.getString(resourceId)
+ record.info != null -> record.info.name
+ else ->
+ context.getString(
+ getUserSwitcherActionTextResourceId(
+ isGuest = record.isGuest,
+ isGuestUserAutoCreated = isGuestUserAutoCreated,
+ isGuestUserResetting = isGuestUserResetting,
+ isAddUser = record.isAddUser,
+ isAddSupervisedUser = record.isAddSupervisedUser,
+ )
+ )
+ }
+ }
+
+ /**
+ * Returns the resource ID for a string for the name of the guest user.
+ *
+ * If the given record is not the guest user, returns `null`.
+ */
+ @StringRes
+ fun getGuestUserRecordNameResourceId(record: UserRecord): Int? {
+ return when {
+ record.isGuest && record.isCurrent ->
+ com.android.settingslib.R.string.guest_exit_quick_settings_button
+ record.isGuest && record.info != null -> com.android.internal.R.string.guest_name
+ else -> null
+ }
+ }
+
+ @JvmStatic
+ @StringRes
+ fun getUserSwitcherActionTextResourceId(
+ isGuest: Boolean,
+ isGuestUserAutoCreated: Boolean,
+ isGuestUserResetting: Boolean,
+ isAddUser: Boolean,
+ isAddSupervisedUser: Boolean,
+ ): Int {
+ check(isGuest || isAddUser || isAddSupervisedUser)
+
+ return when {
+ isGuest && isGuestUserAutoCreated && isGuestUserResetting ->
+ com.android.settingslib.R.string.guest_resetting
+ isGuest && isGuestUserAutoCreated -> com.android.internal.R.string.guest_name
+ isGuest -> com.android.internal.R.string.guest_name
+ isAddUser -> com.android.settingslib.R.string.user_add_user
+ isAddSupervisedUser -> R.string.add_user_supervised
+ else -> error("This should never happen!")
+ }
+ }
+
+ /** Alpha value to apply to a user view in the user switcher when it's selectable. */
+ const val USER_SWITCHER_USER_VIEW_SELECTABLE_ALPHA = 1.0f
+
+ /** Alpha value to apply to a user view in the user switcher when it's not selectable. */
+ const val USER_SWITCHER_USER_VIEW_NOT_SELECTABLE_ALPHA = 0.38f
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeConstants.java b/packages/SystemUI/src/com/android/systemui/user/shared/model/UserActionModel.kt
similarity index 61%
copy from libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeConstants.java
copy to packages/SystemUI/src/com/android/systemui/user/shared/model/UserActionModel.kt
index e62a63a..823bf74 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeConstants.java
+++ b/packages/SystemUI/src/com/android/systemui/user/shared/model/UserActionModel.kt
@@ -12,20 +12,14 @@
* WITHOUT 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.desktopmode;
+package com.android.systemui.user.shared.model
-import android.os.SystemProperties;
-
-/**
- * Constants for desktop mode feature
- */
-public class DesktopModeConstants {
-
- /**
- * Flag to indicate whether desktop mode is available on the device
- */
- public static final boolean IS_FEATURE_ENABLED = SystemProperties.getBoolean(
- "persist.wm.debug.desktop_mode", false);
+enum class UserActionModel {
+ ENTER_GUEST_MODE,
+ ADD_USER,
+ ADD_SUPERVISED_USER,
+ NAVIGATE_TO_USER_MANAGEMENT,
}
diff --git a/packages/SystemUI/src/com/android/systemui/user/shared/model/UserModel.kt b/packages/SystemUI/src/com/android/systemui/user/shared/model/UserModel.kt
new file mode 100644
index 0000000..bf7977a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/user/shared/model/UserModel.kt
@@ -0,0 +1,35 @@
+/*
+ * 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.user.shared.model
+
+import android.graphics.drawable.Drawable
+import com.android.systemui.common.shared.model.Text
+
+/** Represents a single user on the device. */
+data class UserModel(
+ /** ID of the user, unique across all users on this device. */
+ val id: Int,
+ /** Human-facing name for this user. */
+ val name: Text,
+ /** Human-facing image for this user. */
+ val image: Drawable,
+ /** Whether this user is the currently-selected user. */
+ val isSelected: Boolean,
+ /** Whether this use is selectable. A non-selectable user cannot be switched to. */
+ val isSelectable: Boolean,
+)
diff --git a/packages/SystemUI/src/com/android/systemui/user/ui/binder/UserSwitcherViewBinder.kt b/packages/SystemUI/src/com/android/systemui/user/ui/binder/UserSwitcherViewBinder.kt
new file mode 100644
index 0000000..83a3d0d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/user/ui/binder/UserSwitcherViewBinder.kt
@@ -0,0 +1,220 @@
+/*
+ * 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.user.ui.binder
+
+import android.content.Context
+import android.view.LayoutInflater
+import android.view.MotionEvent
+import android.view.View
+import android.view.ViewGroup
+import android.widget.BaseAdapter
+import android.widget.ImageView
+import android.widget.TextView
+import androidx.constraintlayout.helper.widget.Flow as FlowWidget
+import androidx.core.view.isVisible
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.LifecycleOwner
+import androidx.lifecycle.lifecycleScope
+import androidx.lifecycle.repeatOnLifecycle
+import com.android.systemui.Gefingerpoken
+import com.android.systemui.R
+import com.android.systemui.classifier.FalsingCollector
+import com.android.systemui.user.UserSwitcherPopupMenu
+import com.android.systemui.user.UserSwitcherRootView
+import com.android.systemui.user.ui.viewmodel.UserActionViewModel
+import com.android.systemui.user.ui.viewmodel.UserSwitcherViewModel
+import com.android.systemui.util.children
+import kotlinx.coroutines.flow.collect
+import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.launch
+
+/** Binds a user switcher to its view-model. */
+object UserSwitcherViewBinder {
+
+ private const val USER_VIEW_TAG = "user_view"
+
+ /** Binds the given view to the given view-model. */
+ fun bind(
+ view: ViewGroup,
+ viewModel: UserSwitcherViewModel,
+ lifecycleOwner: LifecycleOwner,
+ layoutInflater: LayoutInflater,
+ falsingCollector: FalsingCollector,
+ onFinish: () -> Unit,
+ ) {
+ val rootView: UserSwitcherRootView = view.requireViewById(R.id.user_switcher_root)
+ val flowWidget: FlowWidget = view.requireViewById(R.id.flow)
+ val addButton: View = view.requireViewById(R.id.add)
+ val cancelButton: View = view.requireViewById(R.id.cancel)
+ val popupMenuAdapter = MenuAdapter(layoutInflater)
+ var popupMenu: UserSwitcherPopupMenu? = null
+
+ rootView.touchHandler =
+ object : Gefingerpoken {
+ override fun onTouchEvent(ev: MotionEvent?): Boolean {
+ falsingCollector.onTouchEvent(ev)
+ return false
+ }
+ }
+ addButton.setOnClickListener { viewModel.onOpenMenuButtonClicked() }
+ cancelButton.setOnClickListener { viewModel.onCancelButtonClicked() }
+
+ lifecycleOwner.lifecycleScope.launch {
+ lifecycleOwner.repeatOnLifecycle(Lifecycle.State.CREATED) {
+ launch {
+ viewModel.isFinishRequested
+ .filter { it }
+ .collect {
+ onFinish()
+ viewModel.onFinished()
+ }
+ }
+ }
+ }
+
+ lifecycleOwner.lifecycleScope.launch {
+ lifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
+ launch { viewModel.isOpenMenuButtonVisible.collect { addButton.isVisible = it } }
+
+ launch {
+ viewModel.isMenuVisible.collect { isVisible ->
+ if (isVisible && popupMenu?.isShowing != true) {
+ popupMenu?.dismiss()
+ // Use post to make sure we show the popup menu *after* the activity is
+ // ready to show one to avoid a WindowManager$BadTokenException.
+ view.post {
+ popupMenu =
+ createAndShowPopupMenu(
+ context = view.context,
+ anchorView = addButton,
+ adapter = popupMenuAdapter,
+ onDismissed = viewModel::onMenuClosed,
+ )
+ }
+ } else if (!isVisible && popupMenu?.isShowing == true) {
+ popupMenu?.dismiss()
+ popupMenu = null
+ }
+ }
+ }
+
+ launch {
+ viewModel.menu.collect { menuViewModels ->
+ popupMenuAdapter.setItems(menuViewModels)
+ }
+ }
+
+ launch {
+ viewModel.maximumUserColumns.collect { maximumColumns ->
+ flowWidget.setMaxElementsWrap(maximumColumns)
+ }
+ }
+
+ launch {
+ viewModel.users.collect { users ->
+ val viewPool =
+ view.children.filter { it.tag == USER_VIEW_TAG }.toMutableList()
+ viewPool.forEach { view.removeView(it) }
+ users.forEach { userViewModel ->
+ val userView =
+ if (viewPool.isNotEmpty()) {
+ viewPool.removeAt(0)
+ } else {
+ val inflatedView =
+ layoutInflater.inflate(
+ R.layout.user_switcher_fullscreen_item,
+ view,
+ false,
+ )
+ inflatedView.tag = USER_VIEW_TAG
+ inflatedView
+ }
+ userView.id = View.generateViewId()
+ view.addView(userView)
+ flowWidget.addView(userView)
+ UserViewBinder.bind(
+ view = userView,
+ viewModel = userViewModel,
+ )
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private fun createAndShowPopupMenu(
+ context: Context,
+ anchorView: View,
+ adapter: MenuAdapter,
+ onDismissed: () -> Unit,
+ ): UserSwitcherPopupMenu {
+ return UserSwitcherPopupMenu(context).apply {
+ this.anchorView = anchorView
+ setAdapter(adapter)
+ setOnDismissListener { onDismissed() }
+ setOnItemClickListener { _, _, position, _ ->
+ val itemPositionExcludingHeader = position - 1
+ adapter.getItem(itemPositionExcludingHeader).onClicked()
+ }
+
+ show()
+ }
+ }
+
+ /** Adapter for the menu that can be opened. */
+ private class MenuAdapter(
+ private val layoutInflater: LayoutInflater,
+ ) : BaseAdapter() {
+
+ private val items = mutableListOf<UserActionViewModel>()
+
+ override fun getCount(): Int {
+ return items.size
+ }
+
+ override fun getItem(position: Int): UserActionViewModel {
+ return items[position]
+ }
+
+ override fun getItemId(position: Int): Long {
+ return getItem(position).viewKey
+ }
+
+ override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
+ val view =
+ convertView
+ ?: layoutInflater.inflate(
+ R.layout.user_switcher_fullscreen_popup_item,
+ parent,
+ false
+ )
+ val viewModel = getItem(position)
+ view.requireViewById<ImageView>(R.id.icon).setImageResource(viewModel.iconResourceId)
+ view.requireViewById<TextView>(R.id.text).text =
+ view.resources.getString(viewModel.textResourceId)
+ return view
+ }
+
+ fun setItems(items: List<UserActionViewModel>) {
+ this.items.clear()
+ this.items.addAll(items)
+ notifyDataSetChanged()
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/user/ui/binder/UserViewBinder.kt b/packages/SystemUI/src/com/android/systemui/user/ui/binder/UserViewBinder.kt
new file mode 100644
index 0000000..e78807e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/user/ui/binder/UserViewBinder.kt
@@ -0,0 +1,77 @@
+/*
+ * 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.user.ui.binder
+
+import android.content.Context
+import android.graphics.drawable.Drawable
+import android.graphics.drawable.GradientDrawable
+import android.graphics.drawable.LayerDrawable
+import android.view.View
+import android.widget.ImageView
+import androidx.core.content.res.ResourcesCompat
+import com.android.settingslib.Utils
+import com.android.systemui.R
+import com.android.systemui.common.ui.binder.TextViewBinder
+import com.android.systemui.user.ui.viewmodel.UserViewModel
+
+/** Binds a user view to its view-model. */
+object UserViewBinder {
+ /** Binds the given view to the given view-model. */
+ fun bind(view: View, viewModel: UserViewModel) {
+ TextViewBinder.bind(view.requireViewById(R.id.user_switcher_text), viewModel.name)
+ view
+ .requireViewById<ImageView>(R.id.user_switcher_icon)
+ .setImageDrawable(getSelectableDrawable(view.context, viewModel))
+ view.alpha = viewModel.alpha
+ if (viewModel.onClicked != null) {
+ view.setOnClickListener { viewModel.onClicked.invoke() }
+ } else {
+ view.setOnClickListener(null)
+ }
+ }
+
+ private fun getSelectableDrawable(context: Context, viewModel: UserViewModel): Drawable {
+ val layerDrawable =
+ checkNotNull(
+ ResourcesCompat.getDrawable(
+ context.resources,
+ R.drawable.user_switcher_icon_large,
+ context.theme,
+ )
+ )
+ .mutate() as LayerDrawable
+ if (viewModel.isSelectionMarkerVisible) {
+ (layerDrawable.findDrawableByLayerId(R.id.ring) as GradientDrawable).apply {
+ val stroke =
+ context.resources.getDimensionPixelSize(
+ R.dimen.user_switcher_icon_selected_width
+ )
+ val color =
+ Utils.getColorAttrDefaultColor(
+ context,
+ com.android.internal.R.attr.colorAccentPrimary
+ )
+
+ setStroke(stroke, color)
+ }
+ }
+
+ layerDrawable.setDrawableByLayerId(R.id.user_avatar, viewModel.image)
+ return layerDrawable
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/UserActionViewModel.kt b/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/UserActionViewModel.kt
new file mode 100644
index 0000000..149b1ff
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/UserActionViewModel.kt
@@ -0,0 +1,33 @@
+/*
+ * 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.user.ui.viewmodel
+
+import androidx.annotation.DrawableRes
+import androidx.annotation.StringRes
+
+/** Models UI state for an action that can be performed on a user. */
+data class UserActionViewModel(
+ /**
+ * Key to use with the view or compose system to keep track of the view/composable across
+ * changes to the collection of [UserActionViewModel] instances.
+ */
+ val viewKey: Long,
+ @DrawableRes val iconResourceId: Int,
+ @StringRes val textResourceId: Int,
+ val onClicked: () -> Unit,
+)
diff --git a/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModel.kt b/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModel.kt
new file mode 100644
index 0000000..66ce01b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModel.kt
@@ -0,0 +1,199 @@
+/*
+ * 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.user.ui.viewmodel
+
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+import com.android.systemui.R
+import com.android.systemui.power.domain.interactor.PowerInteractor
+import com.android.systemui.user.domain.interactor.UserInteractor
+import com.android.systemui.user.legacyhelper.ui.LegacyUserUiHelper
+import com.android.systemui.user.shared.model.UserActionModel
+import com.android.systemui.user.shared.model.UserModel
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.map
+
+/** Models UI state for the user switcher feature. */
+class UserSwitcherViewModel
+private constructor(
+ private val userInteractor: UserInteractor,
+ private val powerInteractor: PowerInteractor,
+) : ViewModel() {
+
+ /** On-device users. */
+ val users: Flow<List<UserViewModel>> =
+ userInteractor.users.map { models -> models.map { user -> toViewModel(user) } }
+
+ /** The maximum number of columns that the user selection grid should use. */
+ val maximumUserColumns: Flow<Int> =
+ users.map { LegacyUserUiHelper.getMaxUserSwitcherItemColumns(it.size) }
+
+ /** Whether the button to open the user action menu is visible. */
+ val isOpenMenuButtonVisible: Flow<Boolean> = userInteractor.actions.map { it.isNotEmpty() }
+
+ private val _isMenuVisible = MutableStateFlow(false)
+ /**
+ * Whether the user action menu should be shown. Once the action menu is dismissed/closed, the
+ * consumer must invoke [onMenuClosed].
+ */
+ val isMenuVisible: Flow<Boolean> = _isMenuVisible
+ /** The user action menu. */
+ val menu: Flow<List<UserActionViewModel>> =
+ userInteractor.actions.map { actions -> actions.map { action -> toViewModel(action) } }
+
+ private val hasCancelButtonBeenClicked = MutableStateFlow(false)
+
+ /**
+ * Whether the observer should finish the experience. Once consumed, [onFinished] must be called
+ * by the consumer.
+ */
+ val isFinishRequested: Flow<Boolean> = createFinishRequestedFlow()
+
+ /** Notifies that the user has clicked the cancel button. */
+ fun onCancelButtonClicked() {
+ hasCancelButtonBeenClicked.value = true
+ }
+
+ /**
+ * Notifies that the user experience is finished.
+ *
+ * Call this after consuming [isFinishRequested] with a `true` value in order to mark it as
+ * consumed such that the next consumer doesn't immediately finish itself.
+ */
+ fun onFinished() {
+ hasCancelButtonBeenClicked.value = false
+ }
+
+ /** Notifies that the user has clicked the "open menu" button. */
+ fun onOpenMenuButtonClicked() {
+ _isMenuVisible.value = true
+ }
+
+ /**
+ * Notifies that the user has dismissed or closed the user action menu.
+ *
+ * Call this after consuming [isMenuVisible] with a `true` value in order to reset it to `false`
+ * such that the next consumer doesn't immediately show the menu again.
+ */
+ fun onMenuClosed() {
+ _isMenuVisible.value = false
+ }
+
+ private fun createFinishRequestedFlow(): Flow<Boolean> {
+ var mostRecentSelectedUserId: Int? = null
+ var mostRecentIsInteractive: Boolean? = null
+
+ return combine(
+ // When the user is switched, we should finish.
+ userInteractor.selectedUser
+ .map { it.id }
+ .map {
+ val selectedUserChanged =
+ mostRecentSelectedUserId != null && mostRecentSelectedUserId != it
+ mostRecentSelectedUserId = it
+ selectedUserChanged
+ },
+ // When the screen turns off, we should finish.
+ powerInteractor.isInteractive.map {
+ val screenTurnedOff = mostRecentIsInteractive == true && !it
+ mostRecentIsInteractive = it
+ screenTurnedOff
+ },
+ // When the cancel button is clicked, we should finish.
+ hasCancelButtonBeenClicked,
+ ) { selectedUserChanged, screenTurnedOff, cancelButtonClicked ->
+ selectedUserChanged || screenTurnedOff || cancelButtonClicked
+ }
+ }
+
+ private fun toViewModel(
+ model: UserModel,
+ ): UserViewModel {
+ return UserViewModel(
+ viewKey = model.id,
+ name = model.name,
+ image = model.image,
+ isSelectionMarkerVisible = model.isSelected,
+ alpha =
+ if (model.isSelectable) {
+ LegacyUserUiHelper.USER_SWITCHER_USER_VIEW_SELECTABLE_ALPHA
+ } else {
+ LegacyUserUiHelper.USER_SWITCHER_USER_VIEW_NOT_SELECTABLE_ALPHA
+ },
+ onClicked = createOnSelectedCallback(model),
+ )
+ }
+
+ private fun toViewModel(
+ model: UserActionModel,
+ ): UserActionViewModel {
+ return UserActionViewModel(
+ viewKey = model.ordinal.toLong(),
+ iconResourceId =
+ if (model == UserActionModel.NAVIGATE_TO_USER_MANAGEMENT) {
+ R.drawable.ic_manage_users
+ } else {
+ LegacyUserUiHelper.getUserSwitcherActionIconResourceId(
+ isAddSupervisedUser = model == UserActionModel.ADD_SUPERVISED_USER,
+ isAddUser = model == UserActionModel.ADD_USER,
+ isGuest = model == UserActionModel.ENTER_GUEST_MODE,
+ )
+ },
+ textResourceId =
+ if (model == UserActionModel.NAVIGATE_TO_USER_MANAGEMENT) {
+ R.string.manage_users
+ } else {
+ LegacyUserUiHelper.getUserSwitcherActionTextResourceId(
+ isGuest = model == UserActionModel.ENTER_GUEST_MODE,
+ isGuestUserAutoCreated = userInteractor.isGuestUserAutoCreated,
+ isGuestUserResetting = userInteractor.isGuestUserResetting,
+ isAddSupervisedUser = model == UserActionModel.ADD_SUPERVISED_USER,
+ isAddUser = model == UserActionModel.ADD_USER,
+ )
+ },
+ onClicked = { userInteractor.executeAction(action = model) },
+ )
+ }
+
+ private fun createOnSelectedCallback(model: UserModel): (() -> Unit)? {
+ return if (!model.isSelectable) {
+ null
+ } else {
+ { userInteractor.selectUser(model.id) }
+ }
+ }
+
+ class Factory
+ @Inject
+ constructor(
+ private val userInteractor: UserInteractor,
+ private val powerInteractor: PowerInteractor,
+ ) : ViewModelProvider.Factory {
+ override fun <T : ViewModel> create(modelClass: Class<T>): T {
+ @Suppress("UNCHECKED_CAST")
+ return UserSwitcherViewModel(
+ userInteractor = userInteractor,
+ powerInteractor = powerInteractor,
+ )
+ as T
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/UserViewModel.kt b/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/UserViewModel.kt
new file mode 100644
index 0000000..d57bba0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/UserViewModel.kt
@@ -0,0 +1,36 @@
+/*
+ * 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.user.ui.viewmodel
+
+import android.graphics.drawable.Drawable
+import com.android.systemui.common.shared.model.Text
+
+/** Models UI state for representing a single user. */
+data class UserViewModel(
+ /**
+ * Key to use with the view or compose system to keep track of the view/composable across
+ * changes to the collection of [UserViewModel] instances.
+ */
+ val viewKey: Int,
+ val name: Text,
+ val image: Drawable,
+ /** Whether a marker should be shown to highlight that this user is the selected one. */
+ val isSelectionMarkerVisible: Boolean,
+ val alpha: Float,
+ val onClicked: (() -> Unit)?,
+)
diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/Flow.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/Flow.kt
index 7baebf4..f71d596 100644
--- a/packages/SystemUI/src/com/android/systemui/util/kotlin/Flow.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/Flow.kt
@@ -16,11 +16,15 @@
package com.android.systemui.util.kotlin
+import java.util.concurrent.atomic.AtomicReference
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.distinctUntilChanged
-import kotlinx.coroutines.flow.drop
+import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.onStart
-import kotlinx.coroutines.flow.zip
+import kotlinx.coroutines.launch
/**
* Returns a new [Flow] that combines the two most recent emissions from [this] using [transform].
@@ -29,15 +33,16 @@
*
* Useful for code that needs to compare the current value to the previous value.
*/
-fun <T, R> Flow<T>.pairwiseBy(transform: suspend (old: T, new: T) -> R): Flow<R> {
- // same as current flow, but with the very first event skipped
- val nextEvents = drop(1)
- // zip current flow and nextEvents; transform will receive a pair of old and new value. This
- // works because zip will suppress emissions until both flows have emitted something; since in
- // this case both flows are emitting at the same rate, but the current flow just has one extra
- // thing emitted at the start, the effect is that zip will cache the most recent value while
- // waiting for the next emission from nextEvents.
- return zip(nextEvents, transform)
+fun <T, R> Flow<T>.pairwiseBy(transform: suspend (old: T, new: T) -> R): Flow<R> = flow {
+ val noVal = Any()
+ var previousValue: Any? = noVal
+ collect { newVal ->
+ if (previousValue != noVal) {
+ @Suppress("UNCHECKED_CAST")
+ emit(transform(previousValue as T, newVal))
+ }
+ previousValue = newVal
+ }
}
/**
@@ -74,10 +79,19 @@
/**
* Returns a new [Flow] that combines the [Set] changes between each emission from [this] using
* [transform].
+ *
+ * If [emitFirstEvent] is `true`, then the first [Set] emitted from the upstream [Flow] will cause
+ * a change event to be emitted that contains no removals, and all elements from that first [Set]
+ * as additions.
+ *
+ * If [emitFirstEvent] is `false`, then the first emission is ignored and no changes are emitted
+ * until a second [Set] has been emitted from the upstream [Flow].
*/
fun <T, R> Flow<Set<T>>.setChangesBy(
transform: suspend (removed: Set<T>, added: Set<T>) -> R,
-): Flow<R> = onStart { emit(emptySet()) }.distinctUntilChanged()
+ emitFirstEvent: Boolean = true,
+): Flow<R> = (if (emitFirstEvent) onStart { emit(emptySet()) } else this)
+ .distinctUntilChanged()
.pairwiseBy { old: Set<T>, new: Set<T> ->
// If an element was present in the old set, but not the new one, then it was removed
val removed = old - new
@@ -86,8 +100,18 @@
transform(removed, added)
}
-/** Returns a new [Flow] that produces the [Set] changes between each emission from [this]. */
-fun <T> Flow<Set<T>>.setChanges(): Flow<SetChanges<T>> = setChangesBy(::SetChanges)
+/**
+ * Returns a new [Flow] that produces the [Set] changes between each emission from [this].
+ *
+ * If [emitFirstEvent] is `true`, then the first [Set] emitted from the upstream [Flow] will cause
+ * a change event to be emitted that contains no removals, and all elements from that first [Set]
+ * as additions.
+ *
+ * If [emitFirstEvent] is `false`, then the first emission is ignored and no changes are emitted
+ * until a second [Set] has been emitted from the upstream [Flow].
+ */
+fun <T> Flow<Set<T>>.setChanges(emitFirstEvent: Boolean = true): Flow<SetChanges<T>> =
+ setChangesBy(::SetChanges, emitFirstEvent)
/** Contains the difference in elements between two [Set]s. */
data class SetChanges<T>(
@@ -96,3 +120,35 @@
/** Elements that are present in the second [Set] but not in the first. */
val added: Set<T>,
)
+
+/**
+ * Returns a new [Flow] that emits at the same rate as [this], but combines the emitted value with
+ * the most recent emission from [other] using [transform].
+ *
+ * Note that the returned Flow will not emit anything until [other] has emitted at least one value.
+ */
+fun <A, B, C> Flow<A>.sample(other: Flow<B>, transform: suspend (A, B) -> C): Flow<C> = flow {
+ coroutineScope {
+ val noVal = Any()
+ val sampledRef = AtomicReference(noVal)
+ val job = launch(Dispatchers.Unconfined) {
+ other.collect { sampledRef.set(it) }
+ }
+ collect {
+ val sampled = sampledRef.get()
+ if (sampled != noVal) {
+ @Suppress("UNCHECKED_CAST")
+ emit(transform(it, sampled as B))
+ }
+ }
+ job.cancel()
+ }
+}
+
+/**
+ * Returns a new [Flow] that emits at the same rate as [this], but emits the most recently emitted
+ * value from [other] instead.
+ *
+ * Note that the returned Flow will not emit anything until [other] has emitted at least one value.
+ */
+fun <A> Flow<*>.sample(other: Flow<A>): Flow<A> = sample(other) { _, a -> a }
diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/Suspend.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/Suspend.kt
new file mode 100644
index 0000000..2e551f1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/Suspend.kt
@@ -0,0 +1,35 @@
+/*
+ * 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.util.kotlin
+
+import kotlinx.coroutines.CompletableDeferred
+import kotlinx.coroutines.coroutineScope
+import kotlinx.coroutines.launch
+
+/**
+ * Runs the given [blocks] in parallel, returning the result of the first one to complete, and
+ * cancelling all others.
+ */
+suspend fun <R> race(vararg blocks: suspend () -> R): R = coroutineScope {
+ val completion = CompletableDeferred<R>()
+ val raceJob = launch {
+ for (block in blocks) {
+ launch { completion.complete(block()) }
+ }
+ }
+ completion.await().also { raceJob.cancel() }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java b/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java
index e910f72..619e50b 100644
--- a/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java
@@ -27,6 +27,7 @@
import android.content.Intent;
import android.content.res.ColorStateList;
import android.graphics.Canvas;
+import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.PixelFormat;
@@ -58,7 +59,6 @@
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.qs.QSHost;
import com.android.systemui.qs.logging.QSLogger;
-import com.android.systemui.qs.tileimpl.QSIconViewImpl;
import com.android.systemui.qs.tileimpl.QSTileImpl;
import com.android.systemui.util.concurrency.DelayableExecutor;
import com.android.systemui.util.concurrency.MessageRouter;
@@ -304,7 +304,7 @@
MemoryIconDrawable(Context context) {
baseIcon = context.getDrawable(R.drawable.ic_memory).mutate();
dp = context.getResources().getDisplayMetrics().density;
- paint.setColor(QSIconViewImpl.getIconColorForState(context, STATE_ACTIVE));
+ paint.setColor(Color.WHITE);
}
public void setRss(long rss) {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumePanelDialog.java b/packages/SystemUI/src/com/android/systemui/volume/VolumePanelDialog.java
index 2c74fb9..87a167b 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumePanelDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumePanelDialog.java
@@ -52,6 +52,7 @@
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
import com.android.settingslib.media.MediaOutputConstants;
import com.android.systemui.R;
+import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.statusbar.phone.SystemUIDialog;
import java.util.ArrayList;
@@ -69,6 +70,7 @@
private static final int DURATION_SLICE_BINDING_TIMEOUT_MS = 200;
private static final int DEFAULT_SLICE_SIZE = 4;
+ private final ActivityStarter mActivityStarter;
private RecyclerView mVolumePanelSlices;
private VolumePanelSlicesAdapter mVolumePanelSlicesAdapter;
private final LifecycleRegistry mLifecycleRegistry;
@@ -78,8 +80,10 @@
private boolean mSlicesReadyToLoad;
private LocalBluetoothProfileManager mProfileManager;
- public VolumePanelDialog(Context context, boolean aboveStatusBar) {
+ public VolumePanelDialog(Context context,
+ ActivityStarter activityStarter, boolean aboveStatusBar) {
super(context);
+ mActivityStarter = activityStarter;
mLifecycleRegistry = new LifecycleRegistry(this);
if (!aboveStatusBar) {
getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);
@@ -100,9 +104,11 @@
doneButton.setOnClickListener(v -> dismiss());
Button settingsButton = dialogView.findViewById(R.id.settings_button);
settingsButton.setOnClickListener(v -> {
- getContext().startActivity(new Intent(Settings.ACTION_SOUND_SETTINGS).addFlags(
- Intent.FLAG_ACTIVITY_NEW_TASK));
dismiss();
+
+ Intent intent = new Intent(Settings.ACTION_SOUND_SETTINGS);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ mActivityStarter.startActivity(intent, /* dismissShade= */ true);
});
LocalBluetoothManager localBluetoothManager = LocalBluetoothManager.getInstance(
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumePanelFactory.kt b/packages/SystemUI/src/com/android/systemui/volume/VolumePanelFactory.kt
index c2fafbf..0debe0e 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumePanelFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumePanelFactory.kt
@@ -21,6 +21,7 @@
import android.view.View
import com.android.systemui.animation.DialogLaunchAnimator
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.plugins.ActivityStarter
import javax.inject.Inject
private const val TAG = "VolumePanelFactory"
@@ -33,6 +34,7 @@
@SysUISingleton
class VolumePanelFactory @Inject constructor(
private val context: Context,
+ private val activityStarter: ActivityStarter,
private val dialogLaunchAnimator: DialogLaunchAnimator
) {
companion object {
@@ -45,7 +47,7 @@
return
}
- val dialog = VolumePanelDialog(context, aboveStatusBar)
+ val dialog = VolumePanelDialog(context, activityStarter, aboveStatusBar)
volumePanelDialog = dialog
// Show the dialog.
diff --git a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java
similarity index 98%
rename from packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
rename to packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java
index 8ff90f7..2878ad9 100644
--- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui;
+package com.android.systemui.wallpapers;
import android.app.WallpaperColors;
import android.graphics.Bitmap;
@@ -37,8 +37,8 @@
import androidx.annotation.NonNull;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.glwallpaper.EglHelper;
-import com.android.systemui.glwallpaper.ImageWallpaperRenderer;
+import com.android.systemui.wallpapers.gl.EglHelper;
+import com.android.systemui.wallpapers.gl.ImageWallpaperRenderer;
import java.io.FileDescriptor;
import java.io.PrintWriter;
diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/OWNERS b/packages/SystemUI/src/com/android/systemui/wallpapers/OWNERS
new file mode 100644
index 0000000..731c798
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/wallpapers/OWNERS
@@ -0,0 +1,6 @@
+set noparent
+
+cinek@google.com
+dupin@google.com
+pomini@google.com
+santie@google.com
diff --git a/packages/SystemUI/src/com/android/systemui/glwallpaper/EglHelper.java b/packages/SystemUI/src/com/android/systemui/wallpapers/gl/EglHelper.java
similarity index 99%
rename from packages/SystemUI/src/com/android/systemui/glwallpaper/EglHelper.java
rename to packages/SystemUI/src/com/android/systemui/wallpapers/gl/EglHelper.java
index 11e215d..f9ddce8 100644
--- a/packages/SystemUI/src/com/android/systemui/glwallpaper/EglHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/wallpapers/gl/EglHelper.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.glwallpaper;
+package com.android.systemui.wallpapers.gl;
import static android.opengl.EGL14.EGL_ALPHA_SIZE;
import static android.opengl.EGL14.EGL_BLUE_SIZE;
diff --git a/packages/SystemUI/src/com/android/systemui/glwallpaper/GLWallpaperRenderer.java b/packages/SystemUI/src/com/android/systemui/wallpapers/gl/GLWallpaperRenderer.java
similarity index 97%
rename from packages/SystemUI/src/com/android/systemui/glwallpaper/GLWallpaperRenderer.java
rename to packages/SystemUI/src/com/android/systemui/wallpapers/gl/GLWallpaperRenderer.java
index 6152490..692ced0 100644
--- a/packages/SystemUI/src/com/android/systemui/glwallpaper/GLWallpaperRenderer.java
+++ b/packages/SystemUI/src/com/android/systemui/wallpapers/gl/GLWallpaperRenderer.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.glwallpaper;
+package com.android.systemui.wallpapers.gl;
import android.util.Size;
diff --git a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLProgram.java b/packages/SystemUI/src/com/android/systemui/wallpapers/gl/ImageGLProgram.java
similarity index 98%
rename from packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLProgram.java
rename to packages/SystemUI/src/com/android/systemui/wallpapers/gl/ImageGLProgram.java
index d03b00b..d34eca4 100644
--- a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLProgram.java
+++ b/packages/SystemUI/src/com/android/systemui/wallpapers/gl/ImageGLProgram.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.glwallpaper;
+package com.android.systemui.wallpapers.gl;
import static android.opengl.GLES20.GL_FRAGMENT_SHADER;
import static android.opengl.GLES20.GL_VERTEX_SHADER;
diff --git a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLWallpaper.java b/packages/SystemUI/src/com/android/systemui/wallpapers/gl/ImageGLWallpaper.java
similarity index 99%
rename from packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLWallpaper.java
rename to packages/SystemUI/src/com/android/systemui/wallpapers/gl/ImageGLWallpaper.java
index 1a53c28..f1659b9 100644
--- a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/wallpapers/gl/ImageGLWallpaper.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.glwallpaper;
+package com.android.systemui.wallpapers.gl;
import static android.opengl.GLES20.GL_FLOAT;
import static android.opengl.GLES20.GL_LINEAR;
diff --git a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java b/packages/SystemUI/src/com/android/systemui/wallpapers/gl/ImageWallpaperRenderer.java
similarity index 98%
rename from packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java
rename to packages/SystemUI/src/com/android/systemui/wallpapers/gl/ImageWallpaperRenderer.java
index 7c0b93b..e393786 100644
--- a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java
+++ b/packages/SystemUI/src/com/android/systemui/wallpapers/gl/ImageWallpaperRenderer.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.glwallpaper;
+package com.android.systemui.wallpapers.gl;
import static android.opengl.GLES20.GL_COLOR_BUFFER_BIT;
import static android.opengl.GLES20.glClear;
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
index ce96741..4e77514 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
@@ -57,11 +57,9 @@
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.notification.NotificationChannelHelper;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotifCollection;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.collection.coordinator.BubbleCoordinator;
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
@@ -313,18 +311,6 @@
}
@Override
- public void notifyMaybeCancelSummary(String key) {
- sysuiMainExecutor.execute(() -> {
- final NotificationEntry entry = mCommonNotifCollection.getEntry(key);
- if (entry != null) {
- for (NotifCallback cb : mCallbacks) {
- cb.maybeCancelSummary(entry);
- }
- }
- });
- }
-
- @Override
public void updateNotificationBubbleButton(String key) {
sysuiMainExecutor.execute(() -> {
final NotificationEntry entry = mCommonNotifCollection.getEntry(key);
@@ -460,11 +446,6 @@
mBubbles.onNotificationChannelModified(pkg, user, channel, modificationType);
}
- /**
- * Gets the DismissedByUserStats used by {@link NotificationEntryManager}.
- * Will not be necessary when using the new notification pipeline's {@link NotifCollection}.
- * Instead, this is taken care of by {@link BubbleCoordinator}.
- */
private DismissedByUserStats getDismissedByUserStats(
NotificationEntry entry,
boolean isVisible) {
@@ -653,15 +634,5 @@
* filtered from the shade.
*/
void invalidateNotifications(@NonNull String reason);
-
- /**
- * Called on a bubbled entry that has been removed when there are no longer
- * bubbled entries in its group.
- *
- * Checks whether its group has any other (non-bubbled) children. If it doesn't,
- * removes all remnants of the group's summary from the notification pipeline.
- * TODO: (b/145659174) Only old pipeline needs this - delete post-migration.
- */
- void maybeCancelSummary(@NonNull NotificationEntry entry);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
index a4a59fc..3961a8b 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
@@ -34,7 +34,6 @@
import android.graphics.Rect;
import android.inputmethodservice.InputMethodService;
import android.os.IBinder;
-import android.os.ParcelFileDescriptor;
import android.view.KeyEvent;
import androidx.annotation.NonNull;
@@ -62,12 +61,10 @@
import com.android.wm.shell.onehanded.OneHandedTransitionCallback;
import com.android.wm.shell.onehanded.OneHandedUiEventLogger;
import com.android.wm.shell.pip.Pip;
-import com.android.wm.shell.protolog.ShellProtoLogImpl;
import com.android.wm.shell.splitscreen.SplitScreen;
import com.android.wm.shell.sysui.ShellInterface;
import java.io.PrintWriter;
-import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.Executor;
@@ -336,44 +333,7 @@
if (mShell.handleCommand(args, pw)) {
return;
}
- // Handle logging commands if provided
- if (handleLoggingCommand(args, pw)) {
- return;
- }
// Dump WMShell stuff here if no commands were handled
mShell.dump(pw);
}
-
- @Override
- public void handleWindowManagerLoggingCommand(String[] args, ParcelFileDescriptor outFd) {
- PrintWriter pw = new PrintWriter(new ParcelFileDescriptor.AutoCloseOutputStream(outFd));
- handleLoggingCommand(args, pw);
- pw.flush();
- pw.close();
- }
-
- private boolean handleLoggingCommand(String[] args, PrintWriter pw) {
- ShellProtoLogImpl protoLogImpl = ShellProtoLogImpl.getSingleInstance();
- for (int i = 0; i < args.length; i++) {
- switch (args[i]) {
- case "enable-text": {
- String[] groups = Arrays.copyOfRange(args, i + 1, args.length);
- int result = protoLogImpl.startTextLogging(groups, pw);
- if (result == 0) {
- pw.println("Starting logging on groups: " + Arrays.toString(groups));
- }
- return true;
- }
- case "disable-text": {
- String[] groups = Arrays.copyOfRange(args, i + 1, args.length);
- int result = protoLogImpl.stopTextLogging(groups, pw);
- if (result == 0) {
- pw.println("Stopping logging on groups: " + Arrays.toString(groups));
- }
- return true;
- }
- }
- }
- return false;
- }
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaTest.java b/packages/SystemUI/tests/src/com/android/keyguard/AuthKeyguardMessageAreaTest.java
similarity index 90%
rename from packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaTest.java
rename to packages/SystemUI/tests/src/com/android/keyguard/AuthKeyguardMessageAreaTest.java
index 013c298..0a9c745 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/AuthKeyguardMessageAreaTest.java
@@ -33,14 +33,14 @@
@SmallTest
@RunWith(AndroidTestingRunner.class)
@RunWithLooper
-public class KeyguardMessageAreaTest extends SysuiTestCase {
+public class AuthKeyguardMessageAreaTest extends SysuiTestCase {
private KeyguardMessageArea mKeyguardMessageArea;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- mKeyguardMessageArea = new KeyguardMessageArea(mContext, null);
- mKeyguardMessageArea.setBouncerShowing(true);
+ mKeyguardMessageArea = new AuthKeyguardMessageArea(mContext, null);
+ mKeyguardMessageArea.setIsVisible(true);
}
@Test
@@ -53,7 +53,7 @@
@Test
public void testHiddenWhenBouncerHidden() {
- mKeyguardMessageArea.setBouncerShowing(false);
+ mKeyguardMessageArea.setIsVisible(false);
mKeyguardMessageArea.setVisibility(View.INVISIBLE);
mKeyguardMessageArea.setMessage("oobleck");
assertThat(mKeyguardMessageArea.getVisibility()).isEqualTo(View.INVISIBLE);
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/FaceAuthReasonTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/FaceAuthReasonTest.kt
new file mode 100644
index 0000000..68d0f41
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/FaceAuthReasonTest.kt
@@ -0,0 +1,41 @@
+/*
+ * 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.keyguard
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import junit.framework.Assert
+import kotlin.reflect.full.declaredMembers
+import org.junit.Test
+
+@SmallTest
+class FaceAuthReasonTest : SysuiTestCase() {
+ @Test
+ fun testApiReasonToUiEvent_forAllReasons_isNotNull() {
+ val declaredMemberProperties = FaceAuthApiRequestReason.Companion::class.declaredMembers
+
+ declaredMemberProperties.forEach {
+ val reason = it.call()
+ try {
+ apiRequestReasonToUiEvent(reason as String)
+ } catch (e: Exception) {
+ Assert.fail(
+ "Expected the reason: \"$reason\" to have a corresponding FaceAuthUiEvent"
+ )
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java
index 90f7fda..8bbaf3d 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java
@@ -56,7 +56,7 @@
@Mock
private PasswordTextView mPasswordEntry;
@Mock
- private KeyguardMessageArea mKeyguardMessageArea;
+ private BouncerKeyguardMessageArea mKeyguardMessageArea;
@Mock
private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@Mock
@@ -85,7 +85,7 @@
when(mAbsKeyInputView.getPasswordTextViewId()).thenReturn(1);
when(mAbsKeyInputView.findViewById(1)).thenReturn(mPasswordEntry);
when(mAbsKeyInputView.isAttachedToWindow()).thenReturn(true);
- when(mAbsKeyInputView.findViewById(R.id.keyguard_message_area))
+ when(mAbsKeyInputView.requireViewById(R.id.bouncer_message_area))
.thenReturn(mKeyguardMessageArea);
mKeyguardAbsKeyInputViewController = new KeyguardAbsKeyInputViewController(mAbsKeyInputView,
mKeyguardUpdateMonitor, mSecurityMode, mLockPatternUtils, mKeyguardSecurityCallback,
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardListenQueueTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardListenQueueTest.kt
index bb455da..0bf038d 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardListenQueueTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardListenQueueTest.kt
@@ -86,6 +86,7 @@
becauseCannotSkipBouncer = false,
biometricSettingEnabledForUser = false,
bouncerFullyShown = false,
+ bouncerIsOrWillShow = false,
onlyFaceEnrolled = false,
faceAuthenticated = false,
faceDisabled = false,
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaControllerTest.java
index 8293cc2..69524e5 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaControllerTest.java
@@ -89,8 +89,8 @@
@Test
public void testSetBouncerVisible() {
- mMessageAreaController.setBouncerShowing(true);
- verify(mKeyguardMessageArea).setBouncerShowing(true);
+ mMessageAreaController.setIsVisible(true);
+ verify(mKeyguardMessageArea).setIsVisible(true);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt
index ec85603..b89dbd9 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt
@@ -64,9 +64,10 @@
@Mock
lateinit var keyguardViewController: KeyguardViewController
@Mock
- private lateinit var mKeyguardMessageArea: KeyguardMessageArea
+ private lateinit var mKeyguardMessageArea: BouncerKeyguardMessageArea
@Mock
- private lateinit var mKeyguardMessageAreaController: KeyguardMessageAreaController
+ private lateinit var mKeyguardMessageAreaController:
+ KeyguardMessageAreaController<BouncerKeyguardMessageArea>
private lateinit var keyguardPasswordViewController: KeyguardPasswordViewController
@@ -74,7 +75,8 @@
fun setup() {
MockitoAnnotations.initMocks(this)
Mockito.`when`(
- keyguardPasswordView.findViewById<KeyguardMessageArea>(R.id.keyguard_message_area)
+ keyguardPasswordView
+ .requireViewById<BouncerKeyguardMessageArea>(R.id.bouncer_message_area)
).thenReturn(mKeyguardMessageArea)
Mockito.`when`(messageAreaControllerFactory.create(mKeyguardMessageArea))
.thenReturn(mKeyguardMessageAreaController)
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt
index 616a105..3262a77 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt
@@ -66,10 +66,11 @@
var mKeyguardMessageAreaControllerFactory: KeyguardMessageAreaController.Factory
@Mock
- private lateinit var mKeyguardMessageArea: KeyguardMessageArea
+ private lateinit var mKeyguardMessageArea: BouncerKeyguardMessageArea
@Mock
- private lateinit var mKeyguardMessageAreaController: KeyguardMessageAreaController
+ private lateinit var mKeyguardMessageAreaController:
+ KeyguardMessageAreaController<BouncerKeyguardMessageArea>
@Mock
private lateinit var mLockPatternView: LockPatternView
@@ -83,7 +84,8 @@
fun setup() {
MockitoAnnotations.initMocks(this)
`when`(mKeyguardPatternView.isAttachedToWindow).thenReturn(true)
- `when`(mKeyguardPatternView.findViewById<KeyguardMessageArea>(R.id.keyguard_message_area))
+ `when`(mKeyguardPatternView
+ .requireViewById<BouncerKeyguardMessageArea>(R.id.bouncer_message_area))
.thenReturn(mKeyguardMessageArea)
`when`(mKeyguardPatternView.findViewById<LockPatternView>(R.id.lockPatternView))
.thenReturn(mLockPatternView)
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java
index 7bc8e8a..97d556b 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java
@@ -51,7 +51,7 @@
@Mock
private PasswordTextView mPasswordEntry;
@Mock
- private KeyguardMessageArea mKeyguardMessageArea;
+ private BouncerKeyguardMessageArea mKeyguardMessageArea;
@Mock
private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@Mock
@@ -90,7 +90,7 @@
when(mPinBasedInputView.findViewById(1)).thenReturn(mPasswordEntry);
when(mPinBasedInputView.isAttachedToWindow()).thenReturn(true);
when(mPinBasedInputView.getButtons()).thenReturn(mButtons);
- when(mPinBasedInputView.findViewById(R.id.keyguard_message_area))
+ when(mPinBasedInputView.requireViewById(R.id.bouncer_message_area))
.thenReturn(mKeyguardMessageArea);
when(mPinBasedInputView.findViewById(R.id.delete_button))
.thenReturn(mDeleteButton);
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt
new file mode 100644
index 0000000..9e5bfe5
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt
@@ -0,0 +1,103 @@
+/*
+ * 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.keyguard
+
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.view.View
+import androidx.test.filters.SmallTest
+import com.android.internal.util.LatencyTracker
+import com.android.internal.widget.LockPatternUtils
+import com.android.keyguard.KeyguardSecurityModel.SecurityMode
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.classifier.FalsingCollector
+import com.android.systemui.classifier.FalsingCollectorFake
+import com.android.systemui.statusbar.policy.DevicePostureController
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito
+import org.mockito.Mockito.any
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper
+class KeyguardPinViewControllerTest : SysuiTestCase() {
+ @Mock private lateinit var keyguardPinView: KeyguardPINView
+
+ @Mock private lateinit var keyguardMessageArea: BouncerKeyguardMessageArea
+
+ @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
+
+ @Mock private lateinit var securityMode: SecurityMode
+
+ @Mock private lateinit var lockPatternUtils: LockPatternUtils
+
+ @Mock private lateinit var mKeyguardSecurityCallback: KeyguardSecurityCallback
+
+ @Mock
+ private lateinit var keyguardMessageAreaControllerFactory: KeyguardMessageAreaController.Factory
+
+ @Mock
+ private lateinit var keyguardMessageAreaController:
+ KeyguardMessageAreaController<BouncerKeyguardMessageArea>
+
+ @Mock private lateinit var mLatencyTracker: LatencyTracker
+
+ @Mock private lateinit var liftToActivateListener: LiftToActivateListener
+
+ @Mock private val mEmergencyButtonController: EmergencyButtonController? = null
+ private val falsingCollector: FalsingCollector = FalsingCollectorFake()
+ @Mock lateinit var postureController: DevicePostureController
+
+ lateinit var pinViewController: KeyguardPinViewController
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+ Mockito.`when`(keyguardPinView.requireViewById<View>(R.id.bouncer_message_area))
+ .thenReturn(keyguardMessageArea)
+ Mockito.`when`(
+ keyguardMessageAreaControllerFactory.create(any(KeyguardMessageArea::class.java))
+ )
+ .thenReturn(keyguardMessageAreaController)
+ pinViewController =
+ KeyguardPinViewController(
+ keyguardPinView,
+ keyguardUpdateMonitor,
+ securityMode,
+ lockPatternUtils,
+ mKeyguardSecurityCallback,
+ keyguardMessageAreaControllerFactory,
+ mLatencyTracker,
+ liftToActivateListener,
+ mEmergencyButtonController,
+ falsingCollector,
+ postureController
+ )
+ }
+
+ @Test
+ fun startAppearAnimation() {
+ pinViewController.startAppearAnimation()
+ verify(keyguardMessageAreaController).setMessageIfEmpty(R.string.keyguard_enter_your_pin)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
index d68e8bd..c6ebaa8 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
@@ -41,6 +41,7 @@
import android.hardware.biometrics.BiometricSourceType;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowInsetsController;
@@ -117,7 +118,7 @@
@Mock
private KeyguardMessageAreaController mKeyguardMessageAreaController;
@Mock
- private KeyguardMessageArea mKeyguardMessageArea;
+ private BouncerKeyguardMessageArea mKeyguardMessageArea;
@Mock
private ConfigurationController mConfigurationController;
@Mock
@@ -163,9 +164,10 @@
when(mAdminSecondaryLockScreenControllerFactory.create(any(KeyguardSecurityCallback.class)))
.thenReturn(mAdminSecondaryLockScreenController);
when(mSecurityViewFlipper.getWindowInsetsController()).thenReturn(mWindowInsetsController);
- mKeyguardPasswordView = spy(new KeyguardPasswordView(getContext()));
+ mKeyguardPasswordView = spy((KeyguardPasswordView) LayoutInflater.from(mContext).inflate(
+ R.layout.keyguard_password_view, null));
when(mKeyguardPasswordView.getRootView()).thenReturn(mSecurityViewFlipper);
- when(mKeyguardPasswordView.findViewById(R.id.keyguard_message_area))
+ when(mKeyguardPasswordView.requireViewById(R.id.bouncer_message_area))
.thenReturn(mKeyguardMessageArea);
when(mKeyguardMessageAreaControllerFactory.create(any(KeyguardMessageArea.class)))
.thenReturn(mKeyguardMessageAreaController);
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index c281965..d73799c 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -16,6 +16,8 @@
package com.android.keyguard;
+import static android.app.StatusBarManager.SESSION_KEYGUARD;
+import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_START;
import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ERROR_LOCKOUT;
import static android.telephony.SubscriptionManager.DATA_ROAMING_DISABLE;
import static android.telephony.SubscriptionManager.NAME_SOURCE_CARRIER_ID;
@@ -29,6 +31,7 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeastOnce;
@@ -71,6 +74,7 @@
import android.os.CancellationSignal;
import android.os.Handler;
import android.os.IRemoteCallback;
+import android.os.PowerManager;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
@@ -85,6 +89,8 @@
import com.android.dx.mockito.inline.extended.ExtendedMockito;
import com.android.internal.jank.InteractionJankMonitor;
+import com.android.internal.logging.InstanceId;
+import com.android.internal.logging.UiEventLogger;
import com.android.internal.telephony.TelephonyIntents;
import com.android.internal.util.LatencyTracker;
import com.android.internal.widget.ILockSettings;
@@ -95,6 +101,7 @@
import com.android.systemui.biometrics.AuthController;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.log.SessionTracker;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
@@ -189,6 +196,12 @@
private KeyguardUpdateMonitorLogger mKeyguardUpdateMonitorLogger;
@Mock
private IActivityManager mActivityService;
+ @Mock
+ private SessionTracker mSessionTracker;
+ @Mock
+ private UiEventLogger mUiEventLogger;
+ @Mock
+ private PowerManager mPowerManager;
private final int mCurrentUserId = 100;
private final UserInfo mCurrentUserInfo = new UserInfo(mCurrentUserId, "Test user", 0);
@@ -211,6 +224,7 @@
private MockitoSession mMockitoSession;
private StatusBarStateController.StateListener mStatusBarStateListener;
private IBiometricEnabledOnKeyguardCallback mBiometricEnabledOnKeyguardCallback;
+ private final InstanceId mKeyguardInstanceId = InstanceId.fakeInstanceId(999);
@Before
public void setup() throws RemoteException {
@@ -224,6 +238,7 @@
when(mFaceManager.hasEnrolledTemplates()).thenReturn(true);
when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
when(mFaceManager.getSensorPropertiesInternal()).thenReturn(mFaceSensorProperties);
+ when(mSessionTracker.getSessionId(SESSION_KEYGUARD)).thenReturn(mKeyguardInstanceId);
// IBiometricsFace@1.0 does not support detection, only authentication.
when(mFaceSensorProperties.isEmpty()).thenReturn(false);
@@ -655,7 +670,8 @@
// Stop scanning when bouncer becomes visible
setKeyguardBouncerVisibility(true);
clearInvocations(mFaceManager);
- mKeyguardUpdateMonitor.requestFaceAuth(true);
+ mKeyguardUpdateMonitor.requestFaceAuth(true,
+ FaceAuthApiRequestReason.UDFPS_POINTER_DOWN);
verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
anyBoolean());
}
@@ -1499,10 +1515,13 @@
keyguardIsVisible();
mTestableLooper.processAllMessages();
+ clearInvocations(mUiEventLogger);
assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isTrue();
- mKeyguardUpdateMonitor.requestFaceAuth(true);
+ mKeyguardUpdateMonitor.requestFaceAuth(true,
+ FaceAuthApiRequestReason.UDFPS_POINTER_DOWN);
+
verify(mFaceManager).authenticate(any(),
mCancellationSignalCaptor.capture(),
mAuthenticationCallbackCaptor.capture(),
@@ -1511,7 +1530,7 @@
anyBoolean());
CancellationSignal cancelSignal = mCancellationSignalCaptor.getValue();
- bouncerFullyVisible();
+ bouncerWillBeVisibleSoon();
mTestableLooper.processAllMessages();
assertThat(cancelSignal.isCanceled()).isTrue();
@@ -1545,6 +1564,28 @@
assertThat(mKeyguardUpdateMonitor.shouldListenForFingerprint(anyBoolean())).isEqualTo(true);
}
+ @Test
+ public void testFingerAcquired_wakesUpPowerManager() {
+ mContext.getOrCreateTestableResources().addOverride(
+ com.android.internal.R.bool.kg_wake_on_acquire_start, true);
+ mSpiedContext = spy(mContext);
+ mKeyguardUpdateMonitor = new TestableKeyguardUpdateMonitor(mSpiedContext);
+ fingerprintAcquireStart();
+
+ verify(mPowerManager).wakeUp(anyLong(), anyInt(), anyString());
+ }
+
+ @Test
+ public void testFingerAcquired_doesNotWakeUpPowerManager() {
+ mContext.getOrCreateTestableResources().addOverride(
+ com.android.internal.R.bool.kg_wake_on_acquire_start, false);
+ mSpiedContext = spy(mContext);
+ mKeyguardUpdateMonitor = new TestableKeyguardUpdateMonitor(mSpiedContext);
+ fingerprintAcquireStart();
+
+ verify(mPowerManager, never()).wakeUp(anyLong(), anyInt(), anyString());
+ }
+
private void faceAuthEnabled() {
// this ensures KeyguardUpdateMonitor updates the cached mIsFaceEnrolled flag using the
// face manager mock wire-up in setup()
@@ -1593,8 +1634,13 @@
.onAuthenticationError(FINGERPRINT_ERROR_LOCKOUT, "Fingerprint locked out");
}
+ private void fingerprintAcquireStart() {
+ mKeyguardUpdateMonitor.mFingerprintAuthenticationCallback
+ .onAuthenticationAcquired(FINGERPRINT_ACQUIRED_START);
+ }
+
private void triggerSuccessfulFaceAuth() {
- mKeyguardUpdateMonitor.requestFaceAuth(true);
+ mKeyguardUpdateMonitor.requestFaceAuth(true, FaceAuthApiRequestReason.UDFPS_POINTER_DOWN);
verify(mFaceManager).authenticate(any(),
any(),
mAuthenticationCallbackCaptor.capture(),
@@ -1669,6 +1715,11 @@
setKeyguardBouncerVisibility(true);
}
+ private void bouncerWillBeVisibleSoon() {
+ mKeyguardUpdateMonitor.sendKeyguardBouncerChanged(true, false);
+ mTestableLooper.processAllMessages();
+ }
+
private void setKeyguardBouncerVisibility(boolean isVisible) {
mKeyguardUpdateMonitor.sendKeyguardBouncerChanged(isVisible, isVisible);
mTestableLooper.processAllMessages();
@@ -1709,7 +1760,8 @@
mStatusBarStateController, mLockPatternUtils,
mAuthController, mTelephonyListenerManager,
mInteractionJankMonitor, mLatencyTracker, mActiveUnlockConfig,
- mKeyguardUpdateMonitorLogger);
+ mKeyguardUpdateMonitorLogger, mUiEventLogger, () -> mSessionTracker,
+ mPowerManager);
setStrongAuthTracker(KeyguardUpdateMonitorTest.this.mStrongAuthTracker);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java
index ba21afd..b47b08c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java
@@ -44,12 +44,10 @@
import com.android.internal.messages.nano.SystemMessageProto;
import com.android.systemui.appops.AppOpsController;
-import com.android.systemui.statusbar.notification.NotificationEntryListener;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
-import com.android.systemui.util.time.FakeSystemClock;
+import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
import org.junit.Before;
import org.junit.Test;
@@ -64,9 +62,7 @@
public class ForegroundServiceControllerTest extends SysuiTestCase {
private ForegroundServiceController mFsc;
private ForegroundServiceNotificationListener mListener;
- private NotificationEntryListener mEntryListener;
- private final FakeSystemClock mClock = new FakeSystemClock();
- @Mock private NotificationEntryManager mEntryManager;
+ private NotifCollectionListener mCollectionListener;
@Mock private AppOpsController mAppOpsController;
@Mock private Handler mMainHandler;
@Mock private NotifPipeline mNotifPipeline;
@@ -79,12 +75,13 @@
MockitoAnnotations.initMocks(this);
mFsc = new ForegroundServiceController(mAppOpsController, mMainHandler);
mListener = new ForegroundServiceNotificationListener(
- mContext, mFsc, mEntryManager, mNotifPipeline, mClock);
- ArgumentCaptor<NotificationEntryListener> entryListenerCaptor =
- ArgumentCaptor.forClass(NotificationEntryListener.class);
- verify(mEntryManager).addNotificationEntryListener(
+ mContext, mFsc, mNotifPipeline);
+ mListener.init();
+ ArgumentCaptor<NotifCollectionListener> entryListenerCaptor =
+ ArgumentCaptor.forClass(NotifCollectionListener.class);
+ verify(mNotifPipeline).addCollectionListener(
entryListenerCaptor.capture());
- mEntryListener = entryListenerCaptor.getValue();
+ mCollectionListener = entryListenerCaptor.getValue();
}
@Test
@@ -449,7 +446,7 @@
private NotificationEntry addFgEntry() {
NotificationEntry entry = createFgEntry();
- mEntryListener.onPendingEntryAdded(entry);
+ mCollectionListener.onEntryAdded(entry);
return entry;
}
@@ -461,12 +458,10 @@
}
private void entryRemoved(StatusBarNotification notification) {
- mEntryListener.onEntryRemoved(
+ mCollectionListener.onEntryRemoved(
new NotificationEntryBuilder()
.setSbn(notification)
.build(),
- null,
- false,
REASON_APP_CANCEL);
}
@@ -475,7 +470,7 @@
.setSbn(notification)
.setImportance(importance)
.build();
- mEntryListener.onPendingEntryAdded(entry);
+ mCollectionListener.onEntryAdded(entry);
}
private void entryUpdated(StatusBarNotification notification, int importance) {
@@ -483,7 +478,7 @@
.setSbn(notification)
.setImportance(importance)
.build();
- mEntryListener.onPreEntryUpdated(entry);
+ mCollectionListener.onEntryUpdated(entry);
}
@UserIdInt private static final int USERID_ONE = 10; // UserManagerService.MIN_USER_ID;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricMessageDeferralTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricMessageDeferralTest.kt
new file mode 100644
index 0000000..419fedf
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricMessageDeferralTest.kt
@@ -0,0 +1,147 @@
+/*
+ * 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.biometrics
+
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertNull
+import org.junit.Assert.assertTrue
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class BiometricMessageDeferralTest : SysuiTestCase() {
+
+ @Test
+ fun testProcessNoMessages_noDeferredMessage() {
+ val biometricMessageDeferral = BiometricMessageDeferral(setOf(), setOf())
+
+ assertNull(biometricMessageDeferral.getDeferredMessage())
+ }
+
+ @Test
+ fun testProcessNonDeferredMessages_noDeferredMessage() {
+ val biometricMessageDeferral = BiometricMessageDeferral(setOf(), setOf(1, 2))
+
+ // WHEN there are no deferred messages processed
+ for (i in 0..3) {
+ biometricMessageDeferral.processMessage(4, "test")
+ }
+
+ // THEN getDeferredMessage is null
+ assertNull(biometricMessageDeferral.getDeferredMessage())
+ }
+
+ @Test
+ fun testAllProcessedMessagesWereDeferred() {
+ val biometricMessageDeferral = BiometricMessageDeferral(setOf(), setOf(1))
+
+ // WHEN all the processed messages are a deferred message
+ for (i in 0..3) {
+ biometricMessageDeferral.processMessage(1, "test")
+ }
+
+ // THEN deferredMessage will return the string associated with the deferred msgId
+ assertEquals("test", biometricMessageDeferral.getDeferredMessage())
+ }
+
+ @Test
+ fun testReturnsMostFrequentDeferredMessage() {
+ val biometricMessageDeferral = BiometricMessageDeferral(setOf(), setOf(1, 2))
+
+ // WHEN there's two msgId=1 processed and one msgId=2 processed
+ biometricMessageDeferral.processMessage(1, "msgId-1")
+ biometricMessageDeferral.processMessage(1, "msgId-1")
+ biometricMessageDeferral.processMessage(1, "msgId-1")
+ biometricMessageDeferral.processMessage(2, "msgId-2")
+
+ // THEN the most frequent deferred message is that meets the threshold is returned
+ assertEquals("msgId-1", biometricMessageDeferral.getDeferredMessage())
+ }
+
+ @Test
+ fun testDeferredMessage_mustMeetThreshold() {
+ val biometricMessageDeferral = BiometricMessageDeferral(setOf(), setOf(1))
+
+ // WHEN more nonDeferredMessages are shown than the deferred message
+ val totalMessages = 10
+ val nonDeferredMessagesCount =
+ (totalMessages * BiometricMessageDeferral.THRESHOLD).toInt() + 1
+ for (i in 0 until nonDeferredMessagesCount) {
+ biometricMessageDeferral.processMessage(4, "non-deferred-msg")
+ }
+ for (i in nonDeferredMessagesCount until totalMessages) {
+ biometricMessageDeferral.processMessage(1, "msgId-1")
+ }
+
+ // THEN there's no deferred message because it didn't meet the threshold
+ assertNull(biometricMessageDeferral.getDeferredMessage())
+ }
+
+ @Test
+ fun testDeferredMessage_manyExcludedMessages_getDeferredMessage() {
+ val biometricMessageDeferral = BiometricMessageDeferral(setOf(3), setOf(1))
+
+ // WHEN more excludedMessages are shown than the deferred message
+ val totalMessages = 10
+ val excludedMessagesCount = (totalMessages * BiometricMessageDeferral.THRESHOLD).toInt() + 1
+ for (i in 0 until excludedMessagesCount) {
+ biometricMessageDeferral.processMessage(3, "excluded-msg")
+ }
+ for (i in excludedMessagesCount until totalMessages) {
+ biometricMessageDeferral.processMessage(1, "msgId-1")
+ }
+
+ // THEN there IS a deferred message because the deferred msg meets the threshold amongst the
+ // non-excluded messages
+ assertEquals("msgId-1", biometricMessageDeferral.getDeferredMessage())
+ }
+
+ @Test
+ fun testResetClearsOutCounts() {
+ val biometricMessageDeferral = BiometricMessageDeferral(setOf(), setOf(1, 2))
+
+ // GIVEN two msgId=1 events processed
+ biometricMessageDeferral.processMessage(1, "msgId-1")
+ biometricMessageDeferral.processMessage(1, "msgId-1")
+
+ // WHEN counts are reset and then a single deferred message is processed (msgId=2)
+ biometricMessageDeferral.reset()
+ biometricMessageDeferral.processMessage(2, "msgId-2")
+
+ // THEN msgId-2 is the deferred message since the two msgId=1 events were reset
+ assertEquals("msgId-2", biometricMessageDeferral.getDeferredMessage())
+ }
+
+ @Test
+ fun testShouldDefer() {
+ // GIVEN should defer msgIds 1 and 2
+ val biometricMessageDeferral = BiometricMessageDeferral(setOf(3), setOf(1, 2))
+
+ // THEN shouldDefer returns true for ids 1 & 2
+ assertTrue(biometricMessageDeferral.shouldDefer(1))
+ assertTrue(biometricMessageDeferral.shouldDefer(2))
+
+ // THEN should defer returns false for ids 3 & 4
+ assertFalse(biometricMessageDeferral.shouldDefer(3))
+ assertFalse(biometricMessageDeferral.shouldDefer(4))
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardUnlockAnimationControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardUnlockAnimationControllerTest.kt
index a4d2238..eecbee5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardUnlockAnimationControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardUnlockAnimationControllerTest.kt
@@ -27,11 +27,11 @@
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor.forClass
import org.mockito.Mock
-import org.mockito.Mockito.`when`
import org.mockito.Mockito.mock
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyNoMoreInteractions
+import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
@RunWith(AndroidTestingRunner::class)
@@ -218,4 +218,18 @@
assertFalse(keyguardUnlockAnimationController.canPerformInWindowLauncherAnimations())
assertFalse(keyguardUnlockAnimationController.isPlayingCannedUnlockAnimation())
}
-}
\ No newline at end of file
+
+ @Test
+ fun playCannedUnlockAnimation_nullSmartspaceView_doesNotThrowExecption() {
+ keyguardUnlockAnimationController.lockscreenSmartspace = null
+ keyguardUnlockAnimationController.willUnlockWithInWindowLauncherAnimations = true
+
+ keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation(
+ remoteAnimationTarget,
+ 0 /* startTime */,
+ false /* requestedShowSurfaceBehindKeyguard */
+ )
+
+ assertTrue(keyguardUnlockAnimationController.isPlayingCannedUnlockAnimation())
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
index 3aa2266..ba1e168 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
@@ -19,6 +19,7 @@
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.common.shared.model.Position
+import com.android.systemui.doze.DozeHost
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.mockito.argumentCaptor
@@ -40,6 +41,7 @@
class KeyguardRepositoryImplTest : SysuiTestCase() {
@Mock private lateinit var statusBarStateController: StatusBarStateController
+ @Mock private lateinit var dozeHost: DozeHost
@Mock private lateinit var keyguardStateController: KeyguardStateController
private lateinit var underTest: KeyguardRepositoryImpl
@@ -48,7 +50,12 @@
fun setUp() {
MockitoAnnotations.initMocks(this)
- underTest = KeyguardRepositoryImpl(statusBarStateController, keyguardStateController)
+ underTest =
+ KeyguardRepositoryImpl(
+ statusBarStateController,
+ keyguardStateController,
+ dozeHost,
+ )
}
@Test
@@ -129,8 +136,8 @@
var latest: Boolean? = null
val job = underTest.isDozing.onEach { latest = it }.launchIn(this)
- val captor = argumentCaptor<StatusBarStateController.StateListener>()
- verify(statusBarStateController).addCallback(captor.capture())
+ val captor = argumentCaptor<DozeHost.Callback>()
+ verify(dozeHost).addCallback(captor.capture())
captor.value.onDozingChanged(true)
assertThat(latest).isTrue()
@@ -139,7 +146,7 @@
assertThat(latest).isFalse()
job.cancel()
- verify(statusBarStateController).removeCallback(captor.value)
+ verify(dozeHost).removeCallback(captor.value)
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest.kt
index 9acd21c..9a91ea91 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest.kt
@@ -51,18 +51,19 @@
@Parameters(
name =
"feature enabled = {0}, has favorites = {1}, has service infos = {2}, can show" +
- " while locked = {3} - expected visible = {4}"
+ " while locked = {3}, visibility is AVAILABLE {4} - expected visible = {5}"
)
@JvmStatic
fun data() =
- (0 until 16)
+ (0 until 32)
.map { combination ->
arrayOf(
- /* isFeatureEnabled= */ combination and 0b1000 != 0,
- /* hasFavorites= */ combination and 0b0100 != 0,
- /* hasServiceInfos= */ combination and 0b0010 != 0,
- /* canShowWhileLocked= */ combination and 0b0001 != 0,
- /* isVisible= */ combination == 0b1111,
+ /* isFeatureEnabled= */ combination and 0b10000 != 0,
+ /* hasFavorites= */ combination and 0b01000 != 0,
+ /* hasServiceInfos= */ combination and 0b00100 != 0,
+ /* canShowWhileLocked= */ combination and 0b00010 != 0,
+ /* visibilityAvailable= */ combination and 0b00001 != 0,
+ /* isVisible= */ combination == 0b11111,
)
}
.toList()
@@ -81,7 +82,8 @@
@JvmField @Parameter(1) var hasFavorites: Boolean = false
@JvmField @Parameter(2) var hasServiceInfos: Boolean = false
@JvmField @Parameter(3) var canShowWhileLocked: Boolean = false
- @JvmField @Parameter(4) var isVisible: Boolean = false
+ @JvmField @Parameter(4) var isVisibilityAvailable: Boolean = false
+ @JvmField @Parameter(5) var isVisibleExpected: Boolean = false
@Before
fun setUp() {
@@ -93,6 +95,14 @@
.thenReturn(Optional.of(controlsListingController))
whenever(component.canShowWhileLockedSetting)
.thenReturn(MutableStateFlow(canShowWhileLocked))
+ whenever(component.getVisibility())
+ .thenReturn(
+ if (isVisibilityAvailable) {
+ ControlsComponent.Visibility.AVAILABLE
+ } else {
+ ControlsComponent.Visibility.UNAVAILABLE
+ }
+ )
underTest =
HomeControlsKeyguardQuickAffordanceConfig(
@@ -128,7 +138,7 @@
assertThat(values.last())
.isInstanceOf(
- if (isVisible) {
+ if (isVisibleExpected) {
KeyguardQuickAffordanceConfig.State.Visible::class.java
} else {
KeyguardQuickAffordanceConfig.State.Hidden::class.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt
index 059487d..dede4ec 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt
@@ -69,6 +69,7 @@
val controlsController = mock<ControlsController>()
whenever(component.getControlsController()).thenReturn(Optional.of(controlsController))
whenever(component.getControlsListingController()).thenReturn(Optional.empty())
+ whenever(component.getVisibility()).thenReturn(ControlsComponent.Visibility.AVAILABLE)
whenever(controlsController.getFavorites()).thenReturn(listOf(mock()))
val values = mutableListOf<KeyguardQuickAffordanceConfig.State>()
@@ -87,6 +88,7 @@
val controlsController = mock<ControlsController>()
whenever(component.getControlsController()).thenReturn(Optional.of(controlsController))
whenever(component.getControlsListingController()).thenReturn(Optional.empty())
+ whenever(component.getVisibility()).thenReturn(ControlsComponent.Visibility.AVAILABLE)
whenever(controlsController.getFavorites()).thenReturn(listOf(mock()))
val values = mutableListOf<KeyguardQuickAffordanceConfig.State>()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/usecase/KeyguardQuickAffordanceInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/usecase/KeyguardQuickAffordanceInteractorTest.kt
index d3fc29f..19d8412 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/usecase/KeyguardQuickAffordanceInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/usecase/KeyguardQuickAffordanceInteractorTest.kt
@@ -36,6 +36,7 @@
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.test.runBlockingTest
+import kotlinx.coroutines.yield
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -110,6 +111,10 @@
.quickAffordance(KeyguardQuickAffordancePosition.BOTTOM_START)
.onEach { latest = it }
.launchIn(this)
+ // The interactor has an onStart { emit(Hidden) } to cover for upstream configs that don't
+ // produce an initial value. We yield to give the coroutine time to emit the first real
+ // value from our config.
+ yield()
assertThat(latest).isInstanceOf(KeyguardQuickAffordanceModel.Visible::class.java)
val visibleModel = latest as KeyguardQuickAffordanceModel.Visible
@@ -136,6 +141,10 @@
.quickAffordance(KeyguardQuickAffordancePosition.BOTTOM_END)
.onEach { latest = it }
.launchIn(this)
+ // The interactor has an onStart { emit(Hidden) } to cover for upstream configs that don't
+ // produce an initial value. We yield to give the coroutine time to emit the first real
+ // value from our config.
+ yield()
assertThat(latest).isInstanceOf(KeyguardQuickAffordanceModel.Visible::class.java)
val visibleModel = latest as KeyguardQuickAffordanceModel.Visible
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
index 14b85b8..c612091 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
@@ -224,7 +224,10 @@
repository.setAnimateDozingTransitions(false)
yield()
- assertThat(values).isEqualTo(listOf(false, true, false))
+ // Note the extra false value in the beginning. This is to cover for the initial value
+ // inserted by the quick affordance interactor which it does to cover for config
+ // implementations that don't emit an initial value.
+ assertThat(values).isEqualTo(listOf(false, false, true, false))
job.cancel()
}
@@ -372,6 +375,10 @@
var latest: KeyguardQuickAffordanceViewModel? = null
val job = underTest.startButton.onEach { latest = it }.launchIn(this)
+ // The interactor has an onStart { emit(Hidden) } to cover for upstream configs that don't
+ // produce an initial value. We yield to give the coroutine time to emit the first real
+ // value from our config.
+ yield()
assertQuickAffordanceViewModel(
viewModel = latest,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt
index 219b3c8..5a50a9f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt
@@ -28,18 +28,24 @@
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider
import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.util.animation.TransitionLayout
import com.android.systemui.util.concurrency.DelayableExecutor
+import com.android.systemui.util.mockito.capture
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.time.FakeSystemClock
+import javax.inject.Provider
import junit.framework.Assert.assertEquals
import junit.framework.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.Captor
import org.mockito.Mock
import org.mockito.Mockito.verify
+import org.mockito.Mockito.verifyNoMoreInteractions
+import org.mockito.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations
-import javax.inject.Provider
private val DATA = MediaTestUtils.emptyMediaData
@@ -64,6 +70,14 @@
@Mock lateinit var dumpManager: DumpManager
@Mock lateinit var logger: MediaUiEventLogger
@Mock lateinit var debugLogger: MediaCarouselControllerLogger
+ @Mock lateinit var mediaViewHolder: MediaViewHolder
+ @Mock lateinit var player: TransitionLayout
+ @Mock lateinit var recommendationViewHolder: RecommendationViewHolder
+ @Mock lateinit var recommendations: TransitionLayout
+ @Mock lateinit var mediaPlayer: MediaControlPanel
+ @Mock lateinit var mediaViewController: MediaViewController
+ @Mock lateinit var smartspaceMediaData: SmartspaceMediaData
+ @Captor lateinit var listener: ArgumentCaptor<MediaDataManager.Listener>
private val clock = FakeSystemClock()
private lateinit var mediaCarouselController: MediaCarouselController
@@ -87,7 +101,10 @@
logger,
debugLogger
)
-
+ verify(mediaDataManager).addListener(capture(listener))
+ whenever(mediaControlPanelFactory.get()).thenReturn(mediaPlayer)
+ whenever(mediaPlayer.mediaViewController).thenReturn(mediaViewController)
+ whenever(mediaDataManager.smartspaceMediaData).thenReturn(smartspaceMediaData)
MediaPlayerData.clear()
}
@@ -258,4 +275,103 @@
verify(logger).logRecommendationRemoved(eq(packageName), eq(instanceId!!))
}
-}
\ No newline at end of file
+
+ @Test
+ fun testSetSquishinessFractionForMedia_setPlayerBottom() {
+ whenever(panel.mediaViewHolder).thenReturn(mediaViewHolder)
+ whenever(mediaViewHolder.player).thenReturn(player)
+ whenever(player.measuredHeight).thenReturn(100)
+
+ val playingLocal = Triple("playing local",
+ DATA.copy(active = true, isPlaying = true,
+ playbackLocation = MediaData.PLAYBACK_LOCAL, resumption = false),
+ 4500L)
+ MediaPlayerData.addMediaPlayer(playingLocal.first, playingLocal.second, panel, clock,
+ false, debugLogger)
+
+ mediaCarouselController.squishinessFraction = 0.0f
+ verify(player).bottom = 50
+ verifyNoMoreInteractions(recommendationViewHolder)
+
+ mediaCarouselController.squishinessFraction = 0.5f
+ verify(player).bottom = 75
+ verifyNoMoreInteractions(recommendationViewHolder)
+ }
+
+ @Test
+ fun testSetSquishinessFractionForRecommendation_setPlayerBottom() {
+ whenever(panel.recommendationViewHolder).thenReturn(recommendationViewHolder)
+ whenever(recommendationViewHolder.recommendations).thenReturn(recommendations)
+ whenever(recommendations.measuredHeight).thenReturn(100)
+
+ MediaPlayerData.addMediaRecommendation(SMARTSPACE_KEY, EMPTY_SMARTSPACE_MEDIA_DATA, panel,
+ false, clock)
+
+ mediaCarouselController.squishinessFraction = 0.0f
+ verifyNoMoreInteractions(mediaViewHolder)
+ verify(recommendationViewHolder.recommendations).bottom = 50
+
+ mediaCarouselController.squishinessFraction = 0.5f
+ verifyNoMoreInteractions(mediaViewHolder)
+ verify(recommendationViewHolder.recommendations).bottom = 75
+ }
+
+ fun testMediaLoaded_ScrollToActivePlayer() {
+ listener.value.onMediaDataLoaded("playing local",
+ null,
+ DATA.copy(active = true, isPlaying = true,
+ playbackLocation = MediaData.PLAYBACK_LOCAL, resumption = false)
+ )
+ listener.value.onMediaDataLoaded("paused local",
+ null,
+ DATA.copy(active = true, isPlaying = false,
+ playbackLocation = MediaData.PLAYBACK_LOCAL, resumption = false))
+ // adding a media recommendation card.
+ MediaPlayerData.addMediaRecommendation(SMARTSPACE_KEY, EMPTY_SMARTSPACE_MEDIA_DATA, panel,
+ false, clock)
+ mediaCarouselController.shouldScrollToActivePlayer = true
+ // switching between media players.
+ listener.value.onMediaDataLoaded("playing local",
+ "playing local",
+ DATA.copy(active = true, isPlaying = false,
+ playbackLocation = MediaData.PLAYBACK_LOCAL, resumption = true)
+ )
+ listener.value.onMediaDataLoaded("paused local",
+ "paused local",
+ DATA.copy(active = true, isPlaying = true,
+ playbackLocation = MediaData.PLAYBACK_LOCAL, resumption = false))
+
+ assertEquals(
+ MediaPlayerData.getMediaPlayerIndex("paused local"),
+ mediaCarouselController.mediaCarouselScrollHandler.visibleMediaIndex
+ )
+ }
+
+ @Test
+ fun testMediaLoadedFromRecommendationCard_ScrollToActivePlayer() {
+ MediaPlayerData.addMediaRecommendation(SMARTSPACE_KEY, EMPTY_SMARTSPACE_MEDIA_DATA, panel,
+ false, clock)
+ listener.value.onMediaDataLoaded("playing local",
+ null,
+ DATA.copy(active = true, isPlaying = true,
+ playbackLocation = MediaData.PLAYBACK_LOCAL, resumption = false)
+ )
+
+ var playerIndex = MediaPlayerData.getMediaPlayerIndex("playing local")
+ assertEquals(
+ playerIndex,
+ mediaCarouselController.mediaCarouselScrollHandler.visibleMediaIndex
+ )
+ assertEquals( playerIndex, 0)
+
+ // Replaying the same media player one more time.
+ // And check that the card stays in its position.
+ listener.value.onMediaDataLoaded("playing local",
+ null,
+ DATA.copy(active = true, isPlaying = true,
+ playbackLocation = MediaData.PLAYBACK_LOCAL, resumption = false)
+ )
+ playerIndex = MediaPlayerData.getMediaPlayerIndex("playing local")
+ assertEquals(playerIndex, 0)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt
index 18bfd04..954b438 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt
@@ -29,6 +29,7 @@
import com.android.systemui.controls.controller.ControlsControllerImplTest.Companion.eq
import com.android.systemui.dreams.DreamOverlayStateController
import com.android.systemui.keyguard.WakefulnessLifecycle
+import com.android.systemui.media.dream.MediaDreamComplication
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.shade.testing.FakeNotifPanelEvents
import com.android.systemui.statusbar.StatusBarState
@@ -38,6 +39,8 @@
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.animation.UniqueObjectHostView
import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.nullable
import com.android.systemui.util.settings.FakeSettings
import com.android.systemui.utils.os.FakeHandler
import com.google.common.truth.Truth.assertThat
@@ -79,6 +82,9 @@
private lateinit var wakefullnessObserver: ArgumentCaptor<(WakefulnessLifecycle.Observer)>
@Captor
private lateinit var statusBarCallback: ArgumentCaptor<(StatusBarStateController.StateListener)>
+ @Captor
+ private lateinit var dreamOverlayCallback:
+ ArgumentCaptor<(DreamOverlayStateController.Callback)>
@JvmField
@Rule
val mockito = MockitoJUnit.rule()
@@ -113,6 +119,7 @@
fakeHandler,)
verify(wakefulnessLifecycle).addObserver(wakefullnessObserver.capture())
verify(statusBarStateController).addCallback(statusBarCallback.capture())
+ verify(dreamOverlayStateController).addCallback(dreamOverlayCallback.capture())
setupHost(lockHost, MediaHierarchyManager.LOCATION_LOCKSCREEN, LOCKSCREEN_TOP)
setupHost(qsHost, MediaHierarchyManager.LOCATION_QS, QS_TOP)
setupHost(qqsHost, MediaHierarchyManager.LOCATION_QQS, QQS_TOP)
@@ -332,6 +339,27 @@
assertThat(mediaHierarchyManager.isCurrentlyInGuidedTransformation()).isFalse()
}
+ @Test
+ fun testDream() {
+ goToDream()
+ setMediaDreamComplicationEnabled(true)
+ verify(mediaCarouselController).onDesiredLocationChanged(
+ eq(MediaHierarchyManager.LOCATION_DREAM_OVERLAY),
+ nullable(),
+ eq(false),
+ anyLong(),
+ anyLong())
+ clearInvocations(mediaCarouselController)
+
+ setMediaDreamComplicationEnabled(false)
+ verify(mediaCarouselController).onDesiredLocationChanged(
+ eq(MediaHierarchyManager.LOCATION_QQS),
+ any(MediaHostState::class.java),
+ eq(false),
+ anyLong(),
+ anyLong())
+ }
+
private fun enableSplitShade() {
context.getOrCreateTestableResources().addOverride(
R.bool.config_use_split_notification_shade, true
@@ -343,6 +371,8 @@
whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)
settings.putInt(Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN, 1)
statusBarCallback.value.onStatePreChange(StatusBarState.SHADE, StatusBarState.KEYGUARD)
+ whenever(dreamOverlayStateController.isOverlayActive).thenReturn(false)
+ dreamOverlayCallback.value.onStateChanged()
clearInvocations(mediaCarouselController)
}
@@ -354,6 +384,17 @@
)
}
+ private fun goToDream() {
+ whenever(dreamOverlayStateController.isOverlayActive).thenReturn(true)
+ dreamOverlayCallback.value.onStateChanged()
+ }
+
+ private fun setMediaDreamComplicationEnabled(enabled: Boolean) {
+ val complications = if (enabled) listOf(mock<MediaDreamComplication>()) else emptyList()
+ whenever(dreamOverlayStateController.complications).thenReturn(complications)
+ dreamOverlayCallback.value.onComplicationsChanged()
+ }
+
private fun expandQS() {
mediaHierarchyManager.qsExpansion = 1.0f
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dream/MediaDreamSentinelTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dream/MediaDreamSentinelTest.java
index 2e864dc..0bfc034 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dream/MediaDreamSentinelTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dream/MediaDreamSentinelTest.java
@@ -72,13 +72,13 @@
}
@Test
- public void testComplicationAddition() {
+ public void testOnMediaDataLoaded_complicationAddition() {
final MediaDreamSentinel sentinel = new MediaDreamSentinel(mContext, mMediaDataManager,
mDreamOverlayStateController, mMediaEntryComplication, mFeatureFlags);
-
sentinel.start();
final MediaDataManager.Listener listener = captureMediaDataListener();
+
when(mMediaDataManager.hasActiveMedia()).thenReturn(false);
listener.onMediaDataLoaded(mKey, mOldKey, mData, /* immediately= */ true,
/* receivedSmartspaceCardLatency= */ 0, /* isSsReactived= */ false);
@@ -90,6 +90,19 @@
verify(mDreamOverlayStateController).addComplication(eq(mMediaEntryComplication));
verify(mDreamOverlayStateController, never()).addComplication(
not(eq(mMediaEntryComplication)));
+ }
+
+ @Test
+ public void testOnMediaDataRemoved_complicationRemoval() {
+ final MediaDreamSentinel sentinel = new MediaDreamSentinel(mContext, mMediaDataManager,
+ mDreamOverlayStateController, mMediaEntryComplication, mFeatureFlags);
+ sentinel.start();
+
+ final MediaDataManager.Listener listener = captureMediaDataListener();
+
+ when(mMediaDataManager.hasActiveMedia()).thenReturn(true);
+ listener.onMediaDataLoaded(mKey, mOldKey, mData, /* immediately= */true,
+ /* receivedSmartspaceCardLatency= */0, /* isSsReactived= */ false);
listener.onMediaDataRemoved(mKey);
verify(mDreamOverlayStateController, never()).removeComplication(any());
@@ -100,7 +113,30 @@
}
@Test
- public void testMediaDreamSentinel_mediaComplicationDisabled_doNotAddComplication() {
+ public void testOnMediaDataLoaded_complicationRemoval() {
+ final MediaDreamSentinel sentinel = new MediaDreamSentinel(mContext, mMediaDataManager,
+ mDreamOverlayStateController, mMediaEntryComplication, mFeatureFlags);
+ sentinel.start();
+
+ final MediaDataManager.Listener listener = captureMediaDataListener();
+
+ when(mMediaDataManager.hasActiveMedia()).thenReturn(true);
+ listener.onMediaDataLoaded(mKey, mOldKey, mData, /* immediately= */true,
+ /* receivedSmartspaceCardLatency= */0, /* isSsReactived= */ false);
+ verify(mDreamOverlayStateController, never()).removeComplication(any());
+
+ listener.onMediaDataLoaded(mKey, mOldKey, mData, /* immediately= */true,
+ /* receivedSmartspaceCardLatency= */0, /* isSsReactived= */ false);
+ verify(mDreamOverlayStateController, never()).removeComplication(any());
+
+ when(mMediaDataManager.hasActiveMedia()).thenReturn(false);
+ listener.onMediaDataLoaded(mKey, mOldKey, mData, /* immediately= */true,
+ /* receivedSmartspaceCardLatency= */0, /* isSsReactived= */ false);
+ verify(mDreamOverlayStateController).removeComplication(eq(mMediaEntryComplication));
+ }
+
+ @Test
+ public void testOnMediaDataLoaded_mediaComplicationDisabled_doesNotAddComplication() {
when(mFeatureFlags.isEnabled(MEDIA_DREAM_COMPLICATION)).thenReturn(false);
final MediaDreamSentinel sentinel = new MediaDreamSentinel(mContext, mMediaDataManager,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt
index 171d893..e7b4593 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt
@@ -41,7 +41,6 @@
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.time.FakeSystemClock
-import com.android.systemui.util.view.ViewUtil
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
@@ -74,8 +73,6 @@
@Mock
private lateinit var windowManager: WindowManager
@Mock
- private lateinit var viewUtil: ViewUtil
- @Mock
private lateinit var commandQueue: CommandQueue
private lateinit var commandQueueCallback: CommandQueue.Callbacks
private lateinit var fakeAppIconDrawable: Drawable
@@ -102,7 +99,6 @@
context,
logger,
windowManager,
- viewUtil,
FakeExecutor(FakeSystemClock()),
accessibilityManager,
configurationController,
@@ -182,7 +178,7 @@
@Test
fun setIcon_isAppIcon_usesAppIconSize() {
- controllerReceiver.displayChip(getChipReceiverInfo())
+ controllerReceiver.displayView(getChipReceiverInfo())
val chipView = getChipView()
controllerReceiver.setIcon(chipView, PACKAGE_NAME)
@@ -198,7 +194,7 @@
@Test
fun setIcon_notAppIcon_usesGenericIconSize() {
- controllerReceiver.displayChip(getChipReceiverInfo())
+ controllerReceiver.displayView(getChipReceiverInfo())
val chipView = getChipView()
controllerReceiver.setIcon(chipView, appPackageName = null)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt
index 1061e3c..52b6eed 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt
@@ -42,7 +42,6 @@
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.time.FakeSystemClock
-import com.android.systemui.util.view.ViewUtil
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
@@ -51,8 +50,8 @@
import org.mockito.Mock
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
-import org.mockito.MockitoAnnotations
import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
@SmallTest
@RunWith(AndroidTestingRunner::class)
@@ -75,8 +74,6 @@
@Mock
private lateinit var windowManager: WindowManager
@Mock
- private lateinit var viewUtil: ViewUtil
- @Mock
private lateinit var commandQueue: CommandQueue
private lateinit var commandQueueCallback: CommandQueue.Callbacks
private lateinit var fakeAppIconDrawable: Drawable
@@ -110,7 +107,6 @@
context,
logger,
windowManager,
- viewUtil,
fakeExecutor,
accessibilityManager,
configurationController,
@@ -309,7 +305,7 @@
@Test
fun almostCloseToStartCast_appIcon_deviceName_noLoadingIcon_noUndo_noFailureIcon() {
val state = almostCloseToStartCast()
- controllerSender.displayChip(state)
+ controllerSender.displayView(state)
val chipView = getChipView()
assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable)
@@ -325,7 +321,7 @@
@Test
fun almostCloseToEndCast_appIcon_deviceName_noLoadingIcon_noUndo_noFailureIcon() {
val state = almostCloseToEndCast()
- controllerSender.displayChip(state)
+ controllerSender.displayView(state)
val chipView = getChipView()
assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable)
@@ -341,7 +337,7 @@
@Test
fun transferToReceiverTriggered_appIcon_loadingIcon_noUndo_noFailureIcon() {
val state = transferToReceiverTriggered()
- controllerSender.displayChip(state)
+ controllerSender.displayView(state)
val chipView = getChipView()
assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable)
@@ -357,7 +353,7 @@
@Test
fun transferToThisDeviceTriggered_appIcon_loadingIcon_noUndo_noFailureIcon() {
val state = transferToThisDeviceTriggered()
- controllerSender.displayChip(state)
+ controllerSender.displayView(state)
val chipView = getChipView()
assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable)
@@ -373,7 +369,7 @@
@Test
fun transferToReceiverSucceeded_appIcon_deviceName_noLoadingIcon_noFailureIcon() {
val state = transferToReceiverSucceeded()
- controllerSender.displayChip(state)
+ controllerSender.displayView(state)
val chipView = getChipView()
assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable)
@@ -387,7 +383,7 @@
@Test
fun transferToReceiverSucceeded_nullUndoRunnable_noUndo() {
- controllerSender.displayChip(transferToReceiverSucceeded(undoCallback = null))
+ controllerSender.displayView(transferToReceiverSucceeded(undoCallback = null))
val chipView = getChipView()
assertThat(chipView.getUndoButton().visibility).isEqualTo(View.GONE)
@@ -398,7 +394,7 @@
val undoCallback = object : IUndoMediaTransferCallback.Stub() {
override fun onUndoTriggered() {}
}
- controllerSender.displayChip(transferToReceiverSucceeded(undoCallback))
+ controllerSender.displayView(transferToReceiverSucceeded(undoCallback))
val chipView = getChipView()
assertThat(chipView.getUndoButton().visibility).isEqualTo(View.VISIBLE)
@@ -414,7 +410,7 @@
}
}
- controllerSender.displayChip(transferToReceiverSucceeded(undoCallback))
+ controllerSender.displayView(transferToReceiverSucceeded(undoCallback))
getChipView().getUndoButton().performClick()
assertThat(undoCallbackCalled).isTrue()
@@ -425,7 +421,7 @@
val undoCallback = object : IUndoMediaTransferCallback.Stub() {
override fun onUndoTriggered() {}
}
- controllerSender.displayChip(transferToReceiverSucceeded(undoCallback))
+ controllerSender.displayView(transferToReceiverSucceeded(undoCallback))
getChipView().getUndoButton().performClick()
@@ -440,7 +436,7 @@
@Test
fun transferToThisDeviceSucceeded_appIcon_deviceName_noLoadingIcon_noFailureIcon() {
val state = transferToThisDeviceSucceeded()
- controllerSender.displayChip(state)
+ controllerSender.displayView(state)
val chipView = getChipView()
assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable)
@@ -454,7 +450,7 @@
@Test
fun transferToThisDeviceSucceeded_nullUndoRunnable_noUndo() {
- controllerSender.displayChip(transferToThisDeviceSucceeded(undoCallback = null))
+ controllerSender.displayView(transferToThisDeviceSucceeded(undoCallback = null))
val chipView = getChipView()
assertThat(chipView.getUndoButton().visibility).isEqualTo(View.GONE)
@@ -465,7 +461,7 @@
val undoCallback = object : IUndoMediaTransferCallback.Stub() {
override fun onUndoTriggered() {}
}
- controllerSender.displayChip(transferToThisDeviceSucceeded(undoCallback))
+ controllerSender.displayView(transferToThisDeviceSucceeded(undoCallback))
val chipView = getChipView()
assertThat(chipView.getUndoButton().visibility).isEqualTo(View.VISIBLE)
@@ -481,7 +477,7 @@
}
}
- controllerSender.displayChip(transferToThisDeviceSucceeded(undoCallback))
+ controllerSender.displayView(transferToThisDeviceSucceeded(undoCallback))
getChipView().getUndoButton().performClick()
assertThat(undoCallbackCalled).isTrue()
@@ -492,7 +488,7 @@
val undoCallback = object : IUndoMediaTransferCallback.Stub() {
override fun onUndoTriggered() {}
}
- controllerSender.displayChip(transferToThisDeviceSucceeded(undoCallback))
+ controllerSender.displayView(transferToThisDeviceSucceeded(undoCallback))
getChipView().getUndoButton().performClick()
@@ -507,7 +503,7 @@
@Test
fun transferToReceiverFailed_appIcon_noDeviceName_noLoadingIcon_noUndo_failureIcon() {
val state = transferToReceiverFailed()
- controllerSender.displayChip(state)
+ controllerSender.displayView(state)
val chipView = getChipView()
assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable)
@@ -523,7 +519,7 @@
@Test
fun transferToThisDeviceFailed_appIcon_noDeviceName_noLoadingIcon_noUndo_failureIcon() {
val state = transferToThisDeviceFailed()
- controllerSender.displayChip(state)
+ controllerSender.displayView(state)
val chipView = getChipView()
assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable)
@@ -538,24 +534,24 @@
@Test
fun changeFromAlmostCloseToStartToTransferTriggered_loadingIconAppears() {
- controllerSender.displayChip(almostCloseToStartCast())
- controllerSender.displayChip(transferToReceiverTriggered())
+ controllerSender.displayView(almostCloseToStartCast())
+ controllerSender.displayView(transferToReceiverTriggered())
assertThat(getChipView().getLoadingIconVisibility()).isEqualTo(View.VISIBLE)
}
@Test
fun changeFromTransferTriggeredToTransferSucceeded_loadingIconDisappears() {
- controllerSender.displayChip(transferToReceiverTriggered())
- controllerSender.displayChip(transferToReceiverSucceeded())
+ controllerSender.displayView(transferToReceiverTriggered())
+ controllerSender.displayView(transferToReceiverSucceeded())
assertThat(getChipView().getLoadingIconVisibility()).isEqualTo(View.GONE)
}
@Test
fun changeFromTransferTriggeredToTransferSucceeded_undoButtonAppears() {
- controllerSender.displayChip(transferToReceiverTriggered())
- controllerSender.displayChip(
+ controllerSender.displayView(transferToReceiverTriggered())
+ controllerSender.displayView(
transferToReceiverSucceeded(
object : IUndoMediaTransferCallback.Stub() {
override fun onUndoTriggered() {}
@@ -568,26 +564,26 @@
@Test
fun changeFromTransferSucceededToAlmostCloseToStart_undoButtonDisappears() {
- controllerSender.displayChip(transferToReceiverSucceeded())
- controllerSender.displayChip(almostCloseToStartCast())
+ controllerSender.displayView(transferToReceiverSucceeded())
+ controllerSender.displayView(almostCloseToStartCast())
assertThat(getChipView().getUndoButton().visibility).isEqualTo(View.GONE)
}
@Test
fun changeFromTransferTriggeredToTransferFailed_failureIconAppears() {
- controllerSender.displayChip(transferToReceiverTriggered())
- controllerSender.displayChip(transferToReceiverFailed())
+ controllerSender.displayView(transferToReceiverTriggered())
+ controllerSender.displayView(transferToReceiverFailed())
assertThat(getChipView().getFailureIcon().visibility).isEqualTo(View.VISIBLE)
}
@Test
- fun transferToReceiverTriggeredThenRemoveChip_chipStillDisplayed() {
- controllerSender.displayChip(transferToReceiverTriggered())
+ fun transferToReceiverTriggeredThenRemoveView_viewStillDisplayed() {
+ controllerSender.displayView(transferToReceiverTriggered())
fakeClock.advanceTime(1000L)
- controllerSender.removeChip("fakeRemovalReason")
+ controllerSender.removeView("fakeRemovalReason")
fakeExecutor.runAllReady()
verify(windowManager, never()).removeView(any())
@@ -596,9 +592,9 @@
@Test
fun transferToReceiverTriggeredThenFarFromReceiver_eventuallyTimesOut() {
val state = transferToReceiverTriggered()
- controllerSender.displayChip(state)
+ controllerSender.displayView(state)
fakeClock.advanceTime(1000L)
- controllerSender.removeChip("fakeRemovalReason")
+ controllerSender.removeView("fakeRemovalReason")
fakeClock.advanceTime(TIMEOUT + 1L)
@@ -606,11 +602,11 @@
}
@Test
- fun transferToThisDeviceTriggeredThenRemoveChip_chipStillDisplayed() {
- controllerSender.displayChip(transferToThisDeviceTriggered())
+ fun transferToThisDeviceTriggeredThenRemoveView_viewStillDisplayed() {
+ controllerSender.displayView(transferToThisDeviceTriggered())
fakeClock.advanceTime(1000L)
- controllerSender.removeChip("fakeRemovalReason")
+ controllerSender.removeView("fakeRemovalReason")
fakeExecutor.runAllReady()
verify(windowManager, never()).removeView(any())
@@ -619,9 +615,9 @@
@Test
fun transferToThisDeviceTriggeredThenFarFromReceiver_eventuallyTimesOut() {
val state = transferToThisDeviceTriggered()
- controllerSender.displayChip(state)
+ controllerSender.displayView(state)
fakeClock.advanceTime(1000L)
- controllerSender.removeChip("fakeRemovalReason")
+ controllerSender.removeView("fakeRemovalReason")
fakeClock.advanceTime(TIMEOUT + 1L)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/data/repository/PowerRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/power/data/repository/PowerRepositoryImplTest.kt
new file mode 100644
index 0000000..249a91b
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/power/data/repository/PowerRepositoryImplTest.kt
@@ -0,0 +1,181 @@
+/*
+ * 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.power.data.repository
+
+import android.content.BroadcastReceiver
+import android.content.Intent
+import android.content.IntentFilter
+import android.os.PowerManager
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.util.mockito.capture
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.runBlocking
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.ArgumentCaptor
+import org.mockito.Captor
+import org.mockito.Mock
+import org.mockito.Mockito.anyInt
+import org.mockito.Mockito.isNull
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(JUnit4::class)
+class PowerRepositoryImplTest : SysuiTestCase() {
+
+ @Mock private lateinit var manager: PowerManager
+ @Mock private lateinit var dispatcher: BroadcastDispatcher
+ @Captor private lateinit var receiverCaptor: ArgumentCaptor<BroadcastReceiver>
+ @Captor private lateinit var filterCaptor: ArgumentCaptor<IntentFilter>
+
+ private lateinit var underTest: PowerRepositoryImpl
+
+ private var isInteractive = true
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ isInteractive = true
+ whenever(manager.isInteractive).then { isInteractive }
+
+ underTest = PowerRepositoryImpl(manager = manager, dispatcher = dispatcher)
+ }
+
+ @Test
+ fun `isInteractive - registers for broadcasts`() =
+ runBlocking(IMMEDIATE) {
+ val job = underTest.isInteractive.onEach {}.launchIn(this)
+
+ verifyRegistered()
+ assertThat(filterCaptor.value.hasAction(Intent.ACTION_SCREEN_ON)).isTrue()
+ assertThat(filterCaptor.value.hasAction(Intent.ACTION_SCREEN_OFF)).isTrue()
+
+ job.cancel()
+ }
+
+ @Test
+ fun `isInteractive - unregisters from broadcasts`() =
+ runBlocking(IMMEDIATE) {
+ val job = underTest.isInteractive.onEach {}.launchIn(this)
+ verifyRegistered()
+
+ job.cancel()
+
+ verify(dispatcher).unregisterReceiver(receiverCaptor.value)
+ }
+
+ @Test
+ fun `isInteractive - emits initial true value if screen was on`() =
+ runBlocking(IMMEDIATE) {
+ isInteractive = true
+ var value: Boolean? = null
+ val job = underTest.isInteractive.onEach { value = it }.launchIn(this)
+
+ verifyRegistered()
+
+ assertThat(value).isTrue()
+ job.cancel()
+ }
+
+ @Test
+ fun `isInteractive - emits initial false value if screen was off`() =
+ runBlocking(IMMEDIATE) {
+ isInteractive = false
+ var value: Boolean? = null
+ val job = underTest.isInteractive.onEach { value = it }.launchIn(this)
+
+ verifyRegistered()
+
+ assertThat(value).isFalse()
+ job.cancel()
+ }
+
+ @Test
+ fun `isInteractive - emits true when the screen turns on`() =
+ runBlocking(IMMEDIATE) {
+ var value: Boolean? = null
+ val job = underTest.isInteractive.onEach { value = it }.launchIn(this)
+ verifyRegistered()
+
+ isInteractive = true
+ receiverCaptor.value.onReceive(context, Intent(Intent.ACTION_SCREEN_ON))
+
+ assertThat(value).isTrue()
+ job.cancel()
+ }
+
+ @Test
+ fun `isInteractive - emits false when the screen turns off`() =
+ runBlocking(IMMEDIATE) {
+ var value: Boolean? = null
+ val job = underTest.isInteractive.onEach { value = it }.launchIn(this)
+ verifyRegistered()
+
+ isInteractive = false
+ receiverCaptor.value.onReceive(context, Intent(Intent.ACTION_SCREEN_OFF))
+
+ assertThat(value).isFalse()
+ job.cancel()
+ }
+
+ @Test
+ fun `isInteractive - emits correctly over time`() =
+ runBlocking(IMMEDIATE) {
+ val values = mutableListOf<Boolean>()
+ val job = underTest.isInteractive.onEach(values::add).launchIn(this)
+ verifyRegistered()
+
+ isInteractive = false
+ receiverCaptor.value.onReceive(context, Intent(Intent.ACTION_SCREEN_OFF))
+ isInteractive = true
+ receiverCaptor.value.onReceive(context, Intent(Intent.ACTION_SCREEN_ON))
+ isInteractive = false
+ receiverCaptor.value.onReceive(context, Intent(Intent.ACTION_SCREEN_OFF))
+
+ assertThat(values).isEqualTo(listOf(true, false, true, false))
+ job.cancel()
+ }
+
+ private fun verifyRegistered() {
+ // We must verify with all arguments, even those that are optional because they have default
+ // values because Mockito is forcing us to. Once we can use mockito-kotlin, we should be
+ // able to remove this.
+ verify(dispatcher)
+ .registerReceiver(
+ capture(receiverCaptor),
+ capture(filterCaptor),
+ isNull(),
+ isNull(),
+ anyInt(),
+ isNull(),
+ )
+ }
+
+ companion object {
+ private val IMMEDIATE = Dispatchers.Main.immediate
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/domain/interactor/PowerInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/power/domain/interactor/PowerInteractorTest.kt
new file mode 100644
index 0000000..bf6a37e
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/power/domain/interactor/PowerInteractorTest.kt
@@ -0,0 +1,78 @@
+/*
+ * 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.power.domain.interactor
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.power.data.repository.FakePowerRepository
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.runBlocking
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@SmallTest
+@RunWith(JUnit4::class)
+class PowerInteractorTest : SysuiTestCase() {
+
+ private lateinit var underTest: PowerInteractor
+ private lateinit var repository: FakePowerRepository
+
+ @Before
+ fun setUp() {
+ repository =
+ FakePowerRepository(
+ initialInteractive = true,
+ )
+ underTest = PowerInteractor(repository = repository)
+ }
+
+ @Test
+ fun `isInteractive - screen turns off`() =
+ runBlocking(IMMEDIATE) {
+ repository.setInteractive(true)
+ var value: Boolean? = null
+ val job = underTest.isInteractive.onEach { value = it }.launchIn(this)
+
+ repository.setInteractive(false)
+
+ assertThat(value).isFalse()
+ job.cancel()
+ }
+
+ @Test
+ fun `isInteractive - becomes interactive`() =
+ runBlocking(IMMEDIATE) {
+ repository.setInteractive(false)
+ var value: Boolean? = null
+ val job = underTest.isInteractive.onEach { value = it }.launchIn(this)
+
+ repository.setInteractive(true)
+
+ assertThat(value).isTrue()
+ job.cancel()
+ }
+
+ companion object {
+ private val IMMEDIATE = Dispatchers.Main.immediate
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
index f08ad24..5d5918d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
@@ -94,6 +94,7 @@
@Mock private QSPanel.QSTileLayout mQQsTileLayout;
@Mock private QSAnimator mQSAnimator;
@Mock private StatusBarStateController mStatusBarStateController;
+ @Mock private QSSquishinessController mSquishinessController;
private View mQsFragmentView;
public QSFragmentTest() {
@@ -139,13 +140,15 @@
}
@Test
- public void transitionToFullShade_inSplitShade_setsAlphaBasedOnProgress() {
+ public void transitionToFullShade_setsAlphaUsingShadeInterpolator() {
QSFragment fragment = resumeAndGetFragment();
- enableSplitShade();
- int transitionPxAmount = 123;
+ setStatusBarState(StatusBarState.SHADE);
+ boolean isTransitioningToFullShade = true;
float transitionProgress = 0.5f;
+ float squishinessFraction = 0.5f;
- fragment.setTransitionToFullShadeAmount(transitionPxAmount, transitionProgress);
+ fragment.setTransitionToFullShadeProgress(isTransitioningToFullShade, transitionProgress,
+ squishinessFraction);
assertThat(mQsFragmentView.getAlpha())
.isEqualTo(ShadeInterpolation.getContentAlpha(transitionProgress));
@@ -153,31 +156,32 @@
@Test
public void
- transitionToFullShade_inSplitShade_onKeyguard_bouncerNotActive_usesShadeInterpolator() {
+ transitionToFullShade_onKeyguard_noBouncer_setsAlphaUsingLinearInterpolator() {
QSFragment fragment = resumeAndGetFragment();
- enableSplitShade();
setStatusBarState(StatusBarState.KEYGUARD);
when(mQSPanelController.isBouncerInTransit()).thenReturn(false);
- int transitionPxAmount = 123;
+ boolean isTransitioningToFullShade = true;
float transitionProgress = 0.5f;
+ float squishinessFraction = 0.5f;
- fragment.setTransitionToFullShadeAmount(transitionPxAmount, transitionProgress);
+ fragment.setTransitionToFullShadeProgress(isTransitioningToFullShade, transitionProgress,
+ squishinessFraction);
- assertThat(mQsFragmentView.getAlpha())
- .isEqualTo(ShadeInterpolation.getContentAlpha(transitionProgress));
+ assertThat(mQsFragmentView.getAlpha()).isEqualTo(transitionProgress);
}
@Test
public void
- transitionToFullShade_inSplitShade_onKeyguard_bouncerActive_usesBouncerInterpolator() {
+ transitionToFullShade_onKeyguard_bouncerActive_setsAlphaUsingBouncerInterpolator() {
QSFragment fragment = resumeAndGetFragment();
- enableSplitShade();
setStatusBarState(StatusBarState.KEYGUARD);
when(mQSPanelController.isBouncerInTransit()).thenReturn(true);
- int transitionPxAmount = 123;
+ boolean isTransitioningToFullShade = true;
float transitionProgress = 0.5f;
+ float squishinessFraction = 0.5f;
- fragment.setTransitionToFullShadeAmount(transitionPxAmount, transitionProgress);
+ fragment.setTransitionToFullShadeProgress(isTransitioningToFullShade, transitionProgress,
+ squishinessFraction);
assertThat(mQsFragmentView.getAlpha())
.isEqualTo(
@@ -186,28 +190,44 @@
}
@Test
- public void transitionToFullShade_notInSplitShade_alwaysSetsAlphaTo1() {
+ public void transitionToFullShade_inFullWidth_alwaysSetsAlphaTo1() {
QSFragment fragment = resumeAndGetFragment();
- disableSplitShade();
+ fragment.setIsNotificationPanelFullWidth(true);
- int transitionPxAmount = 12;
+ boolean isTransitioningToFullShade = true;
float transitionProgress = 0.1f;
- fragment.setTransitionToFullShadeAmount(transitionPxAmount, transitionProgress);
+ float squishinessFraction = 0.5f;
+ fragment.setTransitionToFullShadeProgress(isTransitioningToFullShade, transitionProgress,
+ squishinessFraction);
assertThat(mQsFragmentView.getAlpha()).isEqualTo(1);
- transitionPxAmount = 123;
transitionProgress = 0.5f;
- fragment.setTransitionToFullShadeAmount(transitionPxAmount, transitionProgress);
+ fragment.setTransitionToFullShadeProgress(isTransitioningToFullShade, transitionProgress,
+ squishinessFraction);
assertThat(mQsFragmentView.getAlpha()).isEqualTo(1);
assertThat(mQsFragmentView.getAlpha()).isEqualTo(1);
- transitionPxAmount = 234;
transitionProgress = 0.7f;
- fragment.setTransitionToFullShadeAmount(transitionPxAmount, transitionProgress);
+ fragment.setTransitionToFullShadeProgress(isTransitioningToFullShade, transitionProgress,
+ squishinessFraction);
assertThat(mQsFragmentView.getAlpha()).isEqualTo(1);
}
@Test
+ public void transitionToFullShade_setsSquishinessOnController() {
+ QSFragment fragment = resumeAndGetFragment();
+ boolean isTransitioningToFullShade = true;
+ float transitionProgress = 0.123f;
+ float squishinessFraction = 0.456f;
+
+ fragment.setTransitionToFullShadeProgress(isTransitioningToFullShade, transitionProgress,
+ squishinessFraction);
+
+ verify(mQsFragmentComponent.getQSSquishinessController())
+ .setSquishiness(squishinessFraction);
+ }
+
+ @Test
public void setQsExpansion_inSplitShade_setsFooterActionsExpansion_basedOnPanelExpFraction() {
// Random test values without any meaning. They just have to be different from each other.
float expansion = 0.123f;
@@ -453,6 +473,7 @@
when(mQsFragmentComponent.getQSFooterActionController())
.thenReturn(mQSFooterActionController);
when(mQsFragmentComponent.getQSAnimator()).thenReturn(mQSAnimator);
+ when(mQsFragmentComponent.getQSSquishinessController()).thenReturn(mSquishinessController);
}
private QSFragment getFragment() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java
index c127a6b..ecc8457 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java
@@ -44,6 +44,7 @@
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.media.MediaCarouselController;
import com.android.systemui.media.MediaHost;
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.plugins.qs.QSTileView;
@@ -86,6 +87,7 @@
@Mock
private QSLogger mQSLogger;
private DumpManager mDumpManager = new DumpManager();
+ private MediaCarouselController mMediaCarouselController;
@Mock
QSTileImpl mQSTile;
@Mock
@@ -108,9 +110,9 @@
protected TestableQSPanelControllerBase(QSPanel view, QSTileHost host,
QSCustomizerController qsCustomizerController, MediaHost mediaHost,
MetricsLogger metricsLogger, UiEventLogger uiEventLogger, QSLogger qsLogger,
- DumpManager dumpManager) {
+ DumpManager dumpManager, MediaCarouselController mediaCarouselController) {
super(view, host, qsCustomizerController, true, mediaHost, metricsLogger, uiEventLogger,
- qsLogger, dumpManager);
+ qsLogger, dumpManager, mediaCarouselController);
}
@Override
@@ -144,7 +146,7 @@
mController = new TestableQSPanelControllerBase(mQSPanel, mQSTileHost,
mQSCustomizerController, mMediaHost,
- mMetricsLogger, mUiEventLogger, mQSLogger, mDumpManager);
+ mMetricsLogger, mUiEventLogger, mQSLogger, mDumpManager, mMediaCarouselController);
mController.init();
reset(mQSTileRevealController);
@@ -156,7 +158,7 @@
QSPanelControllerBase<QSPanel> controller = new TestableQSPanelControllerBase(mQSPanel,
mQSTileHost, mQSCustomizerController, mMediaHost,
- mMetricsLogger, mUiEventLogger, mQSLogger, mDumpManager) {
+ mMetricsLogger, mUiEventLogger, mQSLogger, mDumpManager, mMediaCarouselController) {
@Override
protected QSTileRevealController createTileRevealController() {
return mQSTileRevealController;
@@ -249,7 +251,7 @@
when(mQSPanel.getDumpableTag()).thenReturn("QSPanelLandscape");
mController = new TestableQSPanelControllerBase(mQSPanel, mQSTileHost,
mQSCustomizerController, mMediaHost,
- mMetricsLogger, mUiEventLogger, mQSLogger, mDumpManager);
+ mMetricsLogger, mUiEventLogger, mQSLogger, mDumpManager, mMediaCarouselController);
mController.init();
assertThat(mController.shouldUseHorizontalLayout()).isTrue();
@@ -258,7 +260,7 @@
when(mQSPanel.getDumpableTag()).thenReturn("QSPanelPortrait");
mController = new TestableQSPanelControllerBase(mQSPanel, mQSTileHost,
mQSCustomizerController, mMediaHost,
- mMetricsLogger, mUiEventLogger, mQSLogger, mDumpManager);
+ mMetricsLogger, mUiEventLogger, mQSLogger, mDumpManager, mMediaCarouselController);
mController.init();
assertThat(mController.shouldUseHorizontalLayout()).isFalse();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.kt
index c0944ef..98d499a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.kt
@@ -6,6 +6,7 @@
import com.android.internal.logging.UiEventLogger
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
+import com.android.systemui.media.MediaCarouselController
import com.android.systemui.media.MediaHost
import com.android.systemui.media.MediaHostState
import com.android.systemui.plugins.FalsingManager
@@ -27,8 +28,8 @@
import org.mockito.Mockito.any
import org.mockito.Mockito.reset
import org.mockito.Mockito.verify
-import org.mockito.MockitoAnnotations
import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
@SmallTest
@RunWith(AndroidTestingRunner::class)
@@ -40,6 +41,7 @@
@Mock private lateinit var qsCustomizerController: QSCustomizerController
@Mock private lateinit var qsTileRevealControllerFactory: QSTileRevealController.Factory
@Mock private lateinit var dumpManager: DumpManager
+ @Mock private lateinit var mediaCarouselController: MediaCarouselController
@Mock private lateinit var metricsLogger: MetricsLogger
@Mock private lateinit var uiEventLogger: UiEventLogger
@Mock private lateinit var qsLogger: QSLogger
@@ -76,6 +78,7 @@
mediaHost,
qsTileRevealControllerFactory,
dumpManager,
+ mediaCarouselController,
metricsLogger,
uiEventLogger,
qsLogger,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.kt
index b98be75..2db58be 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.kt
@@ -158,6 +158,13 @@
assertThat(qsPanel.paddingBottom).isEqualTo(padding)
}
+ @Test
+ fun testSetSquishinessFraction_noCrash() {
+ qsPanel.addView(qsPanel.mTileLayout as View, 0)
+ qsPanel.addView(FrameLayout(context))
+ qsPanel.setSquishinessFraction(0.5f)
+ }
+
private infix fun View.isLeftOf(other: View): Boolean {
val rect = Rect()
getBoundsOnScreen(rect)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt
index e4f47fd..39f27d4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt
@@ -23,6 +23,7 @@
import com.android.internal.logging.testing.UiEventLoggerFake
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
+import com.android.systemui.media.MediaCarouselController
import com.android.systemui.media.MediaHost
import com.android.systemui.media.MediaHostState
import com.android.systemui.plugins.qs.QSTile
@@ -59,6 +60,7 @@
@Mock private lateinit var tileLayout: TileLayout
@Mock private lateinit var tileView: QSTileView
@Captor private lateinit var captor: ArgumentCaptor<QSPanel.OnConfigurationChangedListener>
+ @Mock private lateinit var mediaCarouselController: MediaCarouselController
private val uiEventLogger = UiEventLoggerFake()
private val dumpManager = DumpManager()
@@ -88,7 +90,8 @@
metricsLogger,
uiEventLogger,
qsLogger,
- dumpManager)
+ dumpManager,
+ mediaCarouselController)
controller.init()
}
@@ -157,7 +160,8 @@
metricsLogger: MetricsLogger,
uiEventLogger: UiEventLoggerFake,
qsLogger: QSLogger,
- dumpManager: DumpManager
+ dumpManager: DumpManager,
+ mediaCarouselController: MediaCarouselController
) :
QuickQSPanelController(
view,
@@ -169,7 +173,8 @@
metricsLogger,
uiEventLogger,
qsLogger,
- dumpManager) {
+ dumpManager,
+ mediaCarouselController) {
private var rotation = RotationUtils.ROTATION_NONE
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt
index cb4f08e..eb907bd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt
@@ -192,6 +192,14 @@
verify(view).setIsSingleCarrier(false)
}
+ @Test
+ fun testAlarmIconIgnored() {
+ controller.init()
+
+ verify(iconContainer).addIgnoredSlot(
+ mContext.getString(com.android.internal.R.string.status_bar_alarm_clock))
+ }
+
private fun stubViews() {
`when`(view.findViewById<View>(anyInt())).thenReturn(mockView)
`when`(view.findViewById<QSCarrierGroup>(R.id.carrier_group)).thenReturn(qsCarrierGroup)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModelTest.kt
index e4751d1..2a4996f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModelTest.kt
@@ -70,9 +70,13 @@
val underTest = utils.footerActionsViewModel(showPowerButton = false)
val settings = underTest.settings
- assertThat(settings.contentDescription)
- .isEqualTo(ContentDescription.Resource(R.string.accessibility_quick_settings_settings))
- assertThat(settings.icon).isEqualTo(Icon.Resource(R.drawable.ic_settings))
+ assertThat(settings.icon)
+ .isEqualTo(
+ Icon.Resource(
+ R.drawable.ic_settings,
+ ContentDescription.Resource(R.string.accessibility_quick_settings_settings)
+ )
+ )
assertThat(settings.background).isEqualTo(R.drawable.qs_footer_action_circle)
assertThat(settings.iconTint).isNull()
}
@@ -87,11 +91,13 @@
val underTestWithPower = utils.footerActionsViewModel(showPowerButton = true)
val power = underTestWithPower.power
assertThat(power).isNotNull()
- assertThat(power!!.contentDescription)
+ assertThat(power!!.icon)
.isEqualTo(
- ContentDescription.Resource(R.string.accessibility_quick_settings_power_menu)
+ Icon.Resource(
+ android.R.drawable.ic_lock_power_off,
+ ContentDescription.Resource(R.string.accessibility_quick_settings_power_menu)
+ )
)
- assertThat(power.icon).isEqualTo(Icon.Resource(android.R.drawable.ic_lock_power_off))
assertThat(power.background).isEqualTo(R.drawable.qs_footer_action_circle_color)
assertThat(power.iconTint)
.isEqualTo(
@@ -164,14 +170,13 @@
utils.setUserSwitcherEnabled(settings, true, userId)
val userSwitcher = currentUserSwitcher()
assertThat(userSwitcher).isNotNull()
- assertThat(userSwitcher!!.contentDescription)
- .isEqualTo(ContentDescription.Loaded("Signed in as foo"))
- assertThat(userSwitcher.icon).isEqualTo(Icon.Loaded(picture))
+ assertThat(userSwitcher!!.icon)
+ .isEqualTo(Icon.Loaded(picture, ContentDescription.Loaded("Signed in as foo")))
assertThat(userSwitcher.background).isEqualTo(R.drawable.qs_footer_action_circle)
// Change the current user name.
userSwitcherControllerWrapper.currentUserName = "bar"
- assertThat(currentUserSwitcher()?.contentDescription)
+ assertThat(currentUserSwitcher()?.icon?.contentDescription)
.isEqualTo(ContentDescription.Loaded("Signed in as bar"))
fun iconTint(): Int? = currentUserSwitcher()!!.iconTint
@@ -243,7 +248,7 @@
// Map any SecurityModel into a non-null SecurityButtonConfig.
val buttonConfig =
SecurityButtonConfig(
- icon = Icon.Resource(0),
+ icon = Icon.Resource(res = 0, contentDescription = null),
text = "foo",
isClickable = true,
)
@@ -340,7 +345,7 @@
assertThat(foregroundServices.displayText).isTrue()
securityToConfig = {
SecurityButtonConfig(
- icon = Icon.Resource(0),
+ icon = Icon.Resource(res = 0, contentDescription = null),
text = "foo",
isClickable = true,
)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSIconViewImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSIconViewImplTest.java
index 23e5168..2c76be6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSIconViewImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSIconViewImplTest.java
@@ -97,7 +97,7 @@
ImageView iv = mock(ImageView.class);
State s = new State();
s.state = Tile.STATE_ACTIVE;
- int desiredColor = mIconView.getColor(s.state);
+ int desiredColor = mIconView.getColor(s);
when(iv.isShown()).thenReturn(true);
mIconView.setIcon(iv, s, true);
@@ -109,7 +109,7 @@
ImageView iv = mock(ImageView.class);
State s = new State();
s.state = Tile.STATE_ACTIVE;
- int desiredColor = mIconView.getColor(s.state);
+ int desiredColor = mIconView.getColor(s);
Icon i = mock(Icon.class);
s.icon = i;
when(i.toString()).thenReturn("MOCK ICON");
@@ -124,6 +124,18 @@
assertFalse(mIconView.toString().contains("lastIcon"));
}
+ @Test
+ public void testIconColorDisabledByPolicy_sameAsUnavailable() {
+ State s1 = new State();
+ s1.state = Tile.STATE_INACTIVE;
+ s1.disabledByPolicy = true;
+
+ State s2 = new State();
+ s2.state = Tile.STATE_UNAVAILABLE;
+
+ assertEquals(mIconView.getColor(s1), mIconView.getColor(s2));
+ }
+
private static Drawable.ConstantState fakeConstantState(Drawable otherDrawable) {
return new Drawable.ConstantState() {
@Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileViewImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileViewImplTest.kt
index 9fdc2fd..d3ec1dd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileViewImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileViewImplTest.kt
@@ -280,6 +280,88 @@
assertThat(info.collectionItemInfo).isNull()
}
+ @Test
+ fun testDisabledByPolicyInactive_usesUnavailableColors() {
+ val stateDisabledByPolicy = QSTile.State()
+ stateDisabledByPolicy.state = Tile.STATE_INACTIVE
+ stateDisabledByPolicy.disabledByPolicy = true
+
+ val stateUnavailable = QSTile.State()
+ stateUnavailable.state = Tile.STATE_UNAVAILABLE
+
+ tileView.changeState(stateDisabledByPolicy)
+ val colorsDisabledByPolicy = tileView.getCurrentColors()
+
+ tileView.changeState(stateUnavailable)
+ val colorsUnavailable = tileView.getCurrentColors()
+
+ assertThat(colorsDisabledByPolicy).containsExactlyElementsIn(colorsUnavailable)
+ }
+
+ @Test
+ fun testDisabledByPolicyActive_usesUnavailableColors() {
+ val stateDisabledByPolicy = QSTile.State()
+ stateDisabledByPolicy.state = Tile.STATE_ACTIVE
+ stateDisabledByPolicy.disabledByPolicy = true
+
+ val stateUnavailable = QSTile.State()
+ stateUnavailable.state = Tile.STATE_UNAVAILABLE
+
+ tileView.changeState(stateDisabledByPolicy)
+ val colorsDisabledByPolicy = tileView.getCurrentColors()
+
+ tileView.changeState(stateUnavailable)
+ val colorsUnavailable = tileView.getCurrentColors()
+
+ assertThat(colorsDisabledByPolicy).containsExactlyElementsIn(colorsUnavailable)
+ }
+
+ @Test
+ fun testDisabledByPolicy_secondaryLabelText() {
+ val testA11yLabel = "TEST_LABEL"
+ context.orCreateTestableResources
+ .addOverride(
+ R.string.accessibility_tile_disabled_by_policy_action_description,
+ testA11yLabel
+ )
+
+ val stateDisabledByPolicy = QSTile.State()
+ stateDisabledByPolicy.state = Tile.STATE_INACTIVE
+ stateDisabledByPolicy.disabledByPolicy = true
+
+ tileView.changeState(stateDisabledByPolicy)
+
+ val info = AccessibilityNodeInfo(tileView)
+ tileView.onInitializeAccessibilityNodeInfo(info)
+ assertThat(
+ info.actionList.find {
+ it.id == AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK.id
+ }?.label
+ ).isEqualTo(testA11yLabel)
+ }
+
+ @Test
+ fun testDisabledByPolicy_unavailableInStateDescription() {
+ val state = QSTile.BooleanState()
+ val spec = "internet"
+ state.spec = spec
+ state.disabledByPolicy = true
+ state.state = Tile.STATE_INACTIVE
+
+ val unavailableString = "${spec}_unavailable"
+ val offString = "${spec}_off"
+ val onString = "${spec}_on"
+
+ context.orCreateTestableResources.addOverride(R.array.tile_states_internet, arrayOf(
+ unavailableString,
+ offString,
+ onString
+ ))
+
+ tileView.changeState(state)
+ assertThat(tileView.stateDescription?.contains(unavailableString)).isTrue()
+ }
+
class FakeTileView(
context: Context,
icon: QSIconView,
@@ -289,4 +371,4 @@
handleStateChanged(state)
}
}
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt
index ed98881..f7b9438e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt
@@ -33,17 +33,18 @@
import com.android.systemui.animation.ActivityLaunchAnimator
import com.android.systemui.classifier.FalsingManagerFake
import com.android.systemui.controls.ControlsServiceInfo
+import com.android.systemui.controls.controller.ControlInfo
import com.android.systemui.controls.controller.ControlsController
import com.android.systemui.controls.controller.StructureInfo
import com.android.systemui.controls.dagger.ControlsComponent
import com.android.systemui.controls.management.ControlsListingController
+import com.android.systemui.controls.ui.ControlsActivity
import com.android.systemui.controls.ui.ControlsUiController
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.qs.QSHost
import com.android.systemui.qs.logging.QSLogger
import com.android.systemui.qs.tileimpl.QSTileImpl
-import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.capture
import com.android.systemui.util.mockito.eq
@@ -57,13 +58,13 @@
import org.mockito.ArgumentMatchers.anyBoolean
import org.mockito.Captor
import org.mockito.Mock
+import org.mockito.MockitoAnnotations
import org.mockito.Mockito.`when`
import org.mockito.Mockito.doNothing
import org.mockito.Mockito.nullable
import org.mockito.Mockito.spy
import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyZeroInteractions
-import org.mockito.MockitoAnnotations
import java.util.Optional
@SmallTest
@@ -93,8 +94,6 @@
private lateinit var serviceInfo: ControlsServiceInfo
@Mock
private lateinit var uiEventLogger: UiEventLogger
- @Mock
- private lateinit var keyguardStateController: KeyguardStateController
@Captor
private lateinit var listingCallbackCaptor:
ArgumentCaptor<ControlsListingController.ControlsListingCallback>
@@ -119,7 +118,6 @@
`when`(qsHost.context).thenReturn(spiedContext)
`when`(qsHost.uiEventLogger).thenReturn(uiEventLogger)
`when`(controlsComponent.isEnabled()).thenReturn(true)
- `when`(keyguardStateController.isUnlocked()).thenReturn(true)
`when`(controlsController.getPreferredStructure())
.thenReturn(StructureInfo(ComponentName("pkg", "cls"), "structure", listOf()))
secureSettings.putInt(Settings.Secure.LOCKSCREEN_SHOW_CONTROLS, 1)
@@ -222,12 +220,19 @@
}
@Test
- fun testStateAvailableIfListings() {
+ fun testStateActiveIfListingsHasControlsFavorited() {
verify(controlsListingController).observe(
any(LifecycleOwner::class.java),
capture(listingCallbackCaptor)
)
`when`(controlsComponent.getVisibility()).thenReturn(ControlsComponent.Visibility.AVAILABLE)
+ `when`(controlsController.getPreferredStructure()).thenReturn(
+ StructureInfo(
+ ComponentName("pkg", "cls"),
+ "structure",
+ listOf(ControlInfo("id", "title", "subtitle", 1))
+ )
+ )
listingCallbackCaptor.value.onServicesUpdated(listOf(serviceInfo))
testableLooper.processAllMessages()
@@ -236,6 +241,22 @@
}
@Test
+ fun testStateInactiveIfListingsHasNoControlsFavorited() {
+ verify(controlsListingController).observe(
+ any(LifecycleOwner::class.java),
+ capture(listingCallbackCaptor)
+ )
+ `when`(controlsComponent.getVisibility()).thenReturn(ControlsComponent.Visibility.AVAILABLE)
+ `when`(controlsController.getPreferredStructure())
+ .thenReturn(StructureInfo(ComponentName("pkg", "cls"), "structure", listOf()))
+
+ listingCallbackCaptor.value.onServicesUpdated(listOf(serviceInfo))
+ testableLooper.processAllMessages()
+
+ assertThat(tile.state.state).isEqualTo(Tile.STATE_INACTIVE)
+ }
+
+ @Test
fun testStateInactiveIfLocked() {
verify(controlsListingController).observe(
any(LifecycleOwner::class.java),
@@ -281,7 +302,14 @@
capture(listingCallbackCaptor)
)
`when`(controlsComponent.getVisibility()).thenReturn(ControlsComponent.Visibility.AVAILABLE)
- `when`(keyguardStateController.isUnlocked).thenReturn(true)
+ `when`(controlsUiController.resolveActivity()).thenReturn(ControlsActivity::class.java)
+ `when`(controlsController.getPreferredStructure()).thenReturn(
+ StructureInfo(
+ ComponentName("pkg", "cls"),
+ "structure",
+ listOf(ControlInfo("id", "title", "subtitle", 1))
+ )
+ )
listingCallbackCaptor.value.onServicesUpdated(listOf(serviceInfo))
testableLooper.processAllMessages()
@@ -305,7 +333,14 @@
)
`when`(controlsComponent.getVisibility())
.thenReturn(ControlsComponent.Visibility.AVAILABLE_AFTER_UNLOCK)
- `when`(keyguardStateController.isUnlocked).thenReturn(false)
+ `when`(controlsUiController.resolveActivity()).thenReturn(ControlsActivity::class.java)
+ `when`(controlsController.getPreferredStructure()).thenReturn(
+ StructureInfo(
+ ComponentName("pkg", "cls"),
+ "structure",
+ listOf(ControlInfo("id", "title", "subtitle", 1))
+ )
+ )
listingCallbackCaptor.value.onServicesUpdated(listOf(serviceInfo))
testableLooper.processAllMessages()
@@ -345,8 +380,7 @@
statusBarStateController,
activityStarter,
qsLogger,
- controlsComponent,
- keyguardStateController
+ controlsComponent
).also {
it.initialize()
testableLooper.processAllMessages()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UiModeNightTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UiModeNightTileTest.kt
new file mode 100644
index 0000000..ea70c26
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UiModeNightTileTest.kt
@@ -0,0 +1,141 @@
+/*
+ * 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.qs.tiles
+
+import android.app.UiModeManager
+import android.content.Context
+import android.content.res.Configuration
+import android.content.res.Resources
+import android.os.Handler
+import android.test.suitebuilder.annotation.SmallTest
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import com.android.internal.logging.MetricsLogger
+import com.android.internal.logging.testing.UiEventLoggerFake
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.classifier.FalsingManagerFake
+import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.plugins.qs.QSTile
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.qs.QSTileHost
+import com.android.systemui.qs.logging.QSLogger
+import com.android.systemui.qs.tileimpl.QSTileImpl
+import com.android.systemui.statusbar.policy.BatteryController
+import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.statusbar.policy.LocationController
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.`when`
+import org.mockito.MockitoAnnotations
+
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+@SmallTest
+class UiModeNightTileTest : SysuiTestCase() {
+
+ @Mock
+ private lateinit var mockContext: Context
+ @Mock
+ private lateinit var uiModeManager: UiModeManager
+ @Mock
+ private lateinit var resources: Resources
+ @Mock
+ private lateinit var qsLogger: QSLogger
+ @Mock
+ private lateinit var qsHost: QSTileHost
+ @Mock
+ private lateinit var metricsLogger: MetricsLogger
+ @Mock
+ private lateinit var statusBarStateController: StatusBarStateController
+ @Mock
+ private lateinit var activityStarter: ActivityStarter
+ @Mock
+ private lateinit var configurationController: ConfigurationController
+ @Mock
+ private lateinit var batteryController: BatteryController
+ @Mock
+ private lateinit var locationController: LocationController
+
+ private val uiEventLogger = UiEventLoggerFake()
+ private val falsingManager = FalsingManagerFake()
+ private lateinit var testableLooper: TestableLooper
+ private lateinit var tile: UiModeNightTile
+ private lateinit var configuration: Configuration
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ testableLooper = TestableLooper.get(this)
+ configuration = Configuration()
+ mContext.addMockSystemService(Context.UI_MODE_SERVICE, uiModeManager)
+
+ `when`(qsHost.context).thenReturn(mockContext)
+ `when`(qsHost.userContext).thenReturn(mContext)
+ `when`(mockContext.resources).thenReturn(resources)
+ `when`(resources.configuration).thenReturn(configuration)
+ `when`(qsHost.uiEventLogger).thenReturn(uiEventLogger)
+
+ tile = UiModeNightTile(
+ qsHost,
+ testableLooper.looper,
+ Handler(testableLooper.looper),
+ falsingManager,
+ metricsLogger,
+ statusBarStateController,
+ activityStarter,
+ qsLogger,
+ configurationController,
+ batteryController,
+ locationController)
+ }
+
+ @Test
+ fun testIcon_whenNightModeOn_isOnState() {
+ val state = QSTile.BooleanState()
+ setNightModeOn()
+
+ tile.handleUpdateState(state, /* arg= */ null)
+
+ assertThat(state.icon)
+ .isEqualTo(QSTileImpl.ResourceIcon.get(R.drawable.qs_light_dark_theme_icon_on))
+ }
+
+ @Test
+ fun testIcon_whenNightModeOn_isOffState() {
+ val state = QSTile.BooleanState()
+ setNightModeOff()
+
+ tile.handleUpdateState(state, /* arg= */ null)
+
+ assertThat(state.icon)
+ .isEqualTo(QSTileImpl.ResourceIcon.get(R.drawable.qs_light_dark_theme_icon_off))
+ }
+
+ private fun setNightModeOn() {
+ `when`(uiModeManager.nightMode).thenReturn(UiModeManager.MODE_NIGHT_YES)
+ configuration.uiMode = Configuration.UI_MODE_NIGHT_YES
+ }
+
+ private fun setNightModeOff() {
+ `when`(uiModeManager.nightMode).thenReturn(UiModeManager.MODE_NIGHT_NO)
+ configuration.uiMode = Configuration.UI_MODE_NIGHT_NO
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UserDetailViewAdapterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UserDetailViewAdapterTest.kt
index 5db3b9c..da52a9b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UserDetailViewAdapterTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UserDetailViewAdapterTest.kt
@@ -53,7 +53,6 @@
@Mock private lateinit var mUserDetailItemView: UserDetailItemView
@Mock private lateinit var mOtherView: View
@Mock private lateinit var mInflatedUserDetailItemView: UserDetailItemView
- @Mock private lateinit var mUserInfo: UserInfo
@Mock private lateinit var mLayoutInflater: LayoutInflater
private var falsingManagerFake: FalsingManagerFake = FalsingManagerFake()
private lateinit var adapter: UserDetailView.Adapter
@@ -142,7 +141,7 @@
private fun createUserRecord(current: Boolean, guest: Boolean) =
UserRecord(
- mUserInfo,
+ UserInfo(0 /* id */, "name", 0 /* flags */),
mPicture,
guest,
current,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerCombinedTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerCombinedTest.kt
index 20c6d9a..c448538 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerCombinedTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerCombinedTest.kt
@@ -23,6 +23,7 @@
import android.testing.AndroidTestingRunner
import android.view.DisplayCutout
import android.view.View
+import android.view.ViewPropertyAnimator
import android.view.WindowInsets
import android.widget.TextView
import androidx.constraintlayout.motion.widget.MotionLayout
@@ -30,6 +31,7 @@
import androidx.test.filters.SmallTest
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
+import com.android.systemui.animation.Interpolators
import com.android.systemui.animation.ShadeInterpolation
import com.android.systemui.battery.BatteryMeterView
import com.android.systemui.battery.BatteryMeterViewController
@@ -64,6 +66,7 @@
import org.mockito.ArgumentCaptor
import org.mockito.ArgumentMatchers
import org.mockito.Mock
+import org.mockito.Mockito
import org.mockito.Mockito.anyBoolean
import org.mockito.Mockito.anyFloat
import org.mockito.Mockito.anyInt
@@ -607,6 +610,41 @@
verify(mockConstraintsChanges.largeScreenConstraintsChanges)!!.invoke(any())
}
+ @Test
+ fun alarmIconNotIgnored() {
+ verify(statusIcons, never()).addIgnoredSlot(
+ context.getString(com.android.internal.R.string.status_bar_alarm_clock)
+ )
+ }
+
+ @Test
+ fun animateOutOnStartCustomizing() {
+ val animator = Mockito.mock(ViewPropertyAnimator::class.java, Answers.RETURNS_SELF)
+ val duration = 1000L
+ whenever(view.animate()).thenReturn(animator)
+
+ controller.startCustomizingAnimation(show = true, duration)
+
+ verify(animator).setDuration(duration)
+ verify(animator).alpha(0f)
+ verify(animator).setInterpolator(Interpolators.ALPHA_OUT)
+ verify(animator).start()
+ }
+
+ @Test
+ fun animateInOnEndCustomizing() {
+ val animator = Mockito.mock(ViewPropertyAnimator::class.java, Answers.RETURNS_SELF)
+ val duration = 1000L
+ whenever(view.animate()).thenReturn(animator)
+
+ controller.startCustomizingAnimation(show = false, duration)
+
+ verify(animator).setDuration(duration)
+ verify(animator).alpha(1f)
+ verify(animator).setInterpolator(Interpolators.ALPHA_IN)
+ verify(animator).start()
+ }
+
private fun createWindowInsets(
topCutout: Rect? = Rect()
): WindowInsets {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerTest.kt
index eeb61bc..5ecfc8eb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerTest.kt
@@ -4,10 +4,12 @@
import android.content.Context
import android.testing.AndroidTestingRunner
import android.view.View
+import android.view.ViewPropertyAnimator
import android.widget.TextView
import androidx.test.filters.SmallTest
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
+import com.android.systemui.animation.Interpolators
import com.android.systemui.animation.ShadeInterpolation
import com.android.systemui.battery.BatteryMeterView
import com.android.systemui.battery.BatteryMeterViewController
@@ -29,8 +31,10 @@
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.Answers
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Mock
+import org.mockito.Mockito.mock
import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyZeroInteractions
import org.mockito.Mockito.`when` as whenever
@@ -191,4 +195,39 @@
verify(date).setTextAppearance(R.style.TextAppearance_QS_Status)
verify(carrierGroup).updateTextAppearance(R.style.TextAppearance_QS_Status_Carriers)
}
+
+ @Test
+ fun alarmIconIgnored() {
+ verify(statusIcons).addIgnoredSlot(
+ context.getString(com.android.internal.R.string.status_bar_alarm_clock)
+ )
+ }
+
+ @Test
+ fun animateOutOnStartCustomizing() {
+ val animator = mock(ViewPropertyAnimator::class.java, Answers.RETURNS_SELF)
+ val duration = 1000L
+ whenever(view.animate()).thenReturn(animator)
+
+ mLargeScreenShadeHeaderController.startCustomizingAnimation(show = true, duration)
+
+ verify(animator).setDuration(duration)
+ verify(animator).alpha(0f)
+ verify(animator).setInterpolator(Interpolators.ALPHA_OUT)
+ verify(animator).start()
+ }
+
+ @Test
+ fun animateInOnEndCustomizing() {
+ val animator = mock(ViewPropertyAnimator::class.java, Answers.RETURNS_SELF)
+ val duration = 1000L
+ whenever(view.animate()).thenReturn(animator)
+
+ mLargeScreenShadeHeaderController.startCustomizingAnimation(show = false, duration)
+
+ verify(animator).setDuration(duration)
+ verify(animator).alpha(1f)
+ verify(animator).setInterpolator(Interpolators.ALPHA_IN)
+ verify(animator).start()
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
index e2ce939..e730713 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
@@ -42,7 +42,6 @@
import static org.mockito.Mockito.when;
import android.annotation.IdRes;
-import android.app.ActivityManager;
import android.content.ContentResolver;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -57,6 +56,7 @@
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
+import android.view.ViewGroup;
import android.view.ViewParent;
import android.view.ViewPropertyAnimator;
import android.view.ViewStub;
@@ -107,6 +107,7 @@
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.qs.QS;
import com.android.systemui.qrcodescanner.controller.QRCodeScannerController;
+import com.android.systemui.qs.QSFragment;
import com.android.systemui.screenrecord.RecordingController;
import com.android.systemui.shade.transition.ShadeTransitionController;
import com.android.systemui.statusbar.CommandQueue;
@@ -124,7 +125,6 @@
import com.android.systemui.statusbar.events.PrivacyDotViewController;
import com.android.systemui.statusbar.notification.ConversationNotificationManager;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
import com.android.systemui.statusbar.notification.row.ExpandableView;
import com.android.systemui.statusbar.notification.row.ExpandableView.OnHeightChangedListener;
@@ -161,8 +161,6 @@
import com.android.systemui.statusbar.policy.KeyguardUserSwitcherView;
import com.android.systemui.statusbar.window.StatusBarWindowStateController;
import com.android.systemui.unfold.SysUIUnfoldComponent;
-import com.android.systemui.util.concurrency.FakeExecutor;
-import com.android.systemui.util.settings.SecureSettings;
import com.android.systemui.util.time.FakeSystemClock;
import com.android.systemui.util.time.SystemClock;
import com.android.systemui.wallet.controller.QuickAccessWalletController;
@@ -185,228 +183,136 @@
@TestableLooper.RunWithLooper
public class NotificationPanelViewControllerTest extends SysuiTestCase {
+ private static final int SPLIT_SHADE_FULL_TRANSITION_DISTANCE = 400;
private static final int NOTIFICATION_SCRIM_TOP_PADDING_IN_SPLIT_SHADE = 50;
+ private static final int PANEL_WIDTH = 500; // Random value just for the test.
- @Mock
- private CentralSurfaces mCentralSurfaces;
- @Mock
- private NotificationStackScrollLayout mNotificationStackScrollLayout;
- @Mock
- private KeyguardBottomAreaView mKeyguardBottomArea;
- @Mock
- private KeyguardBottomAreaViewController mKeyguardBottomAreaViewController;
- @Mock
- private KeyguardBottomAreaView mQsFrame;
- private KeyguardStatusView mKeyguardStatusView;
- @Mock
- private NotificationIconAreaController mNotificationAreaController;
- @Mock
- private HeadsUpManagerPhone mHeadsUpManager;
- @Mock
- private NotificationShelfController mNotificationShelfController;
- @Mock
- private KeyguardStatusBarView mKeyguardStatusBar;
- @Mock
- private KeyguardUserSwitcherView mUserSwitcherView;
- @Mock
- private ViewStub mUserSwitcherStubView;
- @Mock
- private HeadsUpTouchHelper.Callback mHeadsUpCallback;
- @Mock
- private KeyguardUpdateMonitor mUpdateMonitor;
- @Mock
- private KeyguardBypassController mKeyguardBypassController;
- @Mock
- private DozeParameters mDozeParameters;
- @Mock
- private ScreenOffAnimationController mScreenOffAnimationController;
- @Mock
- private NotificationPanelView mView;
- @Mock
- private LayoutInflater mLayoutInflater;
- @Mock
- private FeatureFlags mFeatureFlags;
- @Mock
- private DynamicPrivacyController mDynamicPrivacyController;
- @Mock
- private NotificationEntryManager mNotificationEntryManager;
- @Mock
- private StatusBarTouchableRegionManager mStatusBarTouchableRegionManager;
- @Mock
- private KeyguardStateController mKeyguardStateController;
- @Mock
- private DozeLog mDozeLog;
- @Mock
- private ShadeLogger mShadeLog;
- @Mock
- private CommandQueue mCommandQueue;
- @Mock
- private VibratorHelper mVibratorHelper;
- @Mock
- private LatencyTracker mLatencyTracker;
- @Mock
- private PowerManager mPowerManager;
- @Mock
- private AccessibilityManager mAccessibilityManager;
- @Mock
- private MetricsLogger mMetricsLogger;
- @Mock
- private ActivityManager mActivityManager;
- @Mock
- private Resources mResources;
- @Mock
- private Configuration mConfiguration;
- private DisplayMetrics mDisplayMetrics = new DisplayMetrics();
- @Mock
- private KeyguardClockSwitch mKeyguardClockSwitch;
- private NotificationPanelViewController.TouchHandler mTouchHandler;
- private ConfigurationController mConfigurationController;
- @Mock
- private MediaHierarchyManager mMediaHiearchyManager;
- @Mock
- private ConversationNotificationManager mConversationNotificationManager;
- @Mock
- private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
- @Mock
- private KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory;
- @Mock
- private KeyguardQsUserSwitchComponent.Factory mKeyguardQsUserSwitchComponentFactory;
- @Mock
- private KeyguardQsUserSwitchComponent mKeyguardQsUserSwitchComponent;
- @Mock
- private KeyguardQsUserSwitchController mKeyguardQsUserSwitchController;
- @Mock
- private KeyguardUserSwitcherComponent.Factory mKeyguardUserSwitcherComponentFactory;
- @Mock
- private KeyguardUserSwitcherComponent mKeyguardUserSwitcherComponent;
- @Mock
- private KeyguardUserSwitcherController mKeyguardUserSwitcherController;
- @Mock
- private KeyguardStatusViewComponent mKeyguardStatusViewComponent;
- @Mock
- private KeyguardStatusBarViewComponent.Factory mKeyguardStatusBarViewComponentFactory;
- @Mock
- private KeyguardStatusBarViewComponent mKeyguardStatusBarViewComponent;
- @Mock
- private KeyguardClockSwitchController mKeyguardClockSwitchController;
- @Mock
- private KeyguardStatusViewController mKeyguardStatusViewController;
- @Mock
- private KeyguardStatusBarViewController mKeyguardStatusBarViewController;
- @Mock
- private NotificationStackScrollLayoutController mNotificationStackScrollLayoutController;
- @Mock
- private NotificationShadeDepthController mNotificationShadeDepthController;
- @Mock
- private LockscreenShadeTransitionController mLockscreenShadeTransitionController;
- @Mock
- private AuthController mAuthController;
- @Mock
- private ScrimController mScrimController;
- @Mock
- private MediaDataManager mMediaDataManager;
- @Mock
- private AmbientState mAmbientState;
- @Mock
- private UserManager mUserManager;
- @Mock
- private UiEventLogger mUiEventLogger;
- @Mock
- private LockIconViewController mLockIconViewController;
- @Mock
- private KeyguardMediaController mKeyguardMediaController;
- @Mock
- private PrivacyDotViewController mPrivacyDotViewController;
- @Mock
- private NavigationModeController mNavigationModeController;
- @Mock
- private SecureSettings mSecureSettings;
- @Mock
- private LargeScreenShadeHeaderController mLargeScreenShadeHeaderController;
- @Mock
- private ContentResolver mContentResolver;
- @Mock
- private TapAgainViewController mTapAgainViewController;
- @Mock
- private KeyguardIndicationController mKeyguardIndicationController;
- @Mock
- private FragmentService mFragmentService;
- @Mock
- private FragmentHostManager mFragmentHostManager;
- @Mock
- private QuickAccessWalletController mQuickAccessWalletController;
- @Mock
- private QRCodeScannerController mQrCodeScannerController;
- @Mock
- private NotificationRemoteInputManager mNotificationRemoteInputManager;
- @Mock
- private RecordingController mRecordingController;
- @Mock
- private ControlsComponent mControlsComponent;
- @Mock
- private LockscreenGestureLogger mLockscreenGestureLogger;
- @Mock
- private DumpManager mDumpManager;
- @Mock
- private InteractionJankMonitor mInteractionJankMonitor;
- @Mock
- private NotificationsQSContainerController mNotificationsQSContainerController;
- @Mock
- private QsFrameTranslateController mQsFrameTranslateController;
- @Mock
- private StatusBarWindowStateController mStatusBarWindowStateController;
- @Mock
- private KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
- @Mock
- private NotificationShadeWindowController mNotificationShadeWindowController;
- @Mock
- private SysUiState mSysUiState;
- @Mock
- private NotificationListContainer mNotificationListContainer;
- @Mock
- private NotificationStackSizeCalculator mNotificationStackSizeCalculator;
- @Mock
- private UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
- @Mock
- private ShadeTransitionController mShadeTransitionController;
- @Mock
- private QS mQs;
- @Mock
- private View mQsHeader;
- @Mock
- private ViewParent mViewParent;
- @Mock
- private ViewTreeObserver mViewTreeObserver;
+ @Mock private CentralSurfaces mCentralSurfaces;
+ @Mock private NotificationStackScrollLayout mNotificationStackScrollLayout;
+ @Mock private KeyguardBottomAreaView mKeyguardBottomArea;
+ @Mock private KeyguardBottomAreaViewController mKeyguardBottomAreaViewController;
+ @Mock private KeyguardBottomAreaView mQsFrame;
+ @Mock private NotificationIconAreaController mNotificationAreaController;
+ @Mock private HeadsUpManagerPhone mHeadsUpManager;
+ @Mock private NotificationShelfController mNotificationShelfController;
+ @Mock private KeyguardStatusBarView mKeyguardStatusBar;
+ @Mock private KeyguardUserSwitcherView mUserSwitcherView;
+ @Mock private ViewStub mUserSwitcherStubView;
+ @Mock private HeadsUpTouchHelper.Callback mHeadsUpCallback;
+ @Mock private KeyguardUpdateMonitor mUpdateMonitor;
+ @Mock private KeyguardBypassController mKeyguardBypassController;
+ @Mock private DozeParameters mDozeParameters;
+ @Mock private ScreenOffAnimationController mScreenOffAnimationController;
+ @Mock private NotificationPanelView mView;
+ @Mock private LayoutInflater mLayoutInflater;
+ @Mock private FeatureFlags mFeatureFlags;
+ @Mock private DynamicPrivacyController mDynamicPrivacyController;
+ @Mock private StatusBarTouchableRegionManager mStatusBarTouchableRegionManager;
+ @Mock private KeyguardStateController mKeyguardStateController;
+ @Mock private DozeLog mDozeLog;
+ @Mock private ShadeLogger mShadeLog;
+ @Mock private CommandQueue mCommandQueue;
+ @Mock private VibratorHelper mVibratorHelper;
+ @Mock private LatencyTracker mLatencyTracker;
+ @Mock private PowerManager mPowerManager;
+ @Mock private AccessibilityManager mAccessibilityManager;
+ @Mock private MetricsLogger mMetricsLogger;
+ @Mock private Resources mResources;
+ @Mock private Configuration mConfiguration;
+ @Mock private KeyguardClockSwitch mKeyguardClockSwitch;
+ @Mock private MediaHierarchyManager mMediaHiearchyManager;
+ @Mock private ConversationNotificationManager mConversationNotificationManager;
+ @Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
+ @Mock private KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory;
+ @Mock private KeyguardQsUserSwitchComponent.Factory mKeyguardQsUserSwitchComponentFactory;
+ @Mock private KeyguardQsUserSwitchComponent mKeyguardQsUserSwitchComponent;
+ @Mock private KeyguardQsUserSwitchController mKeyguardQsUserSwitchController;
+ @Mock private KeyguardUserSwitcherComponent.Factory mKeyguardUserSwitcherComponentFactory;
+ @Mock private KeyguardUserSwitcherComponent mKeyguardUserSwitcherComponent;
+ @Mock private KeyguardUserSwitcherController mKeyguardUserSwitcherController;
+ @Mock private KeyguardStatusViewComponent mKeyguardStatusViewComponent;
+ @Mock private KeyguardStatusBarViewComponent.Factory mKeyguardStatusBarViewComponentFactory;
+ @Mock private KeyguardStatusBarViewComponent mKeyguardStatusBarViewComponent;
+ @Mock private KeyguardClockSwitchController mKeyguardClockSwitchController;
+ @Mock private KeyguardStatusViewController mKeyguardStatusViewController;
+ @Mock private KeyguardStatusBarViewController mKeyguardStatusBarViewController;
+ @Mock private NotificationStackScrollLayoutController mNotificationStackScrollLayoutController;
+ @Mock private NotificationShadeDepthController mNotificationShadeDepthController;
+ @Mock private LockscreenShadeTransitionController mLockscreenShadeTransitionController;
+ @Mock private AuthController mAuthController;
+ @Mock private ScrimController mScrimController;
+ @Mock private MediaDataManager mMediaDataManager;
+ @Mock private AmbientState mAmbientState;
+ @Mock private UserManager mUserManager;
+ @Mock private UiEventLogger mUiEventLogger;
+ @Mock private LockIconViewController mLockIconViewController;
+ @Mock private KeyguardMediaController mKeyguardMediaController;
+ @Mock private PrivacyDotViewController mPrivacyDotViewController;
+ @Mock private NavigationModeController mNavigationModeController;
+ @Mock private LargeScreenShadeHeaderController mLargeScreenShadeHeaderController;
+ @Mock private ContentResolver mContentResolver;
+ @Mock private TapAgainViewController mTapAgainViewController;
+ @Mock private KeyguardIndicationController mKeyguardIndicationController;
+ @Mock private FragmentService mFragmentService;
+ @Mock private FragmentHostManager mFragmentHostManager;
+ @Mock private QuickAccessWalletController mQuickAccessWalletController;
+ @Mock private QRCodeScannerController mQrCodeScannerController;
+ @Mock private NotificationRemoteInputManager mNotificationRemoteInputManager;
+ @Mock private RecordingController mRecordingController;
+ @Mock private ControlsComponent mControlsComponent;
+ @Mock private LockscreenGestureLogger mLockscreenGestureLogger;
+ @Mock private DumpManager mDumpManager;
+ @Mock private InteractionJankMonitor mInteractionJankMonitor;
+ @Mock private NotificationsQSContainerController mNotificationsQSContainerController;
+ @Mock private QsFrameTranslateController mQsFrameTranslateController;
+ @Mock private StatusBarWindowStateController mStatusBarWindowStateController;
+ @Mock private KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
+ @Mock private NotificationShadeWindowController mNotificationShadeWindowController;
+ @Mock private SysUiState mSysUiState;
+ @Mock private NotificationListContainer mNotificationListContainer;
+ @Mock private NotificationStackSizeCalculator mNotificationStackSizeCalculator;
+ @Mock private UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
+ @Mock private ShadeTransitionController mShadeTransitionController;
+ @Mock private QS mQs;
+ @Mock private QSFragment mQSFragment;
+ @Mock private ViewGroup mQsHeader;
+ @Mock private ViewParent mViewParent;
+ @Mock private ViewTreeObserver mViewTreeObserver;
@Mock private KeyguardBottomAreaViewModel mKeyguardBottomAreaViewModel;
@Mock private KeyguardBottomAreaInteractor mKeyguardBottomAreaInteractor;
- private NotificationPanelViewController.PanelEventsEmitter mPanelEventsEmitter;
- private Optional<SysUIUnfoldComponent> mSysUIUnfoldComponent = Optional.empty();
+
+ private NotificationPanelViewController.TouchHandler mTouchHandler;
+ private ConfigurationController mConfigurationController;
private SysuiStatusBarStateController mStatusBarStateController;
private NotificationPanelViewController mNotificationPanelViewController;
private View.AccessibilityDelegate mAccessibiltyDelegate;
private NotificationsQuickSettingsContainer mNotificationContainerParent;
private List<View.OnAttachStateChangeListener> mOnAttachStateChangeListeners;
- private FalsingManagerFake mFalsingManager = new FalsingManagerFake();
- private FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
private Handler mMainHandler;
+ private View.OnLayoutChangeListener mLayoutChangeListener;
+
+ private final FalsingManagerFake mFalsingManager = new FalsingManagerFake();
+ private final Optional<SysUIUnfoldComponent> mSysUIUnfoldComponent = Optional.empty();
+ private final DisplayMetrics mDisplayMetrics = new DisplayMetrics();
private final PanelExpansionStateManager mPanelExpansionStateManager =
new PanelExpansionStateManager();
- private SystemClock mSystemClock;
+ private FragmentHostManager.FragmentListener mFragmentListener;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
- mSystemClock = new FakeSystemClock();
+ SystemClock systemClock = new FakeSystemClock();
mStatusBarStateController = new StatusBarStateControllerImpl(mUiEventLogger, mDumpManager,
mInteractionJankMonitor);
- mKeyguardStatusView = new KeyguardStatusView(mContext);
- mKeyguardStatusView.setId(R.id.keyguard_status_view);
+ KeyguardStatusView keyguardStatusView = new KeyguardStatusView(mContext);
+ keyguardStatusView.setId(R.id.keyguard_status_view);
DejankUtils.setImmediate(true);
when(mAuthController.isUdfpsEnrolled(anyInt())).thenReturn(false);
when(mHeadsUpCallback.getContext()).thenReturn(mContext);
when(mView.getResources()).thenReturn(mResources);
+ when(mView.getWidth()).thenReturn(PANEL_WIDTH);
when(mResources.getConfiguration()).thenReturn(mConfiguration);
mConfiguration.orientation = ORIENTATION_PORTRAIT;
when(mResources.getDisplayMetrics()).thenReturn(mDisplayMetrics);
@@ -416,6 +322,8 @@
.thenReturn(NOTIFICATION_SCRIM_TOP_PADDING_IN_SPLIT_SHADE);
when(mResources.getDimensionPixelSize(R.dimen.notification_panel_margin_horizontal))
.thenReturn(10);
+ when(mResources.getDimensionPixelSize(R.dimen.split_shade_full_transition_distance))
+ .thenReturn(SPLIT_SHADE_FULL_TRANSITION_DISTANCE);
when(mView.getContext()).thenReturn(getContext());
when(mView.findViewById(R.id.keyguard_header)).thenReturn(mKeyguardStatusBar);
when(mView.findViewById(R.id.keyguard_user_switcher_view)).thenReturn(mUserSwitcherView);
@@ -434,7 +342,7 @@
when(mView.findViewById(R.id.keyguard_status_view))
.thenReturn(mock(KeyguardStatusView.class));
mNotificationContainerParent = new NotificationsQuickSettingsContainer(getContext(), null);
- mNotificationContainerParent.addView(mKeyguardStatusView);
+ mNotificationContainerParent.addView(keyguardStatusView);
mNotificationContainerParent.onFinishInflate();
when(mView.findViewById(R.id.notification_container_parent))
.thenReturn(mNotificationContainerParent);
@@ -450,7 +358,12 @@
when(mKeyguardUserSwitcherComponent.getKeyguardUserSwitcherController())
.thenReturn(mKeyguardUserSwitcherController);
when(mScreenOffAnimationController.shouldAnimateClockChange()).thenReturn(true);
-
+ when(mQs.getView()).thenReturn(mView);
+ when(mQSFragment.getView()).thenReturn(mView);
+ doAnswer(invocation -> {
+ mFragmentListener = invocation.getArgument(1);
+ return null;
+ }).when(mFragmentHostManager).addTagListener(eq(QS.TAG), any());
doAnswer((Answer<Void>) invocation -> {
mTouchHandler = invocation.getArgument(0);
return null;
@@ -487,7 +400,7 @@
when(mKeyguardStatusBarViewComponent.getKeyguardStatusBarViewController())
.thenReturn(mKeyguardStatusBarViewController);
when(mLayoutInflater.inflate(eq(R.layout.keyguard_status_view), any(), anyBoolean()))
- .thenReturn(mKeyguardStatusView);
+ .thenReturn(keyguardStatusView);
when(mLayoutInflater.inflate(eq(R.layout.keyguard_user_switcher), any(), anyBoolean()))
.thenReturn(mUserSwitcherView);
when(mLayoutInflater.inflate(eq(R.layout.keyguard_bottom_area), any(), anyBoolean()))
@@ -502,13 +415,18 @@
((Runnable) invocation.getArgument(0)).run();
return null;
}).when(mNotificationShadeWindowController).batchApplyWindowLayoutParams(any());
+ doAnswer(invocation -> {
+ mLayoutChangeListener = invocation.getArgument(0);
+ return null;
+ }).when(mView).addOnLayoutChangeListener(any());
when(mView.getViewTreeObserver()).thenReturn(mViewTreeObserver);
when(mView.getParent()).thenReturn(mViewParent);
when(mQs.getHeader()).thenReturn(mQsHeader);
mMainHandler = new Handler(Looper.getMainLooper());
- mPanelEventsEmitter = new NotificationPanelViewController.PanelEventsEmitter();
+ NotificationPanelViewController.PanelEventsEmitter panelEventsEmitter =
+ new NotificationPanelViewController.PanelEventsEmitter();
mNotificationPanelViewController = new NotificationPanelViewController(
mView,
@@ -517,7 +435,6 @@
mFeatureFlags,
coordinator, expansionHandler, mDynamicPrivacyController, mKeyguardBypassController,
mFalsingManager, new FalsingCollectorFake(),
- mNotificationEntryManager,
mKeyguardStateController,
mStatusBarStateController,
mStatusBarWindowStateController,
@@ -551,8 +468,6 @@
mNavigationModeController,
mFragmentService,
mContentResolver,
- mQuickAccessWalletController,
- mQrCodeScannerController,
mRecordingController,
mLargeScreenShadeHeaderController,
mScreenOffAnimationController,
@@ -560,21 +475,20 @@
mPanelExpansionStateManager,
mNotificationRemoteInputManager,
mSysUIUnfoldComponent,
- mControlsComponent,
mInteractionJankMonitor,
mQsFrameTranslateController,
mSysUiState,
() -> mKeyguardBottomAreaViewController,
mKeyguardUnlockAnimationController,
mNotificationListContainer,
- mPanelEventsEmitter,
+ panelEventsEmitter,
mNotificationStackSizeCalculator,
mUnlockedScreenOffAnimationController,
mShadeTransitionController,
- mSystemClock,
+ systemClock,
mock(CameraGestureHelper.class),
- () -> mKeyguardBottomAreaViewModel,
- () -> mKeyguardBottomAreaInteractor);
+ mKeyguardBottomAreaViewModel,
+ mKeyguardBottomAreaInteractor);
mNotificationPanelViewController.initDependencies(
mCentralSurfaces,
() -> {},
@@ -755,8 +669,9 @@
}
@Test
- public void testSetPanelScrimMinFraction() {
- mNotificationPanelViewController.setPanelScrimMinFraction(0.5f);
+ public void testSetPanelScrimMinFractionWhenHeadsUpIsDragged() {
+ mNotificationPanelViewController.setHeadsUpDraggingStartingHeight(
+ mNotificationPanelViewController.getMaxPanelHeight() / 2);
verify(mNotificationShadeDepthController).setPanelPullDownMinFraction(eq(0.5f));
}
@@ -1452,40 +1367,137 @@
}
@Test
- public void getMaxPanelHeight_expanding_inSplitShade_returnsSplitShadeFullTransitionDistance() {
- int splitShadeFullTransitionDistance = 123456;
+ public void getMaxPanelTransitionDistance_expanding_inSplitShade_returnsSplitShadeFullTransitionDistance() {
enableSplitShade(true);
- setSplitShadeFullTransitionDistance(splitShadeFullTransitionDistance);
mNotificationPanelViewController.expandWithQs();
- int maxPanelHeight = mNotificationPanelViewController.getMaxPanelHeight();
+ int maxDistance = mNotificationPanelViewController.getMaxPanelTransitionDistance();
- assertThat(maxPanelHeight).isEqualTo(splitShadeFullTransitionDistance);
+ assertThat(maxDistance).isEqualTo(SPLIT_SHADE_FULL_TRANSITION_DISTANCE);
}
@Test
- public void getMaxPanelHeight_expandingSplitShade_keyguard_returnsNonSplitShadeValue() {
+ public void getMaxPanelTransitionDistance_inSplitShade_withHeadsUp_returnsBiggerValue() {
+ enableSplitShade(true);
+ mNotificationPanelViewController.expandWithQs();
+ when(mHeadsUpManager.isTrackingHeadsUp()).thenReturn(true);
+ mNotificationPanelViewController.setHeadsUpDraggingStartingHeight(
+ SPLIT_SHADE_FULL_TRANSITION_DISTANCE);
+
+ int maxDistance = mNotificationPanelViewController.getMaxPanelTransitionDistance();
+
+ assertThat(maxDistance).isGreaterThan(SPLIT_SHADE_FULL_TRANSITION_DISTANCE);
+ }
+
+ @Test
+ public void getMaxPanelTransitionDistance_expandingSplitShade_keyguard_returnsNonSplitShadeValue() {
mStatusBarStateController.setState(KEYGUARD);
- int splitShadeFullTransitionDistance = 123456;
enableSplitShade(true);
- setSplitShadeFullTransitionDistance(splitShadeFullTransitionDistance);
mNotificationPanelViewController.expandWithQs();
- int maxPanelHeight = mNotificationPanelViewController.getMaxPanelHeight();
+ int maxDistance = mNotificationPanelViewController.getMaxPanelTransitionDistance();
- assertThat(maxPanelHeight).isNotEqualTo(splitShadeFullTransitionDistance);
+ assertThat(maxDistance).isNotEqualTo(SPLIT_SHADE_FULL_TRANSITION_DISTANCE);
}
@Test
- public void getMaxPanelHeight_expanding_notSplitShade_returnsNonSplitShadeValue() {
- int splitShadeFullTransitionDistance = 123456;
+ public void getMaxPanelTransitionDistance_expanding_notSplitShade_returnsNonSplitShadeValue() {
enableSplitShade(false);
- setSplitShadeFullTransitionDistance(splitShadeFullTransitionDistance);
mNotificationPanelViewController.expandWithQs();
- int maxPanelHeight = mNotificationPanelViewController.getMaxPanelHeight();
+ int maxDistance = mNotificationPanelViewController.getMaxPanelTransitionDistance();
- assertThat(maxPanelHeight).isNotEqualTo(splitShadeFullTransitionDistance);
+ assertThat(maxDistance).isNotEqualTo(SPLIT_SHADE_FULL_TRANSITION_DISTANCE);
+ }
+
+ @Test
+ public void onLayoutChange_fullWidth_updatesQSWithFullWithTrue() {
+ mNotificationPanelViewController.mQs = mQs;
+
+ setIsFullWidth(true);
+
+ verify(mQs).setIsNotificationPanelFullWidth(true);
+ }
+
+ @Test
+ public void onLayoutChange_notFullWidth_updatesQSWithFullWithFalse() {
+ mNotificationPanelViewController.mQs = mQs;
+
+ setIsFullWidth(false);
+
+ verify(mQs).setIsNotificationPanelFullWidth(false);
+ }
+
+ @Test
+ public void onLayoutChange_qsNotSet_doesNotCrash() {
+ mNotificationPanelViewController.mQs = null;
+
+ triggerLayoutChange();
+ }
+
+ @Test
+ public void onQsFragmentAttached_fullWidth_setsFullWidthTrueOnQS() {
+ setIsFullWidth(true);
+ givenViewAttached();
+ mFragmentListener.onFragmentViewCreated(QS.TAG, mQSFragment);
+
+ verify(mQSFragment).setIsNotificationPanelFullWidth(true);
+ }
+
+ @Test
+ public void onQsFragmentAttached_notFullWidth_setsFullWidthFalseOnQS() {
+ setIsFullWidth(false);
+ givenViewAttached();
+ mFragmentListener.onFragmentViewCreated(QS.TAG, mQSFragment);
+
+ verify(mQSFragment).setIsNotificationPanelFullWidth(false);
+ }
+
+ @Test
+ public void setQsExpansion_lockscreenShadeTransitionInProgress_usesLockscreenSquishiness() {
+ float squishinessFraction = 0.456f;
+ mNotificationPanelViewController.mQs = mQs;
+ when(mLockscreenShadeTransitionController.getQsSquishTransitionFraction())
+ .thenReturn(squishinessFraction);
+ when(mNotificationStackScrollLayoutController.getNotificationSquishinessFraction())
+ .thenReturn(0.987f);
+ // Call setTransitionToFullShadeAmount to get into the full shade transition in progress
+ // state.
+ mNotificationPanelViewController.setTransitionToFullShadeAmount(
+ /* pxAmount= */ 234,
+ /* animate= */ false,
+ /* delay= */ 0
+ );
+
+ mNotificationPanelViewController.setQsExpansion(/* height= */ 123);
+
+ // First for setTransitionToFullShadeAmount and then setQsExpansion
+ verify(mQs, times(2)).setQsExpansion(
+ /* expansion= */ anyFloat(),
+ /* panelExpansionFraction= */ anyFloat(),
+ /* proposedTranslation= */ anyFloat(),
+ eq(squishinessFraction)
+ );
+ }
+
+ @Test
+ public void setQsExpansion_lockscreenShadeTransitionNotInProgress_usesStandardSquishiness() {
+ float lsSquishinessFraction = 0.456f;
+ float nsslSquishinessFraction = 0.987f;
+ mNotificationPanelViewController.mQs = mQs;
+ when(mLockscreenShadeTransitionController.getQsSquishTransitionFraction())
+ .thenReturn(lsSquishinessFraction);
+ when(mNotificationStackScrollLayoutController.getNotificationSquishinessFraction())
+ .thenReturn(nsslSquishinessFraction);
+
+ mNotificationPanelViewController.setQsExpansion(/* height= */ 123);
+
+ verify(mQs).setQsExpansion(
+ /* expansion= */ anyFloat(),
+ /* panelExpansionFraction= */ anyFloat(),
+ /* proposedTranslation= */ anyFloat(),
+ eq(nsslSquishinessFraction)
+ );
}
private static MotionEvent createMotionEvent(int x, int y, int action) {
@@ -1511,12 +1523,6 @@
}
}
- private void givenViewDetached() {
- for (View.OnAttachStateChangeListener listener : mOnAttachStateChangeListeners) {
- listener.onViewDetachedFromWindow(mView);
- }
- }
-
private ConstraintSet.Layout getConstraintSetLayout(@IdRes int id) {
ConstraintSet constraintSet = new ConstraintSet();
constraintSet.clone(mNotificationContainerParent);
@@ -1548,12 +1554,6 @@
mTouchHandler.onTouch(mView, ev);
}
- private void setSplitShadeFullTransitionDistance(int splitShadeFullTransitionDistance) {
- when(mResources.getDimensionPixelSize(R.dimen.split_shade_full_transition_distance))
- .thenReturn(splitShadeFullTransitionDistance);
- mNotificationPanelViewController.updateResources();
- }
-
private void setDozing(boolean dozing, boolean dozingAlwaysOn) {
when(mDozeParameters.getAlwaysOn()).thenReturn(dozingAlwaysOn);
mNotificationPanelViewController.setDozing(
@@ -1573,4 +1573,24 @@
assertThat(getConstraintSetLayout(R.id.keyguard_status_view).endToEnd).isEqualTo(
R.id.qs_edge_guideline);
}
+
+ private void setIsFullWidth(boolean fullWidth) {
+ float nsslWidth = fullWidth ? PANEL_WIDTH : PANEL_WIDTH / 2f;
+ when(mNotificationStackScrollLayoutController.getWidth()).thenReturn(nsslWidth);
+ triggerLayoutChange();
+ }
+
+ private void triggerLayoutChange() {
+ mLayoutChangeListener.onLayoutChange(
+ mView,
+ /* left= */ 0,
+ /* top= */ 0,
+ /* right= */ 0,
+ /* bottom= */ 0,
+ /* oldLeft= */ 0,
+ /* oldTop= */ 0,
+ /* oldRight= */ 0,
+ /* oldBottom= */ 0
+ );
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationQSContainerControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationQSContainerControllerTest.kt
index 0c6a6a9..12ef036 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationQSContainerControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationQSContainerControllerTest.kt
@@ -20,6 +20,7 @@
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
+import java.util.function.Consumer
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -33,10 +34,10 @@
import org.mockito.Mockito.eq
import org.mockito.Mockito.mock
import org.mockito.Mockito.never
+import org.mockito.Mockito.reset
import org.mockito.Mockito.verify
-import org.mockito.MockitoAnnotations
-import java.util.function.Consumer
import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
@SmallTest
@RunWith(AndroidTestingRunner::class)
@@ -63,6 +64,8 @@
@Mock
private lateinit var notificationsQSContainer: NotificationsQuickSettingsContainer
@Mock
+ private lateinit var largeScreenShadeHeaderController: LargeScreenShadeHeaderController
+ @Mock
private lateinit var featureFlags: FeatureFlags
@Captor
lateinit var navigationModeCaptor: ArgumentCaptor<ModeChangedListener>
@@ -92,6 +95,7 @@
notificationsQSContainer,
navigationModeController,
overviewProxyService,
+ largeScreenShadeHeaderController,
featureFlags,
delayableExecutor
)
@@ -371,8 +375,14 @@
container.removeAllViews()
container.addView(newViewWithId(1))
container.addView(newViewWithId(View.NO_ID))
- val controller = NotificationsQSContainerController(container, navigationModeController,
- overviewProxyService, featureFlags, delayableExecutor)
+ val controller = NotificationsQSContainerController(
+ container,
+ navigationModeController,
+ overviewProxyService,
+ largeScreenShadeHeaderController,
+ featureFlags,
+ delayableExecutor
+ )
controller.updateConstraints()
assertThat(container.getChildAt(0).id).isEqualTo(1)
@@ -397,6 +407,21 @@
verify(notificationsQSContainer).setQSContainerPaddingBottom(STABLE_INSET_BOTTOM)
}
+ @Test
+ fun testStartCustomizingWithDuration() {
+ controller.setCustomizerShowing(true, 100L)
+ verify(largeScreenShadeHeaderController).startCustomizingAnimation(true, 100L)
+ }
+
+ @Test
+ fun testEndCustomizingWithDuration() {
+ controller.setCustomizerShowing(true, 0L) // Only tracks changes
+ reset(largeScreenShadeHeaderController)
+
+ controller.setCustomizerShowing(false, 100L)
+ verify(largeScreenShadeHeaderController).startCustomizingAnimation(false, 100L)
+ }
+
private fun disableSplitShade() {
setSplitShadeEnabled(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 6d059b1..2adc389 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
@@ -19,13 +19,14 @@
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
import android.view.MotionEvent
+import android.view.ViewGroup
import androidx.test.filters.SmallTest
import com.android.keyguard.LockIconViewController
+import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.classifier.FalsingCollectorFake
import com.android.systemui.dock.DockManager
import com.android.systemui.keyguard.KeyguardUnlockAnimationController
-import com.android.systemui.lowlightclock.LowLightClockController
import com.android.systemui.shade.NotificationShadeWindowView.InteractionEventHandler
import com.android.systemui.statusbar.LockscreenShadeTransitionController
import com.android.systemui.statusbar.NotificationShadeDepthController
@@ -39,12 +40,10 @@
import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager
import com.android.systemui.statusbar.window.StatusBarWindowStateController
import com.google.common.truth.Truth.assertThat
-import java.util.Optional
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
-import org.mockito.ArgumentMatchers
import org.mockito.Mock
import org.mockito.Mockito.anyFloat
import org.mockito.Mockito.never
@@ -87,8 +86,6 @@
@Mock
private lateinit var phoneStatusBarViewController: PhoneStatusBarViewController
@Mock
- private lateinit var lowLightClockController: LowLightClockController
- @Mock
private lateinit var pulsingGestureListener: PulsingGestureListener
private lateinit var interactionEventHandlerCaptor: ArgumentCaptor<InteractionEventHandler>
@@ -114,7 +111,6 @@
statusBarKeyguardViewManager,
statusBarWindowStateController,
lockIconViewController,
- Optional.of(lowLightClockController),
centralSurfaces,
notificationShadeWindowController,
keyguardUnlockAnimationController,
@@ -254,28 +250,15 @@
}
@Test
- fun testLowLightClockAttachedWhenExpandedStatusBarSetup() {
- verify(lowLightClockController).attachLowLightClockView(ArgumentMatchers.any())
+ fun testGetBouncerContainer() {
+ underTest.bouncerContainer
+ verify(view).findViewById<ViewGroup>(R.id.keyguard_bouncer_container)
}
@Test
- fun testLowLightClockShownWhenDozing() {
- underTest.setDozing(true)
- verify(lowLightClockController).showLowLightClock(true)
- }
-
- @Test
- fun testLowLightClockDozeTimeTickCalled() {
- underTest.dozeTimeTick()
- verify(lowLightClockController).dozeTimeTick()
- }
-
- @Test
- fun testLowLightClockHiddenWhenNotDozing() {
- underTest.setDozing(true)
- verify(lowLightClockController).showLowLightClock(true)
- underTest.setDozing(false)
- verify(lowLightClockController).showLowLightClock(false)
+ fun testGetKeyguardMessageArea() {
+ underTest.keyguardMessageArea
+ verify(view).findViewById<ViewGroup>(R.id.keyguard_message_area)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.java
index 89a2518..001bfee 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.java
@@ -38,7 +38,6 @@
import com.android.systemui.classifier.FalsingCollectorFake;
import com.android.systemui.dock.DockManager;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
-import com.android.systemui.lowlightclock.LowLightClockController;
import com.android.systemui.statusbar.DragDownHelper;
import com.android.systemui.statusbar.LockscreenShadeTransitionController;
import com.android.systemui.statusbar.NotificationShadeDepthController;
@@ -61,8 +60,6 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import java.util.Optional;
-
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
@SmallTest
@@ -86,7 +83,6 @@
@Mock private StatusBarWindowStateController mStatusBarWindowStateController;
@Mock private LockscreenShadeTransitionController mLockscreenShadeTransitionController;
@Mock private LockIconViewController mLockIconViewController;
- @Mock private LowLightClockController mLowLightClockController;
@Mock private KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
@Mock private AmbientState mAmbientState;
@Mock private PulsingGestureListener mPulsingGestureListener;
@@ -121,7 +117,6 @@
mStatusBarKeyguardViewManager,
mStatusBarWindowStateController,
mLockIconViewController,
- Optional.of(mLowLightClockController),
mCentralSurfaces,
mNotificationShadeWindowController,
mKeyguardUnlockAnimationController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/PulsingGestureListenerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/PulsingGestureListenerTest.kt
index d2970a6..97c0bb2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/PulsingGestureListenerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/PulsingGestureListenerTest.kt
@@ -27,6 +27,7 @@
import com.android.systemui.dock.DockManager
import com.android.systemui.dump.DumpManager
import com.android.systemui.plugins.FalsingManager
+import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.phone.CentralSurfaces
import com.android.systemui.tuner.TunerService
import com.android.systemui.tuner.TunerService.Tunable
@@ -63,6 +64,8 @@
private lateinit var tunerService: TunerService
@Mock
private lateinit var dumpManager: DumpManager
+ @Mock
+ private lateinit var statusBarStateController: StatusBarStateController
private lateinit var tunableCaptor: ArgumentCaptor<Tunable>
private lateinit var underTest: PulsingGestureListener
@@ -77,6 +80,7 @@
dockManager,
centralSurfaces,
ambientDisplayConfiguration,
+ statusBarStateController,
tunerService,
dumpManager
)
@@ -85,6 +89,8 @@
@Test
fun testGestureDetector_singleTapEnabled() {
+ whenever(statusBarStateController.isPulsing).thenReturn(true)
+
// GIVEN tap is enabled, prox not covered
whenever(ambientDisplayConfiguration.tapGestureEnabled(anyInt())).thenReturn(true)
updateSettings()
@@ -102,6 +108,8 @@
@Test
fun testGestureDetector_doubleTapEnabled() {
+ whenever(statusBarStateController.isPulsing).thenReturn(true)
+
// GIVEN double tap is enabled, prox not covered
whenever(ambientDisplayConfiguration.doubleTapGestureEnabled(anyInt())).thenReturn(true)
updateSettings()
@@ -119,6 +127,8 @@
@Test
fun testGestureDetector_singleTapEnabled_falsing() {
+ whenever(statusBarStateController.isPulsing).thenReturn(true)
+
// GIVEN tap is enabled, prox not covered
whenever(ambientDisplayConfiguration.tapGestureEnabled(anyInt())).thenReturn(true)
updateSettings()
@@ -135,7 +145,23 @@
}
@Test
+ fun testGestureDetector_notPulsing_noFalsingCheck() {
+ whenever(statusBarStateController.isPulsing).thenReturn(false)
+
+ // GIVEN tap is enabled, prox not covered
+ whenever(ambientDisplayConfiguration.tapGestureEnabled(anyInt())).thenReturn(true)
+ // WHEN there's a tap
+ underTest.onSingleTapConfirmed(downEv)
+
+ // THEN the falsing manager never gets a call (because the device wasn't pulsing
+ // during the tap)
+ verify(falsingManager, never()).isFalseTap(anyInt())
+ }
+
+ @Test
fun testGestureDetector_doubleTapEnabled_falsing() {
+ whenever(statusBarStateController.isPulsing).thenReturn(true)
+
// GIVEN double tap is enabled, prox not covered
whenever(ambientDisplayConfiguration.doubleTapGestureEnabled(anyInt())).thenReturn(true)
updateSettings()
@@ -153,6 +179,8 @@
@Test
fun testGestureDetector_singleTapEnabled_proxCovered() {
+ whenever(statusBarStateController.isPulsing).thenReturn(true)
+
// GIVEN tap is enabled, not a false tap based on classifiers
whenever(ambientDisplayConfiguration.tapGestureEnabled(anyInt())).thenReturn(true)
updateSettings()
@@ -170,6 +198,8 @@
@Test
fun testGestureDetector_doubleTapEnabled_proxCovered() {
+ whenever(statusBarStateController.isPulsing).thenReturn(true)
+
// GIVEN double tap is enabled, not a false tap based on classifiers
whenever(ambientDisplayConfiguration.doubleTapGestureEnabled(anyInt())).thenReturn(true)
updateSettings()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/transition/ScrimShadeTransitionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/transition/ScrimShadeTransitionControllerTest.kt
index baaa447..6be76a6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/transition/ScrimShadeTransitionControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/transition/ScrimShadeTransitionControllerTest.kt
@@ -13,6 +13,7 @@
import com.android.systemui.statusbar.phone.panelstate.STATE_OPEN
import com.android.systemui.statusbar.phone.panelstate.STATE_OPENING
import com.android.systemui.statusbar.policy.FakeConfigurationController
+import com.android.systemui.statusbar.policy.HeadsUpManager
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -28,6 +29,7 @@
@Mock private lateinit var scrimController: ScrimController
@Mock private lateinit var dumpManager: DumpManager
@Mock private lateinit var statusBarStateController: SysuiStatusBarStateController
+ @Mock private lateinit var headsUpManager: HeadsUpManager
private val configurationController = FakeConfigurationController()
private lateinit var controller: ScrimShadeTransitionController
@@ -42,7 +44,8 @@
dumpManager,
scrimController,
context.resources,
- statusBarStateController)
+ statusBarStateController,
+ headsUpManager)
controller.onPanelStateChanged(STATE_OPENING)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/DragDownHelperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/DragDownHelperTest.kt
new file mode 100644
index 0000000..d925d0a
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/DragDownHelperTest.kt
@@ -0,0 +1,83 @@
+/*
+ * 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
+
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import androidx.test.filters.SmallTest
+import com.android.systemui.ExpandHelper
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.classifier.FalsingCollector
+import com.android.systemui.plugins.FalsingManager
+import com.android.systemui.statusbar.notification.row.ExpandableView
+import com.android.systemui.util.mockito.mock
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.anyInt
+import org.mockito.Mockito.atLeast
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when` as whenever
+
+@SmallTest
+@TestableLooper.RunWithLooper
+@RunWith(AndroidTestingRunner::class)
+class DragDownHelperTest : SysuiTestCase() {
+
+ private lateinit var dragDownHelper: DragDownHelper
+
+ private val collapsedHeight = 300
+ private val falsingManager: FalsingManager = mock()
+ private val falsingCollector: FalsingCollector = mock()
+ private val dragDownloadCallback: LockscreenShadeTransitionController = mock()
+ private val expandableView: ExpandableView = mock()
+ private val expandCallback: ExpandHelper.Callback = mock()
+
+ @Before
+ fun setUp() {
+ whenever(expandableView.collapsedHeight).thenReturn(collapsedHeight)
+
+ dragDownHelper = DragDownHelper(
+ falsingManager,
+ falsingCollector,
+ dragDownloadCallback,
+ mContext
+ ).also {
+ it.expandCallback = expandCallback
+ }
+ }
+
+ @Test
+ fun cancelChildExpansion_updateHeight() {
+ whenever(expandableView.actualHeight).thenReturn(500)
+
+ dragDownHelper.cancelChildExpansion(expandableView, animationDuration = 0)
+
+ verify(expandableView, atLeast(1)).actualHeight = collapsedHeight
+ }
+
+ @Test
+ fun cancelChildExpansion_dontUpdateHeight() {
+ whenever(expandableView.actualHeight).thenReturn(collapsedHeight)
+
+ dragDownHelper.cancelChildExpansion(expandableView, animationDuration = 0)
+
+ verify(expandableView, never()).actualHeight = anyInt()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
index 798f47d..ac8874b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
@@ -19,6 +19,7 @@
import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_DEFAULT;
import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_FINANCED;
import static android.content.pm.UserInfo.FLAG_MANAGED_PROFILE;
+import static android.hardware.biometrics.BiometricFaceConstants.FACE_ERROR_TIMEOUT;
import static com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_HELP_FINGERPRINT_NOT_RECOGNIZED;
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_ALIGNMENT;
@@ -65,7 +66,6 @@
import android.graphics.Color;
import android.hardware.biometrics.BiometricFaceConstants;
import android.hardware.biometrics.BiometricSourceType;
-import android.hardware.face.FaceManager;
import android.hardware.fingerprint.FingerprintManager;
import android.os.BatteryManager;
import android.os.Looper;
@@ -602,7 +602,7 @@
String message = mContext.getString(R.string.keyguard_unlock);
mController.setVisible(true);
- mController.getKeyguardCallback().onBiometricError(FaceManager.FACE_ERROR_TIMEOUT,
+ mController.getKeyguardCallback().onBiometricError(FACE_ERROR_TIMEOUT,
"A message", BiometricSourceType.FACE);
verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE, message);
@@ -636,10 +636,10 @@
when(mKeyguardUpdateMonitor.isFaceEnrolled()).thenReturn(true);
mController.setVisible(true);
- mController.getKeyguardCallback().onBiometricError(FaceManager.FACE_ERROR_TIMEOUT,
+ mController.getKeyguardCallback().onBiometricError(FACE_ERROR_TIMEOUT,
"A message", BiometricSourceType.FACE);
- verify(mStatusBarKeyguardViewManager).showBouncerMessage(eq(message), any());
+ verify(mStatusBarKeyguardViewManager).setKeyguardMessage(eq(message), any());
}
@Test
@@ -651,7 +651,7 @@
mController.setVisible(true);
mController.getKeyguardCallback().onBiometricError(
- FaceManager.FACE_ERROR_TIMEOUT, message, BiometricSourceType.FACE);
+ FACE_ERROR_TIMEOUT, message, BiometricSourceType.FACE);
verifyNoMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE);
}
@@ -698,8 +698,7 @@
BiometricFaceConstants.FACE_ACQUIRED_TOO_LEFT,
BiometricFaceConstants.FACE_ACQUIRED_TOO_HIGH,
BiometricFaceConstants.FACE_ACQUIRED_TOO_LOW,
- BiometricFaceConstants.FACE_ACQUIRED_TOO_BRIGHT,
- BiometricFaceConstants.FACE_ACQUIRED_TOO_DARK
+ BiometricFaceConstants.FACE_ACQUIRED_TOO_BRIGHT
};
for (int msgId : msgIds) {
mKeyguardUpdateMonitorCallback.onBiometricHelp(
@@ -728,8 +727,7 @@
BiometricFaceConstants.FACE_ACQUIRED_TOO_LEFT,
BiometricFaceConstants.FACE_ACQUIRED_TOO_HIGH,
BiometricFaceConstants.FACE_ACQUIRED_TOO_LOW,
- BiometricFaceConstants.FACE_ACQUIRED_TOO_BRIGHT,
- BiometricFaceConstants.FACE_ACQUIRED_TOO_DARK
+ BiometricFaceConstants.FACE_ACQUIRED_TOO_BRIGHT
};
for (int msgId : msgIds) {
final String numberedHelpString = helpString + msgId;
@@ -743,6 +741,64 @@
}
@Test
+ public void sendTooDarkFaceHelpMessages_onTimeout_noFpEnrolled() {
+ createController();
+
+ // GIVEN fingerprint NOT enrolled
+ when(mKeyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible(
+ 0)).thenReturn(false);
+
+ // WHEN help message received
+ final String helpString = "helpMsg";
+ mKeyguardUpdateMonitorCallback.onBiometricHelp(
+ BiometricFaceConstants.FACE_ACQUIRED_TOO_DARK,
+ helpString,
+ BiometricSourceType.FACE
+ );
+
+ // THEN help message not shown yet
+ verifyNoMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE);
+
+ // WHEN face timeout error received
+ mKeyguardUpdateMonitorCallback.onBiometricError(FACE_ERROR_TIMEOUT, "face timeout",
+ BiometricSourceType.FACE);
+
+ // THEN the low light message shows with suggestion to swipe up to unlock
+ verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE, helpString);
+ verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP,
+ mContext.getString(R.string.keyguard_unlock));
+ }
+
+ @Test
+ public void sendTooDarkFaceHelpMessages_onTimeout_fingerprintEnrolled() {
+ createController();
+
+ // GIVEN fingerprint enrolled
+ when(mKeyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible(
+ 0)).thenReturn(true);
+
+ // WHEN help message received
+ final String helpString = "helpMsg";
+ mKeyguardUpdateMonitorCallback.onBiometricHelp(
+ BiometricFaceConstants.FACE_ACQUIRED_TOO_DARK,
+ helpString,
+ BiometricSourceType.FACE
+ );
+
+ // THEN help message not shown yet
+ verifyNoMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE);
+
+ // WHEN face timeout error received
+ mKeyguardUpdateMonitorCallback.onBiometricError(FACE_ERROR_TIMEOUT, "face timeout",
+ BiometricSourceType.FACE);
+
+ // THEN the low light message shows and suggests trying fingerprint
+ verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE, helpString);
+ verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP,
+ mContext.getString(R.string.keyguard_suggest_fingerprint));
+ }
+
+ @Test
public void updateMonitor_listenerUpdatesIndication() {
createController();
String restingIndication = "Resting indication";
@@ -994,14 +1050,14 @@
}
@Test
- public void onTrustGrantedMessageDoesShowsOnTrustGranted() {
+ public void onTrustGrantedMessageShowsOnTrustGranted() {
createController();
mController.setVisible(true);
// GIVEN trust is granted
when(mKeyguardUpdateMonitor.getUserHasTrust(anyInt())).thenReturn(true);
- // WHEN the showTrustGranted message is called
+ // WHEN the showTrustGranted method is called
final String trustGrantedMsg = "testing trust granted message";
mController.getKeyguardCallback().showTrustGrantedMessage(trustGrantedMsg);
@@ -1012,6 +1068,38 @@
}
@Test
+ public void onTrustGrantedMessage_nullMessage_showsDefaultMessage() {
+ createController();
+ mController.setVisible(true);
+
+ // GIVEN trust is granted
+ when(mKeyguardUpdateMonitor.getUserHasTrust(anyInt())).thenReturn(true);
+
+ // WHEN the showTrustGranted method is called with a null message
+ mController.getKeyguardCallback().showTrustGrantedMessage(null);
+
+ // THEN verify the default trust granted message shows
+ verifyIndicationMessage(
+ INDICATION_TYPE_TRUST,
+ getContext().getString(R.string.keyguard_indication_trust_unlocked));
+ }
+
+ @Test
+ public void onTrustGrantedMessage_emptyString_showsNoMessage() {
+ createController();
+ mController.setVisible(true);
+
+ // GIVEN trust is granted
+ when(mKeyguardUpdateMonitor.getUserHasTrust(anyInt())).thenReturn(true);
+
+ // WHEN the showTrustGranted method is called with an EMPTY string
+ mController.getKeyguardCallback().showTrustGrantedMessage("");
+
+ // THEN verify NO trust message is shown
+ verifyNoMessage(INDICATION_TYPE_TRUST);
+ }
+
+ @Test
public void coEx_faceSuccess_showsPressToOpen() {
// GIVEN bouncer isn't showing, can skip bouncer, udfps is supported, no a11y enabled
when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(false);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeQsTransitionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeQsTransitionControllerTest.kt
new file mode 100644
index 0000000..7041262
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeQsTransitionControllerTest.kt
@@ -0,0 +1,255 @@
+/*
+ * 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
+
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.plugins.qs.QS
+import com.android.systemui.statusbar.policy.FakeConfigurationController
+import com.google.common.truth.Expect
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class LockscreenShadeQsTransitionControllerTest : SysuiTestCase() {
+
+ private val configurationController = FakeConfigurationController()
+
+ @get:Rule val expect: Expect = Expect.create()
+
+ @Mock private lateinit var dumpManager: DumpManager
+ @Mock private lateinit var qS: QS
+
+ private lateinit var controller: LockscreenShadeQsTransitionController
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ setTransitionDistance(TRANSITION_DISTANCE)
+ setTransitionDelay(TRANSITION_DELAY)
+ setSquishTransitionDistance(SQUISH_TRANSITION_DISTANCE)
+ setSquishStartFraction(SQUISH_START_FRACTION)
+
+ controller =
+ LockscreenShadeQsTransitionController(
+ context,
+ configurationController,
+ dumpManager,
+ qsProvider = { qS }
+ )
+ }
+
+ @Test
+ fun qsTransitionFraction_byDefault_returns0() {
+ assertThat(controller.qsTransitionFraction).isZero()
+ }
+
+ @Test
+ fun qsTransitionFraction_noStartDelay_returnsBasedOnTransitionDistance() {
+ setTransitionDelay(0)
+ setTransitionDistance(100)
+
+ controller.dragDownAmount = 25f
+ expect.that(controller.qsTransitionFraction).isEqualTo(0.25f)
+
+ controller.dragDownAmount = 50f
+ expect.that(controller.qsTransitionFraction).isEqualTo(0.5f)
+
+ controller.dragDownAmount = 75f
+ expect.that(controller.qsTransitionFraction).isEqualTo(0.75f)
+
+ controller.dragDownAmount = 100f
+ expect.that(controller.qsTransitionFraction).isEqualTo(1f)
+ }
+
+ @Test
+ fun qsTransitionFraction_noStartDelay_returnsValuesBetween0and1() {
+ setTransitionDelay(0)
+ setTransitionDistance(100)
+
+ controller.dragDownAmount = -500f
+ expect.that(controller.qsTransitionFraction).isEqualTo(0f)
+
+ controller.dragDownAmount = 500f
+ expect.that(controller.qsTransitionFraction).isEqualTo(1f)
+ }
+
+ @Test
+ fun qsTransitionFraction_withStartDelay_returnsBasedOnTransitionDistanceAndDelay() {
+ setTransitionDelay(10)
+ setTransitionDistance(100)
+
+ controller.dragDownAmount = 0f
+ expect.that(controller.qsTransitionFraction).isEqualTo(0f)
+
+ controller.dragDownAmount = 10f
+ expect.that(controller.qsTransitionFraction).isEqualTo(0f)
+
+ controller.dragDownAmount = 25f
+ expect.that(controller.qsTransitionFraction).isEqualTo(0.15f)
+
+ controller.dragDownAmount = 100f
+ expect.that(controller.qsTransitionFraction).isEqualTo(0.9f)
+
+ controller.dragDownAmount = 110f
+ expect.that(controller.qsTransitionFraction).isEqualTo(1f)
+ }
+
+ @Test
+ fun qsTransitionFraction_withStartDelay_returnsValuesBetween0and1() {
+ setTransitionDelay(10)
+ setTransitionDistance(100)
+
+ controller.dragDownAmount = -500f
+ expect.that(controller.qsTransitionFraction).isEqualTo(0f)
+
+ controller.dragDownAmount = 500f
+ expect.that(controller.qsTransitionFraction).isEqualTo(1f)
+ }
+
+ @Test
+ fun qsSquishTransitionFraction_byDefault_returnsValueSetFromResource() {
+ assertThat(controller.qsSquishTransitionFraction).isEqualTo(SQUISH_START_FRACTION)
+ }
+
+ @Test
+ fun qsSquishTransitionFraction_noStartDelay_startFraction0_returnsBasedOnTransitionDistance() {
+ setTransitionDelay(0)
+ setSquishStartFraction(0f)
+ setSquishTransitionDistance(1000)
+
+ controller.dragDownAmount = 250f
+ expect.that(controller.qsSquishTransitionFraction).isEqualTo(0.25f)
+
+ controller.dragDownAmount = 500f
+ expect.that(controller.qsSquishTransitionFraction).isEqualTo(0.5f)
+
+ controller.dragDownAmount = 750f
+ expect.that(controller.qsSquishTransitionFraction).isEqualTo(0.75f)
+
+ controller.dragDownAmount = 1000f
+ expect.that(controller.qsSquishTransitionFraction).isEqualTo(1f)
+ }
+
+ @Test
+ fun qsSquishTransitionFraction_startDelay_startFraction0_basedOnTransitionDistanceAndDelay() {
+ setTransitionDelay(100)
+ setSquishStartFraction(0f)
+ setSquishTransitionDistance(1000)
+
+ controller.dragDownAmount = 250f
+ expect.that(controller.qsSquishTransitionFraction).isEqualTo(0.15f)
+
+ controller.dragDownAmount = 500f
+ expect.that(controller.qsSquishTransitionFraction).isEqualTo(0.4f)
+
+ controller.dragDownAmount = 750f
+ expect.that(controller.qsSquishTransitionFraction).isEqualTo(0.65f)
+
+ controller.dragDownAmount = 1000f
+ expect.that(controller.qsSquishTransitionFraction).isEqualTo(0.9f)
+
+ controller.dragDownAmount = 1100f
+ expect.that(controller.qsSquishTransitionFraction).isEqualTo(1f)
+ }
+
+ @Test
+ fun qsSquishTransitionFraction_noStartDelay_startFractionSet_returnsBasedOnStartAndDistance() {
+ setTransitionDelay(0)
+ setSquishStartFraction(0.5f)
+ setSquishTransitionDistance(1000)
+
+ controller.dragDownAmount = 0f
+ expect.that(controller.qsSquishTransitionFraction).isEqualTo(0.5f)
+
+ controller.dragDownAmount = 500f
+ expect.that(controller.qsSquishTransitionFraction).isEqualTo(0.75f)
+
+ controller.dragDownAmount = 1000f
+ expect.that(controller.qsSquishTransitionFraction).isEqualTo(1f)
+ }
+
+ @Test
+ fun qsSquishTransitionFraction_startDelay_startFractionSet_basedOnStartAndDistanceAndDelay() {
+ setTransitionDelay(10)
+ setSquishStartFraction(0.5f)
+ setSquishTransitionDistance(100)
+
+ controller.dragDownAmount = 0f
+ expect.that(controller.qsSquishTransitionFraction).isEqualTo(0.5f)
+
+ controller.dragDownAmount = 50f
+ expect.that(controller.qsSquishTransitionFraction).isEqualTo(0.7f)
+
+ controller.dragDownAmount = 100f
+ expect.that(controller.qsSquishTransitionFraction).isEqualTo(0.95f)
+
+ controller.dragDownAmount = 110f
+ expect.that(controller.qsSquishTransitionFraction).isEqualTo(1f)
+ }
+
+ @Test
+ fun onDragDownAmountChanged_setsValuesOnQS() {
+ val rawDragAmount = 200f
+
+ controller.dragDownAmount = rawDragAmount
+
+ verify(qS)
+ .setTransitionToFullShadeProgress(
+ /* isTransitioningToFullShade= */ true,
+ /* transitionFraction= */ controller.qsTransitionFraction,
+ /* squishinessFraction= */ controller.qsSquishTransitionFraction
+ )
+ }
+
+ private fun setTransitionDistance(value: Int) {
+ overrideResource(R.dimen.lockscreen_shade_qs_transition_distance, value)
+ configurationController.notifyConfigurationChanged()
+ }
+
+ private fun setTransitionDelay(value: Int) {
+ overrideResource(R.dimen.lockscreen_shade_qs_transition_delay, value)
+ configurationController.notifyConfigurationChanged()
+ }
+
+ private fun setSquishTransitionDistance(value: Int) {
+ overrideResource(R.dimen.lockscreen_shade_qs_squish_transition_distance, value)
+ configurationController.notifyConfigurationChanged()
+ }
+
+ private fun setSquishStartFraction(value: Float) {
+ overrideResource(R.dimen.lockscreen_shade_qs_squish_start_fraction, value)
+ configurationController.notifyConfigurationChanged()
+ }
+
+ companion object {
+ private const val TRANSITION_DELAY = 123
+ private const val TRANSITION_DISTANCE = 321
+ private const val SQUISH_START_FRACTION = 0.123f
+ private const val SQUISH_TRANSITION_DISTANCE = 456
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
index fe1cd97..8643e86 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
@@ -1,9 +1,9 @@
package com.android.systemui.statusbar
-import android.test.suitebuilder.annotation.SmallTest
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.testing.TestableLooper.RunWithLooper
+import androidx.test.filters.SmallTest
import com.android.systemui.ExpandHelper
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
@@ -78,6 +78,7 @@
@Mock lateinit var qS: QS
@Mock lateinit var singleShadeOverScroller: SingleShadeLockScreenOverScroller
@Mock lateinit var splitShadeOverScroller: SplitShadeLockScreenOverScroller
+ @Mock lateinit var qsTransitionController: LockscreenShadeQsTransitionController
@JvmField @Rule val mockito = MockitoJUnit.rule()
private val configurationController = FakeConfigurationController()
@@ -120,7 +121,9 @@
context,
configurationController,
dumpManager)
- })
+ },
+ qsTransitionControllerFactory = { qsTransitionController },
+ )
whenever(nsslController.view).thenReturn(stackscroller)
whenever(nsslController.expandHelperCallback).thenReturn(expandHelperCallback)
transitionController.notificationPanelController = notificationPanelController
@@ -249,7 +252,7 @@
verify(scrimController, never()).setTransitionToFullShadeProgress(anyFloat(), anyFloat())
verify(notificationPanelController, never()).setTransitionToFullShadeAmount(anyFloat(),
anyBoolean(), anyLong())
- verify(qS, never()).setTransitionToFullShadeAmount(anyFloat(), anyFloat())
+ verify(qsTransitionController, never()).dragDownAmount = anyFloat()
}
@Test
@@ -260,7 +263,7 @@
verify(scrimController).setTransitionToFullShadeProgress(anyFloat(), anyFloat())
verify(notificationPanelController).setTransitionToFullShadeAmount(anyFloat(),
anyBoolean(), anyLong())
- verify(qS).setTransitionToFullShadeAmount(anyFloat(), anyFloat())
+ verify(qsTransitionController).dragDownAmount = 10f
verify(depthController).transitionToFullShadeProgress = anyFloat()
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java
index 0fd2e38..5432a74 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java
@@ -28,12 +28,9 @@
import com.android.systemui.Dependency;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.shade.ShadeController;
-import com.android.systemui.statusbar.notification.NotificationEntryListener;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager.OnSettingsClickListener;
-import com.android.systemui.statusbar.notification.row.NotificationInfo.CheckSaveListener;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import org.junit.Before;
@@ -54,10 +51,8 @@
public class NonPhoneDependencyTest extends SysuiTestCase {
@Mock private NotificationPresenter mPresenter;
@Mock private NotificationListContainer mListContainer;
- @Mock private NotificationEntryListener mEntryListener;
@Mock private RemoteInputController.Delegate mDelegate;
@Mock private NotificationRemoteInputManager.Callback mRemoteInputManagerCallback;
- @Mock private CheckSaveListener mCheckSaveListener;
@Mock private OnSettingsClickListener mOnSettingsClickListener;
@Before
@@ -72,7 +67,6 @@
@Test
public void testNotificationManagementCodeHasNoDependencyOnStatusBarWindowManager() {
mDependency.injectMockDependency(ShadeController.class);
- NotificationEntryManager entryManager = Dependency.get(NotificationEntryManager.class);
NotificationGutsManager gutsManager = Dependency.get(NotificationGutsManager.class);
NotificationLogger notificationLogger = Dependency.get(NotificationLogger.class);
NotificationMediaManager mediaManager = Dependency.get(NotificationMediaManager.class);
@@ -80,7 +74,6 @@
Dependency.get(NotificationRemoteInputManager.class);
NotificationLockscreenUserManager lockscreenUserManager =
Dependency.get(NotificationLockscreenUserManager.class);
- entryManager.addNotificationEntryListener(mEntryListener);
gutsManager.setUpWithPresenter(mPresenter, mListContainer,
mOnSettingsClickListener);
notificationLogger.setUpWithContainer(mListContainer);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
index 3cc4ee1..853d1df 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
@@ -21,7 +21,6 @@
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -54,7 +53,6 @@
import com.android.systemui.dump.DumpManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.NotificationLockscreenUserManager.NotificationStateChangedListener;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
@@ -84,8 +82,6 @@
@Mock
private NotificationVisibilityProvider mVisibilityProvider;
@Mock
- private NotificationEntryManager mEntryManager;
- @Mock
private CommonNotifCollection mNotifCollection;
@Mock
private DevicePolicyManager mDevicePolicyManager;
@@ -114,7 +110,6 @@
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- mDependency.injectTestDependency(NotificationEntryManager.class, mEntryManager);
int currentUserId = ActivityManager.getCurrentUser();
mSettings = new FakeSettings();
@@ -149,12 +144,6 @@
}
@Test
- public void testLockScreenShowNotificationsChangeUpdatesNotifications() {
- mLockscreenUserManager.getLockscreenSettingsObserverForTest().onChange(false);
- verify(mEntryManager, times(1)).updateNotifications(anyString());
- }
-
- @Test
public void testLockScreenShowNotificationsFalse() {
mSettings.putInt(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0);
mLockscreenUserManager.getLockscreenSettingsObserverForTest().onChange(false);
@@ -297,13 +286,6 @@
}
@Test
- public void testSettingsObserverUpdatesNotifications() {
- when(mDeviceProvisionedController.isDeviceProvisioned()).thenReturn(true);
- mLockscreenUserManager.getSettingsObserverForTest().onChange(false);
- verify(mEntryManager, times(1)).updateNotifications(anyString());
- }
-
- @Test
public void testActionUserSwitchedCallsOnUserSwitched() {
Intent intent = new Intent()
.setAction(ACTION_USER_SWITCHED)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
index 6e29669..5170678 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
@@ -23,8 +23,6 @@
import android.app.Notification;
import android.content.Context;
-import android.os.Handler;
-import android.os.Looper;
import android.os.SystemClock;
import android.os.UserHandle;
import android.testing.AndroidTestingRunner;
@@ -36,7 +34,6 @@
import com.android.systemui.dump.DumpManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.notification.NotifPipelineFlags;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider;
@@ -70,7 +67,6 @@
@Mock private StatusBarStateController mStateController;
@Mock private RemoteInputUriController mRemoteInputUriController;
@Mock private NotificationClickNotifier mClickNotifier;
- @Mock private NotificationEntryManager mEntryManager;
@Mock private NotificationLockscreenUserManager mLockscreenUserManager;
private TestableNotificationRemoteInputManager mRemoteInputManager;
@@ -85,11 +81,8 @@
mLockscreenUserManager,
mSmartReplyController,
mVisibilityProvider,
- mEntryManager,
- mock(RemoteInputNotificationRebuilder.class),
() -> Optional.of(mock(CentralSurfaces.class)),
mStateController,
- Handler.createAsync(Looper.myLooper()),
mRemoteInputUriController,
mClickNotifier,
mock(ActionClickLogger.class),
@@ -145,11 +138,8 @@
NotificationLockscreenUserManager lockscreenUserManager,
SmartReplyController smartReplyController,
NotificationVisibilityProvider visibilityProvider,
- NotificationEntryManager notificationEntryManager,
- RemoteInputNotificationRebuilder rebuilder,
Lazy<Optional<CentralSurfaces>> centralSurfacesOptionalLazy,
StatusBarStateController statusBarStateController,
- Handler mainHandler,
RemoteInputUriController remoteInputUriController,
NotificationClickNotifier clickNotifier,
ActionClickLogger actionClickLogger,
@@ -160,7 +150,6 @@
lockscreenUserManager,
smartReplyController,
visibilityProvider,
- notificationEntryManager,
centralSurfacesOptionalLazy,
statusBarStateController,
remoteInputUriController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
index b166b73..6446fb5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
@@ -48,7 +48,6 @@
import org.mockito.Captor
import org.mockito.Mock
import org.mockito.Mockito
-import org.mockito.Mockito.`when`
import org.mockito.Mockito.any
import org.mockito.Mockito.anyFloat
import org.mockito.Mockito.anyString
@@ -56,6 +55,7 @@
import org.mockito.Mockito.never
import org.mockito.Mockito.reset
import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when`
import org.mockito.junit.MockitoJUnit
@RunWith(AndroidTestingRunner::class)
@@ -139,7 +139,7 @@
notificationShadeDepthController.onPanelExpansionChanged(
PanelExpansionChangeEvent(
fraction = 1f, expanded = true, tracking = false, dragDownPxAmount = 0f))
- verify(shadeAnimation).animateTo(eq(maxBlur), any())
+ verify(shadeAnimation).animateTo(eq(maxBlur))
}
@Test
@@ -147,7 +147,7 @@
notificationShadeDepthController.onPanelExpansionChanged(
PanelExpansionChangeEvent(
fraction = 0.01f, expanded = false, tracking = false, dragDownPxAmount = 0f))
- verify(shadeAnimation).animateTo(eq(maxBlur), any())
+ verify(shadeAnimation).animateTo(eq(maxBlur))
}
@Test
@@ -157,7 +157,7 @@
notificationShadeDepthController.onPanelExpansionChanged(
PanelExpansionChangeEvent(
fraction = 0f, expanded = false, tracking = false, dragDownPxAmount = 0f))
- verify(shadeAnimation).animateTo(eq(0), any())
+ verify(shadeAnimation).animateTo(eq(0))
}
@Test
@@ -168,15 +168,15 @@
onPanelExpansionChanged_apliesBlur_ifShade()
clearInvocations(shadeAnimation)
notificationShadeDepthController.onPanelExpansionChanged(event)
- verify(shadeAnimation, never()).animateTo(anyInt(), any())
+ verify(shadeAnimation, never()).animateTo(anyInt())
notificationShadeDepthController.onPanelExpansionChanged(
event.copy(fraction = 0.9f, tracking = true))
- verify(shadeAnimation, never()).animateTo(anyInt(), any())
+ verify(shadeAnimation, never()).animateTo(anyInt())
notificationShadeDepthController.onPanelExpansionChanged(
event.copy(fraction = 0.8f, tracking = false))
- verify(shadeAnimation).animateTo(eq(0), any())
+ verify(shadeAnimation).animateTo(eq(0))
}
@Test
@@ -186,7 +186,7 @@
notificationShadeDepthController.onPanelExpansionChanged(
PanelExpansionChangeEvent(
fraction = 0.6f, expanded = true, tracking = true, dragDownPxAmount = 0f))
- verify(shadeAnimation).animateTo(eq(maxBlur), any())
+ verify(shadeAnimation).animateTo(eq(maxBlur))
}
@Test
@@ -212,7 +212,7 @@
statusBarState = StatusBarState.KEYGUARD
statusBarStateListener.onStateChanged(statusBarState)
- verify(shadeAnimation).animateTo(eq(0), any())
+ verify(shadeAnimation).animateTo(eq(0))
}
@Test
@@ -395,13 +395,13 @@
@Test
fun brightnessMirrorVisible_whenVisible() {
notificationShadeDepthController.brightnessMirrorVisible = true
- verify(brightnessSpring).animateTo(eq(maxBlur), any())
+ verify(brightnessSpring).animateTo(eq(maxBlur))
}
@Test
fun brightnessMirrorVisible_whenHidden() {
notificationShadeDepthController.brightnessMirrorVisible = false
- verify(brightnessSpring).animateTo(eq(0), any())
+ verify(brightnessSpring).animateTo(eq(0))
}
@Test
@@ -424,7 +424,7 @@
fun ignoreShadeBlurUntilHidden_whennNull_ignoresIfShadeHasNoBlur() {
`when`(shadeAnimation.radius).thenReturn(0f)
notificationShadeDepthController.blursDisabledForAppLaunch = true
- verify(shadeAnimation, never()).animateTo(anyInt(), any())
+ verify(shadeAnimation, never()).animateTo(anyInt())
}
private fun enableSplitShade() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/PulseExpansionHandlerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/PulseExpansionHandlerTest.kt
new file mode 100644
index 0000000..44cbe51
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/PulseExpansionHandlerTest.kt
@@ -0,0 +1,100 @@
+/*
+ * 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
+
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.classifier.FalsingCollector
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.plugins.FalsingManager
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator
+import com.android.systemui.statusbar.notification.row.ExpandableView
+import com.android.systemui.statusbar.notification.stack.NotificationRoundnessManager
+import com.android.systemui.statusbar.phone.HeadsUpManagerPhone
+import com.android.systemui.statusbar.phone.KeyguardBypassController
+import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.util.mockito.mock
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.anyInt
+import org.mockito.Mockito.atLeast
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when` as whenever
+
+@SmallTest
+@TestableLooper.RunWithLooper
+@RunWith(AndroidTestingRunner::class)
+class PulseExpansionHandlerTest : SysuiTestCase() {
+
+ private lateinit var pulseExpansionHandler: PulseExpansionHandler
+
+ private val collapsedHeight = 300
+ private val wakeUpCoordinator: NotificationWakeUpCoordinator = mock()
+ private val bypassController: KeyguardBypassController = mock()
+ private val headsUpManager: HeadsUpManagerPhone = mock()
+ private val roundnessManager: NotificationRoundnessManager = mock()
+ private val configurationController: ConfigurationController = mock()
+ private val statusBarStateController: StatusBarStateController = mock()
+ private val falsingManager: FalsingManager = mock()
+ private val lockscreenShadeTransitionController: LockscreenShadeTransitionController = mock()
+ private val falsingCollector: FalsingCollector = mock()
+ private val dumpManager: DumpManager = mock()
+ private val expandableView: ExpandableView = mock()
+
+ @Before
+ fun setUp() {
+ whenever(expandableView.collapsedHeight).thenReturn(collapsedHeight)
+
+ pulseExpansionHandler = PulseExpansionHandler(
+ mContext,
+ wakeUpCoordinator,
+ bypassController,
+ headsUpManager,
+ roundnessManager,
+ configurationController,
+ statusBarStateController,
+ falsingManager,
+ lockscreenShadeTransitionController,
+ falsingCollector,
+ dumpManager
+ )
+ }
+
+ @Test
+ fun resetChild_updateHeight() {
+ whenever(expandableView.actualHeight).thenReturn(500)
+
+ pulseExpansionHandler.reset(expandableView, animationDuration = 0)
+
+ verify(expandableView, atLeast(1)).actualHeight = collapsedHeight
+ }
+
+ @Test
+ fun resetChild_dontUpdateHeight() {
+ whenever(expandableView.actualHeight).thenReturn(collapsedHeight)
+
+ pulseExpansionHandler.reset(expandableView, animationDuration = 0)
+
+ verify(expandableView, never()).actualHeight = anyInt()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/ui/MobileContextProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/ui/MobileContextProviderTest.kt
new file mode 100644
index 0000000..0fdda62
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/ui/MobileContextProviderTest.kt
@@ -0,0 +1,122 @@
+/*
+ * 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.connectivity.ui
+
+import android.telephony.SubscriptionInfo
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.demomode.DemoModeController
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.statusbar.connectivity.NetworkController
+import com.android.systemui.statusbar.connectivity.SignalCallback
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.withArgCaptor
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+class MobileContextProviderTest : SysuiTestCase() {
+ @Mock private lateinit var networkController: NetworkController
+ @Mock private lateinit var dumpManager: DumpManager
+ @Mock private lateinit var demoModeController: DemoModeController
+
+ private lateinit var provider: MobileContextProvider
+ private lateinit var signalCallback: SignalCallback
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+ provider =
+ MobileContextProvider(
+ networkController,
+ dumpManager,
+ demoModeController,
+ )
+
+ signalCallback = withArgCaptor { verify(networkController).addCallback(capture()) }
+ }
+
+ @Test
+ fun test_oneSubscription_contextHasMccMnc() {
+ // GIVEN there is one SubscriptionInfo
+ signalCallback.setSubs(listOf(SUB_1))
+
+ // WHEN we ask for a mobile context
+ val ctx = provider.getMobileContextForSub(SUB_1_ID, context)
+
+ // THEN the configuration of that context reflect this subscription's MCC/MNC override
+ val config = ctx.resources.configuration
+ assertThat(config.mcc).isEqualTo(SUB_1_MCC)
+ assertThat(config.mnc).isEqualTo(SUB_1_MNC)
+ }
+
+ @Test
+ fun test_twoSubscriptions_eachContextReflectsMccMnc() {
+ // GIVEN there are two SubscriptionInfos
+ signalCallback.setSubs(listOf(SUB_1, SUB_2))
+
+ // WHEN we ask for a mobile context for each sub
+ val ctx1 = provider.getMobileContextForSub(SUB_1_ID, context)
+ val ctx2 = provider.getMobileContextForSub(SUB_2_ID, context)
+
+ // THEN the configuration of each context reflect this subscription's MCC/MNC override
+ val config1 = ctx1.resources.configuration
+ assertThat(config1.mcc).isEqualTo(SUB_1_MCC)
+ assertThat(config1.mnc).isEqualTo(SUB_1_MNC)
+
+ val config2 = ctx2.resources.configuration
+ assertThat(config2.mcc).isEqualTo(SUB_2_MCC)
+ assertThat(config2.mnc).isEqualTo(SUB_2_MNC)
+ }
+
+ @Test
+ fun test_requestingContextForNonexistentSubscription_returnsGivenContext() {
+ // GIVEN no SubscriptionInfos
+ signalCallback.setSubs(listOf())
+
+ // WHEN we ask for a mobile context for an unknown subscription
+ val ctx = provider.getMobileContextForSub(SUB_1_ID, context)
+
+ // THEN we get the original context back
+ assertThat(ctx).isEqualTo(context)
+ }
+
+ private val SUB_1_ID = 1
+ private val SUB_1_MCC = 123
+ private val SUB_1_MNC = 456
+ private val SUB_1 =
+ mock<SubscriptionInfo>().also {
+ whenever(it.subscriptionId).thenReturn(SUB_1_ID)
+ whenever(it.mcc).thenReturn(SUB_1_MCC)
+ whenever(it.mnc).thenReturn(SUB_1_MNC)
+ }
+
+ private val SUB_2_ID = 2
+ private val SUB_2_MCC = 666
+ private val SUB_2_MNC = 777
+ private val SUB_2 =
+ mock<SubscriptionInfo>().also {
+ whenever(it.subscriptionId).thenReturn(SUB_2_ID)
+ whenever(it.mcc).thenReturn(SUB_2_MCC)
+ whenever(it.mnc).thenReturn(SUB_2_MNC)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/SmartspaceDedupingCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/SmartspaceDedupingCoordinatorTest.kt
index d4f0505..8272f5a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/SmartspaceDedupingCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/SmartspaceDedupingCoordinatorTest.kt
@@ -23,11 +23,9 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.plugins.BcSmartspaceDataPlugin.SmartspaceTargetListener
import com.android.systemui.plugins.statusbar.StatusBarStateController
-import com.android.systemui.statusbar.NotificationLockscreenUserManager
import com.android.systemui.statusbar.StatusBarState
import com.android.systemui.statusbar.SysuiStatusBarStateController
import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController
-import com.android.systemui.statusbar.notification.NotificationEntryManager
import com.android.systemui.statusbar.notification.collection.NotifPipeline
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
@@ -46,7 +44,6 @@
import org.junit.Before
import org.junit.Test
import org.mockito.Mock
-import org.mockito.Mockito.anyString
import org.mockito.Mockito.clearInvocations
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
@@ -61,10 +58,6 @@
@Mock
private lateinit var smartspaceController: LockscreenSmartspaceController
@Mock
- private lateinit var notificationEntryManager: NotificationEntryManager
- @Mock
- private lateinit var notificationLockscreenUserManager: NotificationLockscreenUserManager
- @Mock
private lateinit var notifPipeline: NotifPipeline
@Mock
private lateinit var pluggableListener: Pluggable.PluggableListener<NotifFilter>
@@ -99,12 +92,10 @@
deduper = SmartspaceDedupingCoordinator(
statusBarStateController,
smartspaceController,
- notificationEntryManager,
- notificationLockscreenUserManager,
notifPipeline,
executor,
clock
- )
+ )
// Attach the deduper and capture the listeners/filters that it registers
deduper.attach(notifPipeline)
@@ -352,7 +343,6 @@
// THEN the new pipeline is invalidated (but the old one isn't because it's not
// necessary) because the notif should no longer be filtered out
verify(pluggableListener).onPluggableInvalidated(eq(filter), any())
- verify(notificationEntryManager, never()).updateNotifications(anyString())
assertFalse(filter.shouldFilterOut(entry2HasNotRecentlyAlerted, now))
}
@@ -390,7 +380,6 @@
private fun verifyPipelinesInvalidated() {
verify(pluggableListener).onPluggableInvalidated(eq(filter), any())
- verify(notificationEntryManager).updateNotifications(anyString())
}
private fun assertExecutorIsClear() {
@@ -399,12 +388,10 @@
private fun verifyPipelinesNotInvalidated() {
verify(pluggableListener, never()).onPluggableInvalidated(eq(filter), any())
- verify(notificationEntryManager, never()).updateNotifications(anyString())
}
private fun clearPipelineInvocations() {
clearInvocations(pluggableListener)
- clearInvocations(notificationEntryManager)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
index 8a7b9d3..b2dc842 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
@@ -44,8 +44,6 @@
import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.StatusBarStateControllerImpl;
-import com.android.systemui.statusbar.notification.NotifPipelineFlags;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotifLiveData;
import com.android.systemui.statusbar.notification.collection.NotifLiveDataStore;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
@@ -85,11 +83,9 @@
@Mock private NotificationLogger.ExpansionStateLogger mExpansionStateLogger;
// Dependency mocks:
- @Mock private NotifPipelineFlags mNotifPipelineFlags;
@Mock private NotifLiveDataStore mNotifLiveDataStore;
@Mock private NotifLiveData<List<NotificationEntry>> mActiveNotifEntries;
@Mock private NotificationVisibilityProvider mVisibilityProvider;
- @Mock private NotificationEntryManager mEntryManager;
@Mock private NotifPipeline mNotifPipeline;
@Mock private NotificationListener mListener;
@@ -118,17 +114,14 @@
mLogger = new TestableNotificationLogger(
mListener,
mUiBgExecutor,
- mNotifPipelineFlags,
mNotifLiveDataStore,
mVisibilityProvider,
- mEntryManager,
mNotifPipeline,
mock(StatusBarStateControllerImpl.class),
mBarService,
mExpansionStateLogger
);
mLogger.setUpWithContainer(mListContainer);
- verify(mEntryManager, never()).addNotificationEntryListener(any());
verify(mNotifPipeline).addCollectionListener(any());
}
@@ -266,10 +259,8 @@
TestableNotificationLogger(NotificationListener notificationListener,
Executor uiBgExecutor,
- NotifPipelineFlags notifPipelineFlags,
NotifLiveDataStore notifLiveDataStore,
NotificationVisibilityProvider visibilityProvider,
- NotificationEntryManager entryManager,
NotifPipeline notifPipeline,
StatusBarStateControllerImpl statusBarStateController,
IStatusBarService barService,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/FeedbackInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/FeedbackInfoTest.java
index fe2f5f0..6d687a6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/FeedbackInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/FeedbackInfoTest.java
@@ -57,7 +57,6 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.statusbar.notification.AssistantFeedbackController;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
@@ -84,8 +83,6 @@
private StatusBarNotification mSbn;
@Mock
- private NotificationEntryManager mNotificationEntryManager;
- @Mock
private IStatusBarService mStatusBarService;
@Mock
private NotificationGutsManager mNotificationGutsManager;
@@ -94,7 +91,6 @@
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- mDependency.injectTestDependency(NotificationEntryManager.class, mNotificationEntryManager);
mDependency.injectTestDependency(IStatusBarService.class, mStatusBarService);
mDependency.injectTestDependency(NotificationGutsManager.class, mNotificationGutsManager);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/AmbientStateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/AmbientStateTest.kt
new file mode 100644
index 0000000..11798a7
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/AmbientStateTest.kt
@@ -0,0 +1,390 @@
+/*
+ * 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.notification.stack
+
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.statusbar.StatusBarState
+import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+private const val MAX_PULSE_HEIGHT = 100000f
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class AmbientStateTest : SysuiTestCase() {
+
+ private val dumpManager = mock<DumpManager>()
+ private val sectionProvider = StackScrollAlgorithm.SectionProvider { _, _ -> false }
+ private val bypassController = StackScrollAlgorithm.BypassController { false }
+ private val statusBarKeyguardViewManager = mock<StatusBarKeyguardViewManager>()
+
+ private lateinit var sut: AmbientState
+
+ @Before
+ fun setUp() {
+ sut =
+ AmbientState(
+ context,
+ dumpManager,
+ sectionProvider,
+ bypassController,
+ statusBarKeyguardViewManager,
+ )
+ }
+
+ // region isDimmed
+ @Test
+ fun isDimmed_whenTrue_shouldReturnTrue() {
+ sut.arrangeDimmed(true)
+
+ assertThat(sut.isDimmed).isTrue()
+ }
+
+ @Test
+ fun isDimmed_whenFalse_shouldReturnFalse() {
+ sut.arrangeDimmed(false)
+
+ assertThat(sut.isDimmed).isFalse()
+ }
+
+ @Test
+ fun isDimmed_whenDozeAmountIsEmpty_shouldReturnTrue() {
+ sut.arrangeDimmed(true)
+ sut.dozeAmount = 0f
+
+ assertThat(sut.isDimmed).isTrue()
+ }
+
+ @Test
+ fun isDimmed_whenPulseExpandingIsFalse_shouldReturnTrue() {
+ sut.arrangeDimmed(true)
+ sut.arrangePulseExpanding(false)
+ sut.dozeAmount = 1f // arrangePulseExpanding changes dozeAmount
+
+ assertThat(sut.isDimmed).isTrue()
+ }
+ // endregion
+
+ // region pulseHeight
+ @Test
+ fun pulseHeight_whenValueChanged_shouldCallListener() {
+ var listenerCalledCount = 0
+ sut.pulseHeight = MAX_PULSE_HEIGHT
+ sut.setOnPulseHeightChangedListener { listenerCalledCount++ }
+
+ sut.pulseHeight = 0f
+
+ assertThat(listenerCalledCount).isEqualTo(1)
+ }
+
+ @Test
+ fun pulseHeight_whenSetSameValue_shouldDoNothing() {
+ var listenerCalledCount = 0
+ sut.pulseHeight = MAX_PULSE_HEIGHT
+ sut.setOnPulseHeightChangedListener { listenerCalledCount++ }
+
+ sut.pulseHeight = MAX_PULSE_HEIGHT
+
+ assertThat(listenerCalledCount).isEqualTo(0)
+ }
+
+ @Test
+ fun pulseHeight_whenValueIsFull_shouldReturn0() {
+ sut.pulseHeight = MAX_PULSE_HEIGHT
+
+ assertThat(sut.pulseHeight).isEqualTo(0f)
+ }
+
+ @Test
+ fun pulseHeight_whenValueIsNotFull_shouldReturnValue() {
+ val expected = MAX_PULSE_HEIGHT - 0.1f
+ sut.pulseHeight = expected
+
+ assertThat(sut.pulseHeight).isEqualTo(expected)
+ }
+ // endregion
+
+ // region statusBarState
+ @Test
+ fun statusBarState_whenPreviousStateIsNotKeyguardAndChange_shouldSetIsFlingRequiredToFalse() {
+ sut.setStatusBarState(StatusBarState.SHADE)
+ sut.isFlingRequiredAfterLockScreenSwipeUp = true
+
+ sut.setStatusBarState(StatusBarState.KEYGUARD)
+
+ assertThat(sut.isFlingRequiredAfterLockScreenSwipeUp).isFalse()
+ }
+
+ @Test
+ fun statusBarState_whenPreviousStateIsKeyguardAndChange_shouldDoNothing() {
+ sut.setStatusBarState(StatusBarState.KEYGUARD)
+ sut.isFlingRequiredAfterLockScreenSwipeUp = true
+
+ sut.setStatusBarState(StatusBarState.SHADE)
+
+ assertThat(sut.isFlingRequiredAfterLockScreenSwipeUp).isTrue()
+ }
+ // endregion
+
+ // region hideAmount
+ @Test
+ fun hideAmount_whenSetToFullValue_shouldReturnZeroFromPulseHeight() {
+ sut.hideAmount = 0f
+ sut.pulseHeight = 1f
+
+ sut.hideAmount = 1f
+
+ assertThat(sut.pulseHeight).isEqualTo(0f)
+ }
+
+ @Test
+ fun hideAmount_whenSetToAnyNotFullValue_shouldDoNothing() {
+ sut.hideAmount = 1f
+ sut.pulseHeight = 1f
+
+ sut.hideAmount = 0f
+
+ assertThat(sut.pulseHeight).isEqualTo(1f)
+ }
+ // endregion
+
+ // region dozeAmount
+ @Test
+ fun dozeAmount_whenDozeAmountIsSetToFullDozing_shouldReturnZeroFromPulseHeight() {
+ sut.dozeAmount = 0f
+ sut.pulseHeight = 1f
+
+ sut.dozeAmount = 1f
+
+ assertThat(sut.pulseHeight).isEqualTo(0f)
+ }
+
+ @Test
+ fun dozeAmount_whenDozeAmountIsSetToFullAwake_shouldReturnZeroFromPulseHeight() {
+ sut.dozeAmount = 1f
+ sut.pulseHeight = 1f
+
+ sut.dozeAmount = 0f
+
+ assertThat(sut.pulseHeight).isEqualTo(0f)
+ }
+
+ @Test
+ fun dozeAmount_whenDozeAmountIsSetAnyValueNotFullAwakeOrDozing_shouldDoNothing() {
+ sut.dozeAmount = 1f
+ sut.pulseHeight = 1f
+
+ sut.dozeAmount = 0.5f
+
+ assertThat(sut.pulseHeight).isEqualTo(1f)
+ }
+ // endregion
+
+ // region trackedHeadsUpRow
+ @Test
+ fun trackedHeadsUpRow_whenIsAboveTheShelf_shouldReturnInstance() {
+ sut.trackedHeadsUpRow = mock { whenever(isAboveShelf).thenReturn(true) }
+
+ assertThat(sut.trackedHeadsUpRow).isNotNull()
+ }
+
+ @Test
+ fun trackedHeadsUpRow_whenIsNotAboveTheShelf_shouldReturnNull() {
+ sut.trackedHeadsUpRow = mock { whenever(isAboveShelf).thenReturn(false) }
+
+ assertThat(sut.trackedHeadsUpRow).isNull()
+ }
+ // endregion
+
+ // region isSwipingUp
+ @Test
+ fun isSwipingUp_whenValueChangedToTrue_shouldRequireFling() {
+ sut.isSwipingUp = false
+ sut.isFlingRequiredAfterLockScreenSwipeUp = false
+
+ sut.isSwipingUp = true
+
+ assertThat(sut.isFlingRequiredAfterLockScreenSwipeUp).isFalse()
+ }
+
+ @Test
+ fun isSwipingUp_whenValueChangedToFalse_shouldRequireFling() {
+ sut.isSwipingUp = true
+ sut.isFlingRequiredAfterLockScreenSwipeUp = false
+
+ sut.isSwipingUp = false
+
+ assertThat(sut.isFlingRequiredAfterLockScreenSwipeUp).isTrue()
+ }
+ // endregion
+
+ // region isFlinging
+ @Test
+ fun isFlinging_shouldNotNeedFling() {
+ sut.arrangeFlinging(true)
+
+ sut.setFlinging(false)
+
+ assertThat(sut.isFlingRequiredAfterLockScreenSwipeUp).isFalse()
+ }
+
+ @Test
+ fun isFlinging_whenNotOnLockScreen_shouldDoNothing() {
+ sut.arrangeFlinging(true)
+ sut.setStatusBarState(StatusBarState.SHADE)
+ sut.isFlingRequiredAfterLockScreenSwipeUp = true
+
+ sut.setFlinging(false)
+
+ assertThat(sut.isFlingRequiredAfterLockScreenSwipeUp).isTrue()
+ }
+
+ @Test
+ fun isFlinging_whenValueChangedToTrue_shouldDoNothing() {
+ sut.arrangeFlinging(false)
+
+ sut.setFlinging(true)
+
+ assertThat(sut.isFlingRequiredAfterLockScreenSwipeUp).isTrue()
+ }
+ // endregion
+
+ // region scrollY
+ @Test
+ fun scrollY_shouldSetValueGreaterThanZero() {
+ sut.scrollY = 0
+
+ sut.scrollY = 1
+
+ assertThat(sut.scrollY).isEqualTo(1)
+ }
+
+ @Test
+ fun scrollY_shouldNotSetValueLessThanZero() {
+ sut.scrollY = 0
+
+ sut.scrollY = -1
+
+ assertThat(sut.scrollY).isEqualTo(0)
+ }
+ // endregion
+
+ // region setOverScrollAmount
+ fun setOverScrollAmount_shouldSetValueOnTop() {
+ sut.setOverScrollAmount(/* amount = */ 10f, /* onTop = */ true)
+
+ val resultOnTop = sut.getOverScrollAmount(/* top = */ true)
+ val resultOnBottom = sut.getOverScrollAmount(/* top = */ false)
+
+ assertThat(resultOnTop).isEqualTo(10f)
+ assertThat(resultOnBottom).isEqualTo(0f)
+ }
+
+ fun setOverScrollAmount_shouldSetValueOnBottom() {
+ sut.setOverScrollAmount(/* amount = */ 10f, /* onTop = */ false)
+
+ val resultOnTop = sut.getOverScrollAmount(/* top */ true)
+ val resultOnBottom = sut.getOverScrollAmount(/* top */ false)
+
+ assertThat(resultOnTop).isEqualTo(0f)
+ assertThat(resultOnBottom).isEqualTo(10f)
+ }
+ // endregion
+
+ // region IsPulseExpanding
+ @Test
+ fun isPulseExpanding_shouldReturnTrue() {
+ sut.arrangePulseExpanding(true)
+
+ assertThat(sut.isPulseExpanding).isTrue()
+ }
+
+ @Test
+ fun isPulseExpanding_whenPulseHeightIsMax_shouldReturnFalse() {
+ sut.arrangePulseExpanding(true)
+ sut.pulseHeight = MAX_PULSE_HEIGHT
+
+ assertThat(sut.isPulseExpanding).isFalse()
+ }
+
+ @Test
+ fun isPulseExpanding_whenDozeAmountIsZero_shouldReturnFalse() {
+ sut.arrangePulseExpanding(true)
+ sut.dozeAmount = 0f
+
+ assertThat(sut.isPulseExpanding).isFalse()
+ }
+
+ @Test
+ fun isPulseExpanding_whenHideAmountIsFull_shouldReturnFalse() {
+ sut.arrangePulseExpanding(true)
+ sut.hideAmount = 1f
+
+ assertThat(sut.isPulseExpanding).isFalse()
+ }
+ // endregion
+
+ // region isOnKeyguard
+ @Test
+ fun isOnKeyguard_whenStatusBarStateIsKeyguard_shouldReturnTrue() {
+ sut.setStatusBarState(StatusBarState.KEYGUARD)
+
+ assertThat(sut.isOnKeyguard).isTrue()
+ }
+
+ @Test
+ fun isOnKeyguard_whenStatusBarStateIsNotKeyguard_shouldReturnFalse() {
+ sut.setStatusBarState(StatusBarState.SHADE)
+
+ assertThat(sut.isOnKeyguard).isFalse()
+ }
+ // endregion
+}
+
+// region Arrange helper methods.
+private fun AmbientState.arrangeDimmed(value: Boolean) {
+ isDimmed = value
+ dozeAmount = if (value) 0f else 1f
+ arrangePulseExpanding(!value)
+}
+
+private fun AmbientState.arrangePulseExpanding(value: Boolean) {
+ if (value) {
+ dozeAmount = 1f
+ hideAmount = 0f
+ pulseHeight = 0f
+ } else {
+ dozeAmount = 0f
+ hideAmount = 1f
+ pulseHeight = MAX_PULSE_HEIGHT
+ }
+}
+
+private fun AmbientState.arrangeFlinging(value: Boolean) {
+ setStatusBarState(StatusBarState.KEYGUARD)
+ setFlinging(value)
+ isFlingRequiredAfterLockScreenSwipeUp = true
+}
+// endregion
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt
index 3f19036..7741813 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt
@@ -3,15 +3,22 @@
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
import androidx.test.filters.SmallTest
+import com.android.keyguard.BouncerPanelExpansionCalculator.aboutToShowBouncerProgress
import com.android.systemui.SysuiTestCase
+import com.android.systemui.animation.ShadeInterpolation
import com.android.systemui.statusbar.NotificationShelf
import com.android.systemui.statusbar.StatusBarIconView
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.statusbar.notification.row.ExpandableView
-import junit.framework.Assert.*
+import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm.StackScrollAlgorithmState
+import com.android.systemui.util.mockito.mock
+import junit.framework.Assert.assertEquals
+import junit.framework.Assert.assertFalse
+import junit.framework.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.Mockito.*
+import org.mockito.Mockito.mock
import org.mockito.Mockito.`when` as whenever
/**
@@ -22,13 +29,18 @@
@RunWithLooper
class NotificationShelfTest : SysuiTestCase() {
- private val shelf = NotificationShelf(context, /* attrs */ null)
+ private val shelf = NotificationShelf(
+ context,
+ /* attrs */ null,
+ /* showNotificationShelf */true
+ )
private val shelfState = shelf.viewState as NotificationShelf.ShelfState
private val ambientState = mock(AmbientState::class.java)
+ private val hostLayoutController: NotificationStackScrollLayoutController = mock()
@Before
fun setUp() {
- shelf.bind(ambientState, /* hostLayoutController */ null)
+ shelf.bind(ambientState, /* hostLayoutController */ hostLayoutController)
shelf.layout(/* left */ 0, /* top */ 0, /* right */ 30, /* bottom */5)
}
@@ -37,7 +49,7 @@
setFractionToShade(0f)
setOnLockscreen(true)
- shelf.updateActualWidth(/* fractionToShade */ 0f, /* shortestWidth */ 10f);
+ shelf.updateActualWidth(/* fractionToShade */ 0f, /* shortestWidth */ 10f)
assertTrue(shelf.actualWidth == 10)
shelf.updateActualWidth(/* fractionToShade */ 0.5f, /* shortestWidth */ 10f)
@@ -155,7 +167,7 @@
whenever(expandableView.actualHeight).thenReturn(20)
whenever(expandableView.minHeight).thenReturn(20)
- whenever(expandableView.shelfTransformationTarget).thenReturn(null) // use translationY
+ whenever(expandableView.shelfTransformationTarget).thenReturn(null) // use translationY
whenever(expandableView.isInShelf).thenReturn(true)
whenever(ambientState.isOnKeyguard).thenReturn(true)
@@ -182,7 +194,7 @@
whenever(expandableView.actualHeight).thenReturn(20)
whenever(expandableView.minHeight).thenReturn(20)
- whenever(expandableView.shelfTransformationTarget).thenReturn(null) // use translationY
+ whenever(expandableView.shelfTransformationTarget).thenReturn(null) // use translationY
whenever(expandableView.isInShelf).thenReturn(true)
whenever(ambientState.isOnKeyguard).thenReturn(true)
@@ -209,7 +221,7 @@
whenever(expandableView.actualHeight).thenReturn(25)
whenever(expandableView.minHeight).thenReturn(25)
- whenever(expandableView.shelfTransformationTarget).thenReturn(null) // use translationY
+ whenever(expandableView.shelfTransformationTarget).thenReturn(null) // use translationY
whenever(expandableView.isInShelf).thenReturn(true)
whenever(ambientState.isOnKeyguard).thenReturn(true)
@@ -236,7 +248,7 @@
whenever(expandableView.actualHeight).thenReturn(10)
whenever(expandableView.minHeight).thenReturn(10)
- whenever(expandableView.shelfTransformationTarget).thenReturn(null) // use translationY
+ whenever(expandableView.shelfTransformationTarget).thenReturn(null) // use translationY
whenever(expandableView.isInShelf).thenReturn(false)
whenever(ambientState.isExpansionChanging).thenReturn(false)
@@ -251,6 +263,42 @@
assertEquals(0f, amountInShelf)
}
+ @Test
+ fun updateState_expansionChanging_shelfTransparent() {
+ updateState_expansionChanging_shelfAlphaUpdated(
+ expansionFraction = 0.25f,
+ expectedAlpha = 0.0f
+ )
+ }
+
+ @Test
+ fun updateState_expansionChangingWhileBouncerInTransit_shelfTransparent() {
+ whenever(ambientState.isBouncerInTransit).thenReturn(true)
+
+ updateState_expansionChanging_shelfAlphaUpdated(
+ expansionFraction = 0.85f,
+ expectedAlpha = 0.0f
+ )
+ }
+
+ @Test
+ fun updateState_expansionChanging_shelfAlphaUpdated() {
+ updateState_expansionChanging_shelfAlphaUpdated(
+ expansionFraction = 0.6f,
+ expectedAlpha = ShadeInterpolation.getContentAlpha(0.6f)
+ )
+ }
+
+ @Test
+ fun updateState_expansionChangingWhileBouncerInTransit_shelfAlphaUpdated() {
+ whenever(ambientState.isBouncerInTransit).thenReturn(true)
+
+ updateState_expansionChanging_shelfAlphaUpdated(
+ expansionFraction = 0.95f,
+ expectedAlpha = aboutToShowBouncerProgress(0.95f)
+ )
+ }
+
private fun setFractionToShade(fraction: Float) {
whenever(ambientState.fractionToShade).thenReturn(fraction)
}
@@ -258,4 +306,19 @@
private fun setOnLockscreen(isOnLockscreen: Boolean) {
whenever(ambientState.isOnKeyguard).thenReturn(isOnLockscreen)
}
-}
\ No newline at end of file
+
+ private fun updateState_expansionChanging_shelfAlphaUpdated(
+ expansionFraction: Float,
+ expectedAlpha: Float
+ ) {
+ whenever(ambientState.lastVisibleBackgroundChild)
+ .thenReturn(ExpandableNotificationRow(mContext, null))
+ whenever(ambientState.isExpansionChanging).thenReturn(true)
+ whenever(ambientState.expansionFraction).thenReturn(expansionFraction)
+ whenever(hostLayoutController.speedBumpIndex).thenReturn(0)
+
+ shelf.updateState(StackScrollAlgorithmState(), ambientState)
+
+ assertEquals(expectedAlpha, shelf.viewState.alpha)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
index 966e233..8be9eb5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
@@ -58,7 +58,6 @@
import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotifCollection;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;
@@ -119,7 +118,6 @@
@Mock private SectionHeaderController mSilentHeaderController;
@Mock private NotifPipeline mNotifPipeline;
@Mock private NotifCollection mNotifCollection;
- @Mock private NotificationEntryManager mEntryManager;
@Mock private UiEventLogger mUiEventLogger;
@Mock private LockscreenShadeTransitionController mLockscreenShadeTransitionController;
@Mock private NotificationRemoteInputManager mRemoteInputManager;
@@ -168,7 +166,6 @@
mSilentHeaderController,
mNotifPipeline,
mNotifCollection,
- mEntryManager,
mLockscreenShadeTransitionController,
mShadeTransitionController,
mUiEventLogger,
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 3c22edc..6ae021b 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
@@ -250,7 +250,7 @@
// Validate that when the animation ends the stackEndHeight is recalculated immediately
clearInvocations(mAmbientState);
mStackScroller.setPanelFlinging(false);
- verify(mAmbientState).setIsFlinging(eq(false));
+ verify(mAmbientState).setFlinging(eq(false));
verify(mAmbientState).setStackEndHeight(anyFloat());
verify(mAmbientState).setStackHeight(anyFloat());
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
index 35d2363b..40aec82 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
@@ -20,7 +20,10 @@
import junit.framework.Assert.assertTrue
import org.junit.Before
import org.junit.Test
+import org.mockito.Mockito.any
+import org.mockito.Mockito.eq
import org.mockito.Mockito.mock
+import org.mockito.Mockito.verify
import org.mockito.Mockito.`when` as whenever
@SmallTest
@@ -35,7 +38,6 @@
private val emptyShadeView = EmptyShadeView(context, /* attrs= */ null).apply {
layout(/* l= */ 0, /* t= */ 0, /* r= */ 100, /* b= */ 100)
}
-
private val ambientState = AmbientState(
context,
dumpManager,
@@ -115,29 +117,54 @@
}
@Test
- fun resetViewStates_isExpansionChanging_viewBecomesTransparent() {
+ fun resetViewStates_expansionChanging_notificationBecomesTransparent() {
whenever(mStatusBarKeyguardViewManager.isBouncerInTransit).thenReturn(false)
- ambientState.isExpansionChanging = true
- ambientState.expansionFraction = 0.25f
- stackScrollAlgorithm.initView(context)
-
- stackScrollAlgorithm.resetViewStates(ambientState, /* speedBumpIndex= */ 0)
-
- val expected = getContentAlpha(0.25f)
- assertThat(notificationRow.viewState.alpha).isEqualTo(expected)
+ resetViewStates_expansionChanging_notificationAlphaUpdated(
+ expansionFraction = 0.25f,
+ expectedAlpha = 0.0f
+ )
}
@Test
- fun resetViewStates_isExpansionChangingWhileBouncerInTransit_viewBecomesTransparent() {
+ fun resetViewStates_expansionChangingWhileBouncerInTransit_viewBecomesTransparent() {
whenever(mStatusBarKeyguardViewManager.isBouncerInTransit).thenReturn(true)
+ resetViewStates_expansionChanging_notificationAlphaUpdated(
+ expansionFraction = 0.85f,
+ expectedAlpha = 0.0f
+ )
+ }
+
+ @Test
+ fun resetViewStates_expansionChanging_notificationAlphaUpdated() {
+ whenever(mStatusBarKeyguardViewManager.isBouncerInTransit).thenReturn(false)
+ resetViewStates_expansionChanging_notificationAlphaUpdated(
+ expansionFraction = 0.6f,
+ expectedAlpha = getContentAlpha(0.6f)
+ )
+ }
+
+ @Test
+ fun resetViewStates_expansionChangingWhileBouncerInTransit_notificationAlphaUpdated() {
+ whenever(mStatusBarKeyguardViewManager.isBouncerInTransit).thenReturn(true)
+ resetViewStates_expansionChanging_notificationAlphaUpdated(
+ expansionFraction = 0.95f,
+ expectedAlpha = aboutToShowBouncerProgress(0.95f)
+ )
+ }
+
+ @Test
+ fun resetViewStates_expansionChanging_shelfUpdated() {
+ ambientState.shelf = notificationShelf
ambientState.isExpansionChanging = true
- ambientState.expansionFraction = 0.25f
+ ambientState.expansionFraction = 0.6f
stackScrollAlgorithm.initView(context)
stackScrollAlgorithm.resetViewStates(ambientState, /* speedBumpIndex= */ 0)
- val expected = aboutToShowBouncerProgress(0.25f)
- assertThat(notificationRow.viewState.alpha).isEqualTo(expected)
+ verify(notificationShelf).updateState(
+ /* algorithmState= */any(),
+ /* ambientState= */eq(ambientState)
+ )
}
@Test
@@ -179,7 +206,28 @@
}
@Test
- fun resetViewStates_hiddenShelf_viewAlphaDoesNotChange() {
+ fun resetViewStates_hiddenShelf_allRowsBecomesTransparent() {
+ hostView.removeAllViews()
+ val row1 = mockExpandableNotificationRow()
+ hostView.addView(row1)
+ val row2 = mockExpandableNotificationRow()
+ hostView.addView(row2)
+
+ ambientState.setStatusBarState(StatusBarState.KEYGUARD)
+ ambientState.hideAmount = 0.25f
+ notificationShelf.viewState.hidden = true
+ ambientState.shelf = notificationShelf
+ stackScrollAlgorithm.initView(context)
+
+ stackScrollAlgorithm.resetViewStates(ambientState, /* speedBumpIndex= */ 0)
+
+ val expected = 1f - ambientState.hideAmount
+ assertThat(row1.viewState.alpha).isEqualTo(expected)
+ assertThat(row2.viewState.alpha).isEqualTo(expected)
+ }
+
+ @Test
+ fun resetViewStates_hiddenShelf_shelfAlphaDoesNotChange() {
val expected = notificationShelf.viewState.alpha
notificationShelf.viewState.hidden = true
ambientState.shelf = notificationShelf
@@ -458,4 +506,23 @@
/* originalCornerRoundness= */ 1f)
assertEquals(1f, currentRoundness)
}
+
+ private fun resetViewStates_expansionChanging_notificationAlphaUpdated(
+ expansionFraction: Float,
+ expectedAlpha: Float
+ ) {
+ ambientState.isExpansionChanging = true
+ ambientState.expansionFraction = expansionFraction
+ stackScrollAlgorithm.initView(context)
+
+ stackScrollAlgorithm.resetViewStates(ambientState, /* speedBumpIndex= */ 0)
+
+ assertThat(notificationRow.viewState.alpha).isEqualTo(expectedAlpha)
+ }
+}
+
+private fun mockExpandableNotificationRow(): ExpandableNotificationRow {
+ return mock(ExpandableNotificationRow::class.java).apply {
+ whenever(viewState).thenReturn(ExpandableViewState())
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
index a6808e0..cd0cc33 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
@@ -167,8 +167,6 @@
mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT,
BiometricSourceType.FINGERPRINT, false /* isStrongBiometric */);
verify(mStatusBarKeyguardViewManager).showBouncer(anyBoolean());
- verify(mShadeController).animateCollapsePanels(anyInt(), anyBoolean(), anyBoolean(),
- anyFloat());
assertThat(mBiometricUnlockController.getMode())
.isEqualTo(BiometricUnlockController.MODE_SHOW_BOUNCER);
assertThat(mBiometricUnlockController.getBiometricType())
@@ -298,10 +296,6 @@
mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT,
BiometricSourceType.FACE, true /* isStrongBiometric */);
- // Wake up before showing the bouncer
- verify(mStatusBarKeyguardViewManager, never()).showBouncer(anyBoolean());
- mBiometricUnlockController.mWakefulnessObserver.onFinishedWakingUp();
-
verify(mStatusBarKeyguardViewManager).showBouncer(anyBoolean());
assertThat(mBiometricUnlockController.getMode())
.isEqualTo(BiometricUnlockController.MODE_SHOW_BOUNCER);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
index 735a88d..f510e48 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
@@ -35,6 +35,7 @@
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.verify;
import static org.mockito.Mockito.when;
@@ -69,7 +70,11 @@
import android.util.SparseArray;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
+import android.view.ViewRootImpl;
import android.view.WindowManager;
+import android.window.OnBackInvokedCallback;
+import android.window.OnBackInvokedDispatcher;
+import android.window.WindowOnBackInvokedDispatcher;
import androidx.test.filters.SmallTest;
@@ -127,7 +132,6 @@
import com.android.systemui.statusbar.StatusBarStateControllerImpl;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.NotifPipelineFlags;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
import com.android.systemui.statusbar.notification.collection.NotifLiveDataStore;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
@@ -169,6 +173,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -223,7 +228,6 @@
@Mock private NotificationShadeWindowView mNotificationShadeWindowView;
@Mock private BroadcastDispatcher mBroadcastDispatcher;
@Mock private AssistManager mAssistManager;
- @Mock private NotificationEntryManager mNotificationEntryManager;
@Mock private NotificationGutsManager mNotificationGutsManager;
@Mock private NotificationMediaManager mNotificationMediaManager;
@Mock private NavigationBarController mNavigationBarController;
@@ -281,6 +285,15 @@
@Mock private InteractionJankMonitor mJankMonitor;
@Mock private DeviceStateManager mDeviceStateManager;
@Mock private WiredChargingRippleController mWiredChargingRippleController;
+ /**
+ * The process of registering/unregistering a predictive back callback requires a
+ * ViewRootImpl, which is present IRL, but may be missing during a Mockito unit test.
+ * To prevent an NPE during test execution, we explicitly craft and provide a fake ViewRootImpl.
+ */
+ @Mock private ViewRootImpl mViewRootImpl;
+ @Mock private WindowOnBackInvokedDispatcher mOnBackInvokedDispatcher;
+ @Captor private ArgumentCaptor<OnBackInvokedCallback> mOnBackInvokedCallback;
+
private ShadeController mShadeController;
private final FakeSystemClock mFakeSystemClock = new FakeSystemClock();
private FakeExecutor mMainExecutor = new FakeExecutor(mFakeSystemClock);
@@ -370,10 +383,10 @@
return null;
}).when(mNotificationShadeWindowController).batchApplyWindowLayoutParams(any());
- mShadeController = new ShadeControllerImpl(mCommandQueue,
+ mShadeController = spy(new ShadeControllerImpl(mCommandQueue,
mStatusBarStateController, mNotificationShadeWindowController,
mStatusBarKeyguardViewManager, mContext.getSystemService(WindowManager.class),
- () -> Optional.of(mCentralSurfaces), () -> mAssistManager);
+ () -> Optional.of(mCentralSurfaces), () -> mAssistManager));
when(mOperatorNameViewControllerFactory.create(any()))
.thenReturn(mOperatorNameViewController);
@@ -397,7 +410,6 @@
new FalsingManagerFake(),
new FalsingCollectorFake(),
mBroadcastDispatcher,
- mNotificationEntryManager,
mNotificationGutsManager,
notificationLogger,
mNotificationInterruptStateProvider,
@@ -463,7 +475,14 @@
mActivityLaunchAnimator,
mJankMonitor,
mDeviceStateManager,
- mWiredChargingRippleController, mDreamManager);
+ mWiredChargingRippleController, mDreamManager) {
+ @Override
+ protected ViewRootImpl getViewRootImpl() {
+ return mViewRootImpl;
+ }
+ };
+ when(mViewRootImpl.getOnBackInvokedDispatcher())
+ .thenReturn(mOnBackInvokedDispatcher);
when(mKeyguardViewMediator.registerCentralSurfaces(
any(CentralSurfacesImpl.class),
any(NotificationPanelViewController.class),
@@ -741,6 +760,43 @@
}
}
+ /**
+ * Do the following:
+ * 1. verify that a predictive back callback is registered when CSurf becomes visible
+ * 2. verify that the same callback is unregistered when CSurf becomes invisible
+ */
+ @Test
+ public void testPredictiveBackCallback_registration() {
+ mCentralSurfaces.handleVisibleToUserChanged(true);
+ verify(mOnBackInvokedDispatcher).registerOnBackInvokedCallback(
+ eq(OnBackInvokedDispatcher.PRIORITY_DEFAULT),
+ mOnBackInvokedCallback.capture());
+
+ mCentralSurfaces.handleVisibleToUserChanged(false);
+ verify(mOnBackInvokedDispatcher).unregisterOnBackInvokedCallback(
+ eq(mOnBackInvokedCallback.getValue()));
+ }
+
+ /**
+ * Do the following:
+ * 1. capture the predictive back callback during registration
+ * 2. call the callback directly
+ * 3. verify that the ShadeController's panel collapse animation is invoked
+ */
+ @Test
+ public void testPredictiveBackCallback_invocationCollapsesPanel() {
+ mCentralSurfaces.setNotificationShadeWindowViewController(
+ mNotificationShadeWindowViewController);
+ mCentralSurfaces.handleVisibleToUserChanged(true);
+ verify(mOnBackInvokedDispatcher).registerOnBackInvokedCallback(
+ eq(OnBackInvokedDispatcher.PRIORITY_DEFAULT),
+ mOnBackInvokedCallback.capture());
+
+ when(mNotificationPanelViewController.canPanelBeCollapsed()).thenReturn(true);
+ mOnBackInvokedCallback.getValue().onBackInvoked();
+ verify(mShadeController).animateCollapsePanels();
+ }
+
@Test
public void testPanelOpenForHeadsUp() {
when(mDeviceProvisionedController.isDeviceProvisioned()).thenReturn(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java
index 5c9871a..9de9db1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java
@@ -29,6 +29,7 @@
import android.os.PowerManager;
import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper.RunWithLooper;
import android.view.View;
import androidx.test.filters.SmallTest;
@@ -61,10 +62,10 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
-import java.util.Optional;
@SmallTest
@RunWith(AndroidTestingRunner.class)
+@RunWithLooper(setAsMainLooper = true)
public class DozeServiceHostTest extends SysuiTestCase {
private DozeServiceHost mDozeServiceHost;
@@ -92,6 +93,7 @@
@Mock private View mAmbientIndicationContainer;
@Mock private BiometricUnlockController mBiometricUnlockController;
@Mock private AuthController mAuthController;
+ @Mock private DozeHost.Callback mCallback;
@Before
public void setup() {
@@ -100,7 +102,7 @@
mStatusBarStateController, mDeviceProvisionedController, mHeadsUpManager,
mBatteryController, mScrimController, () -> mBiometricUnlockController,
mKeyguardViewMediator, () -> mAssistManager, mDozeScrimController,
- mKeyguardUpdateMonitor, mPulseExpansionHandler, Optional.empty(),
+ mKeyguardUpdateMonitor, mPulseExpansionHandler,
mNotificationShadeWindowController, mNotificationWakeUpCoordinator,
mAuthController, mNotificationIconAreaController);
@@ -114,16 +116,19 @@
@Test
public void testStartStopDozing() {
+ mDozeServiceHost.addCallback(mCallback);
when(mStatusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD);
when(mStatusBarStateController.isKeyguardRequested()).thenReturn(true);
assertFalse(mDozeServiceHost.getDozingRequested());
mDozeServiceHost.startDozing();
+ verify(mCallback).onDozingChanged(eq(true));
verify(mStatusBarStateController).setIsDozing(eq(true));
verify(mCentralSurfaces).updateIsKeyguard();
mDozeServiceHost.stopDozing();
+ verify(mCallback).onDozingChanged(eq(false));
verify(mStatusBarStateController).setIsDozing(eq(false));
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaTest.kt
deleted file mode 100644
index 3440fa5..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaTest.kt
+++ /dev/null
@@ -1,54 +0,0 @@
-package com.android.systemui.statusbar.phone
-
-import android.testing.AndroidTestingRunner
-import android.testing.TestableLooper
-import android.view.LayoutInflater
-import androidx.test.filters.SmallTest
-import com.android.systemui.R
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.assist.AssistManager
-import com.android.systemui.plugins.ActivityStarter
-import com.android.systemui.statusbar.policy.AccessibilityController
-import com.android.systemui.statusbar.policy.FlashlightController
-import com.android.systemui.statusbar.policy.KeyguardStateController
-import com.android.systemui.tuner.TunerService
-import java.util.concurrent.Executor
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.Mock
-import org.mockito.MockitoAnnotations
-
-@SmallTest
-@RunWith(AndroidTestingRunner::class)
-@TestableLooper.RunWithLooper(setAsMainLooper = true)
-class KeyguardBottomAreaTest : SysuiTestCase() {
-
- @Mock
- private lateinit var mCentralSurfaces: CentralSurfaces
- private lateinit var mKeyguardBottomArea: KeyguardBottomAreaView
-
- @Before
- fun setup() {
- MockitoAnnotations.initMocks(this)
- // Mocked dependencies
- mDependency.injectMockDependency(AccessibilityController::class.java)
- mDependency.injectMockDependency(ActivityStarter::class.java)
- mDependency.injectMockDependency(AssistManager::class.java)
- mDependency.injectTestDependency(Executor::class.java, Executor { it.run() })
- mDependency.injectMockDependency(FlashlightController::class.java)
- mDependency.injectMockDependency(KeyguardStateController::class.java)
- mDependency.injectMockDependency(TunerService::class.java)
-
- mKeyguardBottomArea = LayoutInflater.from(mContext).inflate(
- R.layout.keyguard_bottom_area, null, false) as KeyguardBottomAreaView
- }
-
- @Test
- fun initFrom_doesntCrash() {
- val other = LayoutInflater.from(mContext).inflate(R.layout.keyguard_bottom_area,
- null, false) as KeyguardBottomAreaView
-
- other.initFrom(mKeyguardBottomArea)
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicyTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicyTest.kt
new file mode 100644
index 0000000..64dee95
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicyTest.kt
@@ -0,0 +1,230 @@
+/*
+ * 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.phone
+
+import android.app.AlarmManager
+import android.app.IActivityManager
+import android.app.admin.DevicePolicyManager
+import android.content.SharedPreferences
+import android.os.UserManager
+import android.telecom.TelecomManager
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.testing.TestableLooper.RunWithLooper
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.privacy.PrivacyItemController
+import com.android.systemui.privacy.logging.PrivacyLogger
+import com.android.systemui.screenrecord.RecordingController
+import com.android.systemui.statusbar.CommandQueue
+import com.android.systemui.statusbar.policy.BluetoothController
+import com.android.systemui.statusbar.policy.CastController
+import com.android.systemui.statusbar.policy.DataSaverController
+import com.android.systemui.statusbar.policy.DeviceProvisionedController
+import com.android.systemui.statusbar.policy.HotspotController
+import com.android.systemui.statusbar.policy.KeyguardStateController
+import com.android.systemui.statusbar.policy.LocationController
+import com.android.systemui.statusbar.policy.NextAlarmController
+import com.android.systemui.statusbar.policy.RotationLockController
+import com.android.systemui.statusbar.policy.SensorPrivacyController
+import com.android.systemui.statusbar.policy.UserInfoController
+import com.android.systemui.statusbar.policy.ZenModeController
+import com.android.systemui.util.RingerModeTracker
+import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.mockito.capture
+import com.android.systemui.util.time.DateFormatUtil
+import com.android.systemui.util.time.FakeSystemClock
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Answers
+import org.mockito.ArgumentCaptor
+import org.mockito.Captor
+import org.mockito.Mock
+import org.mockito.Mockito.anyInt
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
+
+@RunWith(AndroidTestingRunner::class)
+@RunWithLooper
+@SmallTest
+class PhoneStatusBarPolicyTest : SysuiTestCase() {
+
+ companion object {
+ private const val ALARM_SLOT = "alarm"
+ }
+
+ @Mock
+ private lateinit var iconController: StatusBarIconController
+ @Mock
+ private lateinit var commandQueue: CommandQueue
+ @Mock
+ private lateinit var broadcastDispatcher: BroadcastDispatcher
+ @Mock
+ private lateinit var castController: CastController
+ @Mock
+ private lateinit var hotspotController: HotspotController
+ @Mock
+ private lateinit var bluetoothController: BluetoothController
+ @Mock
+ private lateinit var nextAlarmController: NextAlarmController
+ @Mock
+ private lateinit var userInfoController: UserInfoController
+ @Mock
+ private lateinit var rotationLockController: RotationLockController
+ @Mock
+ private lateinit var dataSaverController: DataSaverController
+ @Mock
+ private lateinit var zenModeController: ZenModeController
+ @Mock
+ private lateinit var deviceProvisionedController: DeviceProvisionedController
+ @Mock
+ private lateinit var keyguardStateController: KeyguardStateController
+ @Mock
+ private lateinit var locationController: LocationController
+ @Mock
+ private lateinit var sensorPrivacyController: SensorPrivacyController
+ @Mock
+ private lateinit var iActivityManager: IActivityManager
+ @Mock
+ private lateinit var alarmManager: AlarmManager
+ @Mock
+ private lateinit var userManager: UserManager
+ @Mock
+ private lateinit var devicePolicyManager: DevicePolicyManager
+ @Mock
+ private lateinit var recordingController: RecordingController
+ @Mock
+ private lateinit var telecomManager: TelecomManager
+ @Mock
+ private lateinit var sharedPreferences: SharedPreferences
+ @Mock
+ private lateinit var dateFormatUtil: DateFormatUtil
+ @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+ private lateinit var ringerModeTracker: RingerModeTracker
+ @Mock
+ private lateinit var privacyItemController: PrivacyItemController
+ @Mock
+ private lateinit var privacyLogger: PrivacyLogger
+ @Captor
+ private lateinit var alarmCallbackCaptor:
+ ArgumentCaptor<NextAlarmController.NextAlarmChangeCallback>
+
+ private lateinit var executor: FakeExecutor
+ private lateinit var statusBarPolicy: PhoneStatusBarPolicy
+ private lateinit var testableLooper: TestableLooper
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ executor = FakeExecutor(FakeSystemClock())
+ testableLooper = TestableLooper.get(this)
+ context.orCreateTestableResources.addOverride(
+ com.android.internal.R.string.status_bar_alarm_clock,
+ ALARM_SLOT
+ )
+ statusBarPolicy = createStatusBarPolicy()
+ }
+
+ @Test
+ fun testDeviceNotProvisioned_alarmIconNotShown() {
+ val alarmInfo = createAlarmInfo()
+
+ whenever(deviceProvisionedController.isCurrentUserSetup).thenReturn(false)
+ statusBarPolicy.init()
+ verify(nextAlarmController).addCallback(capture(alarmCallbackCaptor))
+
+ whenever(alarmManager.getNextAlarmClock(anyInt())).thenReturn(alarmInfo)
+
+ alarmCallbackCaptor.value.onNextAlarmChanged(alarmInfo)
+ verify(iconController, never()).setIconVisibility(ALARM_SLOT, true)
+ }
+
+ @Test
+ fun testDeviceProvisioned_alarmIconShown() {
+ val alarmInfo = createAlarmInfo()
+
+ whenever(deviceProvisionedController.isCurrentUserSetup).thenReturn(true)
+ statusBarPolicy.init()
+
+ verify(nextAlarmController).addCallback(capture(alarmCallbackCaptor))
+ whenever(alarmManager.getNextAlarmClock(anyInt())).thenReturn(alarmInfo)
+
+ alarmCallbackCaptor.value.onNextAlarmChanged(alarmInfo)
+ verify(iconController).setIconVisibility(ALARM_SLOT, true)
+ }
+
+ @Test
+ fun testDeviceProvisionedChanged_alarmIconShownAfterCurrentUserSetup() {
+ val alarmInfo = createAlarmInfo()
+
+ whenever(deviceProvisionedController.isCurrentUserSetup).thenReturn(false)
+ statusBarPolicy.init()
+
+ verify(nextAlarmController).addCallback(capture(alarmCallbackCaptor))
+ whenever(alarmManager.getNextAlarmClock(anyInt())).thenReturn(alarmInfo)
+
+ alarmCallbackCaptor.value.onNextAlarmChanged(alarmInfo)
+ verify(iconController, never()).setIconVisibility(ALARM_SLOT, true)
+
+ whenever(deviceProvisionedController.isCurrentUserSetup).thenReturn(true)
+ statusBarPolicy.onUserSetupChanged()
+ verify(iconController).setIconVisibility(ALARM_SLOT, true)
+ }
+
+ private fun createAlarmInfo(): AlarmManager.AlarmClockInfo {
+ return AlarmManager.AlarmClockInfo(10L, null)
+ }
+
+ private fun createStatusBarPolicy(): PhoneStatusBarPolicy {
+ return PhoneStatusBarPolicy(
+ iconController,
+ commandQueue,
+ broadcastDispatcher,
+ executor,
+ testableLooper.looper,
+ context.resources,
+ castController,
+ hotspotController,
+ bluetoothController,
+ nextAlarmController,
+ userInfoController,
+ rotationLockController,
+ dataSaverController,
+ zenModeController,
+ deviceProvisionedController,
+ keyguardStateController,
+ locationController,
+ sensorPrivacyController,
+ iActivityManager,
+ alarmManager,
+ userManager,
+ devicePolicyManager,
+ recordingController,
+ telecomManager,
+ /* displayId = */ 0,
+ sharedPreferences,
+ dateFormatUtil,
+ ringerModeTracker,
+ privacyItemController,
+ privacyLogger
+ )
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index 7cd275d..4d1a52c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -59,16 +59,19 @@
import com.android.systemui.dock.DockManager;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.scrim.ScrimView;
-import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.FakeConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
import com.android.systemui.util.wakelock.DelayedWakeLock;
import com.android.systemui.utils.os.FakeHandler;
+import com.google.common.truth.Expect;
+
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -86,6 +89,11 @@
@SmallTest
public class ScrimControllerTest extends SysuiTestCase {
+ @Rule public Expect mExpect = Expect.create();
+
+ private final FakeConfigurationController mConfigurationController =
+ new FakeConfigurationController();
+
private ScrimController mScrimController;
private ScrimView mScrimBehind;
private ScrimView mNotificationsScrim;
@@ -96,32 +104,19 @@
private int mScrimVisibility;
private boolean mAlwaysOnEnabled;
private TestableLooper mLooper;
- @Mock
- private AlarmManager mAlarmManager;
- @Mock
- private DozeParameters mDozeParameters;
- @Mock
- LightBarController mLightBarController;
- @Mock
- DelayedWakeLock.Builder mDelayedWakeLockBuilder;
- @Mock
- private DelayedWakeLock mWakeLock;
- @Mock
- KeyguardStateController mKeyguardStateController;
- @Mock
- KeyguardUpdateMonitor mKeyguardUpdateMonitor;
- @Mock
- private DockManager mDockManager;
- @Mock
- private ConfigurationController mConfigurationController;
- @Mock
- private ScreenOffAnimationController mScreenOffAnimationController;
- @Mock
- private KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
+ @Mock private AlarmManager mAlarmManager;
+ @Mock private DozeParameters mDozeParameters;
+ @Mock private LightBarController mLightBarController;
+ @Mock private DelayedWakeLock.Builder mDelayedWakeLockBuilder;
+ @Mock private DelayedWakeLock mWakeLock;
+ @Mock private KeyguardStateController mKeyguardStateController;
+ @Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ @Mock private DockManager mDockManager;
+ @Mock private ScreenOffAnimationController mScreenOffAnimationController;
+ @Mock private KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
// TODO(b/204991468): Use a real PanelExpansionStateManager object once this bug is fixed. (The
// event-dispatch-on-registration pattern caused some of these unit tests to fail.)
- @Mock
- private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
+ @Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
private static class AnimatorListener implements Animator.AnimatorListener {
private int mNumStarts;
@@ -1450,6 +1445,41 @@
}
@Test
+ public void notificationAlpha_qsNotClipped_alphaMatchesNotificationExpansionProgress() {
+ mScrimController.setClipsQsScrim(false);
+ mScrimController.transitionTo(ScrimState.KEYGUARD);
+ // RawPanelExpansion and QsExpansion are usually used for the notification alpha
+ // calculation.
+ // Here we set them to non-zero values explicitly to make sure that in not clipped mode,
+ // they are not being used even when set.
+ mScrimController.setRawPanelExpansionFraction(0.5f);
+ mScrimController.setQsPosition(/* expansionFraction= */ 0.5f, /* qsPanelBottomY= */ 500);
+ finishAnimationsImmediately();
+
+ float progress = 0.5f;
+
+ float notificationExpansionProgress = 0f;
+ mScrimController.setTransitionToFullShadeProgress(progress, notificationExpansionProgress);
+ mExpect.that(mNotificationsScrim.getViewAlpha()).isEqualTo(notificationExpansionProgress);
+
+ notificationExpansionProgress = 0.25f;
+ mScrimController.setTransitionToFullShadeProgress(progress, notificationExpansionProgress);
+ mExpect.that(mNotificationsScrim.getViewAlpha()).isEqualTo(notificationExpansionProgress);
+
+ notificationExpansionProgress = 0.5f;
+ mScrimController.setTransitionToFullShadeProgress(progress, notificationExpansionProgress);
+ mExpect.that(mNotificationsScrim.getViewAlpha()).isEqualTo(notificationExpansionProgress);
+
+ notificationExpansionProgress = 0.75f;
+ mScrimController.setTransitionToFullShadeProgress(progress, notificationExpansionProgress);
+ mExpect.that(mNotificationsScrim.getViewAlpha()).isEqualTo(notificationExpansionProgress);
+
+ notificationExpansionProgress = 1f;
+ mScrimController.setTransitionToFullShadeProgress(progress, notificationExpansionProgress);
+ mExpect.that(mNotificationsScrim.getViewAlpha()).isEqualTo(notificationExpansionProgress);
+ }
+
+ @Test
public void setNotificationsOverScrollAmount_setsTranslationYOnNotificationsScrim() {
int overScrollAmount = 10;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java
index ca98143..de7db74 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java
@@ -20,7 +20,10 @@
import static junit.framework.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper.RunWithLooper;
@@ -30,12 +33,12 @@
import androidx.test.filters.SmallTest;
import com.android.internal.statusbar.StatusBarIcon;
-import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.statusbar.StatusBarMobileView;
import com.android.systemui.statusbar.StatusBarWifiView;
import com.android.systemui.statusbar.StatusIconDisplayable;
+import com.android.systemui.statusbar.connectivity.ui.MobileContextProvider;
import com.android.systemui.statusbar.phone.StatusBarIconController.DarkIconManager;
import com.android.systemui.statusbar.phone.StatusBarIconController.IconManager;
import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState;
@@ -55,15 +58,19 @@
@SmallTest
public class StatusBarIconControllerTest extends LeakCheckedTest {
+ private MobileContextProvider mMobileContextProvider = mock(MobileContextProvider.class);
+
@Before
public void setup() {
injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES);
+ // For testing, ignore context overrides
+ when(mMobileContextProvider.getMobileContextForSub(anyInt(), any())).thenReturn(mContext);
}
@Test
public void testSetCalledOnAdd_IconManager() {
LinearLayout layout = new LinearLayout(mContext);
- TestIconManager manager = new TestIconManager(layout);
+ TestIconManager manager = new TestIconManager(layout, mMobileContextProvider);
testCallOnAdd_forManager(manager);
}
@@ -72,9 +79,9 @@
LinearLayout layout = new LinearLayout(mContext);
TestDarkIconManager manager = new TestDarkIconManager(
layout,
- mock(FeatureFlags.class),
mock(StatusBarPipelineFlags.class),
() -> mock(WifiViewModel.class),
+ mMobileContextProvider,
mock(DarkIconDispatcher.class));
testCallOnAdd_forManager(manager);
}
@@ -114,11 +121,14 @@
TestDarkIconManager(
LinearLayout group,
- FeatureFlags featureFlags,
StatusBarPipelineFlags statusBarPipelineFlags,
Provider<WifiViewModel> wifiViewModelProvider,
+ MobileContextProvider contextProvider,
DarkIconDispatcher darkIconDispatcher) {
- super(group, featureFlags, statusBarPipelineFlags, wifiViewModelProvider,
+ super(group,
+ statusBarPipelineFlags,
+ wifiViewModelProvider,
+ contextProvider,
darkIconDispatcher);
}
@@ -153,11 +163,11 @@
}
private static class TestIconManager extends IconManager implements TestableIconManager {
- TestIconManager(ViewGroup group) {
+ TestIconManager(ViewGroup group, MobileContextProvider contextProvider) {
super(group,
- mock(FeatureFlags.class),
mock(StatusBarPipelineFlags.class),
- () -> mock(WifiViewModel.class));
+ () -> mock(WifiViewModel.class),
+ contextProvider);
}
@Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
index 2dcdcfc..e790d85 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
@@ -51,6 +51,7 @@
import com.android.systemui.shade.ShadeController;
import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.NotificationShadeWindowController;
+import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.phone.panelstate.PanelExpansionChangeEvent;
import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
@@ -277,6 +278,17 @@
}
@Test
+ public void onPanelExpansionChanged_neverTranslatesBouncerWhenShadeLocked() {
+ when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE_LOCKED);
+ mStatusBarKeyguardViewManager.onPanelExpansionChanged(
+ expansionEvent(
+ /* fraction= */ KeyguardBouncer.EXPANSION_VISIBLE,
+ /* expanded= */ true,
+ /* tracking= */ false));
+ verify(mBouncer, never()).setExpansion(anyFloat());
+ }
+
+ @Test
public void setOccluded_animatesPanelExpansion_onlyIfBouncerHidden() {
mStatusBarKeyguardViewManager.setOccluded(false /* occluded */, true /* animated */);
verify(mCentralSurfaces).animateKeyguardUnoccluding();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
index 2b80508..c409857 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
@@ -66,7 +66,6 @@
import com.android.systemui.statusbar.NotificationPresenter;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationLaunchAnimatorControllerProvider;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -102,8 +101,6 @@
@Mock
private AssistManager mAssistManager;
@Mock
- private NotificationEntryManager mEntryManager;
- @Mock
private ActivityStarter mActivityStarter;
@Mock
private NotificationClickNotifier mClickNotifier;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java
index 1ec4de9..c3a7e65 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java
@@ -37,7 +37,6 @@
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
@@ -55,7 +54,6 @@
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
public class StatusBarRemoteInputCallbackTest extends SysuiTestCase {
- @Mock private NotificationEntryManager mEntryManager;
@Mock private DeviceProvisionedController mDeviceProvisionedController;
@Mock private com.android.systemui.shade.ShadeController mShadeController;
@Mock private NotificationLockscreenUserManager mNotificationLockscreenUserManager;
@@ -71,7 +69,6 @@
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- mDependency.injectTestDependency(NotificationEntryManager.class, mEntryManager);
mDependency.injectTestDependency(DeviceProvisionedController.class,
mDeviceProvisionedController);
mDependency.injectTestDependency(ShadeController.class, mShadeController);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepositoryImplTest.kt
new file mode 100644
index 0000000..6dbee2f
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepositoryImplTest.kt
@@ -0,0 +1,295 @@
+/*
+ * 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.shared.data.repository
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
+import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot
+import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlots
+import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepositoryImpl.Companion.DEFAULT_HIDDEN_ICONS_RESOURCE
+import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepositoryImpl.Companion.HIDDEN_ICONS_TUNABLE_KEY
+import com.android.systemui.tuner.TunerService
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.argumentCaptor
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.cancel
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.yield
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.mockito.Mock
+import org.mockito.Mockito
+import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+class ConnectivityRepositoryImplTest : SysuiTestCase() {
+
+ private lateinit var underTest: ConnectivityRepositoryImpl
+
+ @Mock private lateinit var connectivitySlots: ConnectivitySlots
+ @Mock private lateinit var dumpManager: DumpManager
+ @Mock private lateinit var logger: ConnectivityPipelineLogger
+ private lateinit var scope: CoroutineScope
+ @Mock private lateinit var tunerService: TunerService
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ scope = CoroutineScope(IMMEDIATE)
+
+ underTest = ConnectivityRepositoryImpl(
+ connectivitySlots,
+ context,
+ dumpManager,
+ logger,
+ scope,
+ tunerService,
+ )
+ }
+
+ @After
+ fun tearDown() {
+ scope.cancel()
+ }
+
+ @Test
+ fun forceHiddenSlots_initiallyGetsDefault() = runBlocking(IMMEDIATE) {
+ setUpEthernetWifiMobileSlotNames()
+ context.getOrCreateTestableResources().addOverride(
+ DEFAULT_HIDDEN_ICONS_RESOURCE,
+ arrayOf(SLOT_WIFI, SLOT_ETHERNET)
+ )
+ // Re-create our [ConnectivityRepositoryImpl], since it fetches
+ // config_statusBarIconsToExclude when it's first constructed
+ underTest = ConnectivityRepositoryImpl(
+ connectivitySlots,
+ context,
+ dumpManager,
+ logger,
+ scope,
+ tunerService,
+ )
+
+ var latest: Set<ConnectivitySlot>? = null
+ val job = underTest
+ .forceHiddenSlots
+ .onEach { latest = it }
+ .launchIn(this)
+
+ assertThat(latest).containsExactly(ConnectivitySlot.ETHERNET, ConnectivitySlot.WIFI)
+
+ job.cancel()
+ }
+
+ @Test
+ fun forceHiddenSlots_slotNamesAdded_flowHasSlots() = runBlocking(IMMEDIATE) {
+ setUpEthernetWifiMobileSlotNames()
+
+ var latest: Set<ConnectivitySlot>? = null
+ val job = underTest
+ .forceHiddenSlots
+ .onEach { latest = it }
+ .launchIn(this)
+
+ getTunable().onTuningChanged(HIDDEN_ICONS_TUNABLE_KEY, SLOT_MOBILE)
+
+ assertThat(latest).containsExactly(ConnectivitySlot.MOBILE)
+
+ job.cancel()
+ }
+
+ @Test
+ fun forceHiddenSlots_wrongKey_doesNotUpdate() = runBlocking(IMMEDIATE) {
+ setUpEthernetWifiMobileSlotNames()
+
+ var latest: Set<ConnectivitySlot>? = null
+ val job = underTest
+ .forceHiddenSlots
+ .onEach { latest = it }
+ .launchIn(this)
+
+ getTunable().onTuningChanged(HIDDEN_ICONS_TUNABLE_KEY, SLOT_MOBILE)
+
+ // WHEN onTuningChanged with the wrong key
+ getTunable().onTuningChanged("wrongKey", SLOT_WIFI)
+ yield()
+
+ // THEN we didn't update our value and still have the old one
+ assertThat(latest).containsExactly(ConnectivitySlot.MOBILE)
+
+ job.cancel()
+ }
+
+ @Test
+ fun forceHiddenSlots_slotNamesAddedThenNull_flowHasDefault() = runBlocking(IMMEDIATE) {
+ setUpEthernetWifiMobileSlotNames()
+ context.getOrCreateTestableResources().addOverride(
+ DEFAULT_HIDDEN_ICONS_RESOURCE,
+ arrayOf(SLOT_WIFI, SLOT_ETHERNET)
+ )
+ // Re-create our [ConnectivityRepositoryImpl], since it fetches
+ // config_statusBarIconsToExclude when it's first constructed
+ underTest = ConnectivityRepositoryImpl(
+ connectivitySlots,
+ context,
+ dumpManager,
+ logger,
+ scope,
+ tunerService,
+ )
+
+ var latest: Set<ConnectivitySlot>? = null
+ val job = underTest
+ .forceHiddenSlots
+ .onEach { latest = it }
+ .launchIn(this)
+
+ // First, update the slots
+ getTunable().onTuningChanged(HIDDEN_ICONS_TUNABLE_KEY, SLOT_MOBILE)
+ assertThat(latest).containsExactly(ConnectivitySlot.MOBILE)
+
+ // WHEN we update to a null value
+ getTunable().onTuningChanged(HIDDEN_ICONS_TUNABLE_KEY, null)
+ yield()
+
+ // THEN we go back to our default value
+ assertThat(latest).containsExactly(ConnectivitySlot.ETHERNET, ConnectivitySlot.WIFI)
+
+ job.cancel()
+ }
+
+ @Test
+ fun forceHiddenSlots_someInvalidSlotNames_flowHasValidSlotsOnly() = runBlocking(IMMEDIATE) {
+ var latest: Set<ConnectivitySlot>? = null
+ val job = underTest
+ .forceHiddenSlots
+ .onEach { latest = it }
+ .launchIn(this)
+
+ whenever(connectivitySlots.getSlotFromName(SLOT_WIFI))
+ .thenReturn(ConnectivitySlot.WIFI)
+ whenever(connectivitySlots.getSlotFromName(SLOT_MOBILE)).thenReturn(null)
+
+ getTunable().onTuningChanged(HIDDEN_ICONS_TUNABLE_KEY, "$SLOT_WIFI,$SLOT_MOBILE")
+
+ assertThat(latest).containsExactly(ConnectivitySlot.WIFI)
+
+ job.cancel()
+ }
+
+ @Test
+ fun forceHiddenSlots_someEmptySlotNames_flowHasValidSlotsOnly() = runBlocking(IMMEDIATE) {
+ setUpEthernetWifiMobileSlotNames()
+
+ var latest: Set<ConnectivitySlot>? = null
+ val job = underTest
+ .forceHiddenSlots
+ .onEach { latest = it }
+ .launchIn(this)
+
+ // WHEN there's empty and blank slot names
+ getTunable().onTuningChanged(
+ HIDDEN_ICONS_TUNABLE_KEY, "$SLOT_MOBILE, ,,$SLOT_WIFI"
+ )
+
+ // THEN we skip that slot but still process the other ones
+ assertThat(latest).containsExactly(ConnectivitySlot.WIFI, ConnectivitySlot.MOBILE)
+
+ job.cancel()
+ }
+
+ @Test
+ fun forceHiddenSlots_allInvalidOrEmptySlotNames_flowHasEmpty() = runBlocking(IMMEDIATE) {
+ var latest: Set<ConnectivitySlot>? = null
+ val job = underTest
+ .forceHiddenSlots
+ .onEach { latest = it }
+ .launchIn(this)
+
+ whenever(connectivitySlots.getSlotFromName(SLOT_WIFI)).thenReturn(null)
+ whenever(connectivitySlots.getSlotFromName(SLOT_ETHERNET)).thenReturn(null)
+ whenever(connectivitySlots.getSlotFromName(SLOT_MOBILE)).thenReturn(null)
+
+ getTunable().onTuningChanged(
+ HIDDEN_ICONS_TUNABLE_KEY, "$SLOT_MOBILE,,$SLOT_WIFI,$SLOT_ETHERNET,,,"
+ )
+
+ assertThat(latest).isEmpty()
+
+ job.cancel()
+ }
+
+ @Test
+ fun forceHiddenSlots_newSubscriberGetsCurrentValue() = runBlocking(IMMEDIATE) {
+ setUpEthernetWifiMobileSlotNames()
+
+ var latest1: Set<ConnectivitySlot>? = null
+ val job1 = underTest
+ .forceHiddenSlots
+ .onEach { latest1 = it }
+ .launchIn(this)
+
+ getTunable().onTuningChanged(HIDDEN_ICONS_TUNABLE_KEY, "$SLOT_WIFI,$SLOT_ETHERNET")
+
+ assertThat(latest1).containsExactly(ConnectivitySlot.WIFI, ConnectivitySlot.ETHERNET)
+
+ // WHEN we add a second subscriber after having already emitted a value
+ var latest2: Set<ConnectivitySlot>? = null
+ val job2 = underTest
+ .forceHiddenSlots
+ .onEach { latest2 = it }
+ .launchIn(this)
+
+ // THEN the second subscribe receives the already-emitted value
+ assertThat(latest2).containsExactly(ConnectivitySlot.WIFI, ConnectivitySlot.ETHERNET)
+
+ job1.cancel()
+ job2.cancel()
+ }
+
+ private fun getTunable(): TunerService.Tunable {
+ val callbackCaptor = argumentCaptor<TunerService.Tunable>()
+ Mockito.verify(tunerService).addTunable(callbackCaptor.capture(), any())
+ return callbackCaptor.value!!
+ }
+
+ private fun setUpEthernetWifiMobileSlotNames() {
+ whenever(connectivitySlots.getSlotFromName(SLOT_ETHERNET))
+ .thenReturn(ConnectivitySlot.ETHERNET)
+ whenever(connectivitySlots.getSlotFromName(SLOT_WIFI))
+ .thenReturn(ConnectivitySlot.WIFI)
+ whenever(connectivitySlots.getSlotFromName(SLOT_MOBILE))
+ .thenReturn(ConnectivitySlot.MOBILE)
+ }
+
+ companion object {
+ private const val SLOT_ETHERNET = "ethernet"
+ private const val SLOT_WIFI = "wifi"
+ private const val SLOT_MOBILE = "mobile"
+ private val IMMEDIATE = Dispatchers.Main.immediate
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/data/repository/FakeConnectivityRepository.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/data/repository/FakeConnectivityRepository.kt
new file mode 100644
index 0000000..bd70034
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/data/repository/FakeConnectivityRepository.kt
@@ -0,0 +1,32 @@
+/*
+ * 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.shared.data.repository
+
+import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+
+/** Fake implementation of [ConnectivityRepository] exposing set methods for all the flows. */
+class FakeConnectivityRepository : ConnectivityRepository {
+ private val _forceHiddenIcons: MutableStateFlow<Set<ConnectivitySlot>> =
+ MutableStateFlow(emptySet())
+ override val forceHiddenSlots: StateFlow<Set<ConnectivitySlot>> = _forceHiddenIcons
+
+ fun setForceHiddenIcons(hiddenIcons: Set<ConnectivitySlot>) {
+ _forceHiddenIcons.value = hiddenIcons
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorTest.kt
index 9d8b4bc..e896749 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorTest.kt
@@ -18,6 +18,8 @@
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+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.pipeline.wifi.data.model.WifiActivityModel
import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel
import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository
@@ -37,18 +39,22 @@
private lateinit var underTest: WifiInteractor
- private lateinit var repository: FakeWifiRepository
+ private lateinit var connectivityRepository: FakeConnectivityRepository
+ private lateinit var wifiRepository: FakeWifiRepository
@Before
fun setUp() {
- repository = FakeWifiRepository()
- underTest = WifiInteractor(repository)
+ connectivityRepository = FakeConnectivityRepository()
+ wifiRepository = FakeWifiRepository()
+ underTest = WifiInteractor(connectivityRepository, wifiRepository)
}
@Test
fun hasActivityIn_noInOrOut_outputsFalse() = runBlocking(IMMEDIATE) {
- repository.setWifiNetwork(VALID_WIFI_NETWORK_MODEL)
- repository.setWifiActivity(WifiActivityModel(hasActivityIn = false, hasActivityOut = false))
+ wifiRepository.setWifiNetwork(VALID_WIFI_NETWORK_MODEL)
+ wifiRepository.setWifiActivity(
+ WifiActivityModel(hasActivityIn = false, hasActivityOut = false)
+ )
var latest: Boolean? = null
val job = underTest
@@ -63,8 +69,10 @@
@Test
fun hasActivityIn_onlyOut_outputsFalse() = runBlocking(IMMEDIATE) {
- repository.setWifiNetwork(VALID_WIFI_NETWORK_MODEL)
- repository.setWifiActivity(WifiActivityModel(hasActivityIn = false, hasActivityOut = true))
+ wifiRepository.setWifiNetwork(VALID_WIFI_NETWORK_MODEL)
+ wifiRepository.setWifiActivity(
+ WifiActivityModel(hasActivityIn = false, hasActivityOut = true)
+ )
var latest: Boolean? = null
val job = underTest
@@ -79,8 +87,10 @@
@Test
fun hasActivityIn_onlyIn_outputsTrue() = runBlocking(IMMEDIATE) {
- repository.setWifiNetwork(VALID_WIFI_NETWORK_MODEL)
- repository.setWifiActivity(WifiActivityModel(hasActivityIn = true, hasActivityOut = false))
+ wifiRepository.setWifiNetwork(VALID_WIFI_NETWORK_MODEL)
+ wifiRepository.setWifiActivity(
+ WifiActivityModel(hasActivityIn = true, hasActivityOut = false)
+ )
var latest: Boolean? = null
val job = underTest
@@ -95,8 +105,10 @@
@Test
fun hasActivityIn_inAndOut_outputsTrue() = runBlocking(IMMEDIATE) {
- repository.setWifiNetwork(VALID_WIFI_NETWORK_MODEL)
- repository.setWifiActivity(WifiActivityModel(hasActivityIn = true, hasActivityOut = true))
+ wifiRepository.setWifiNetwork(VALID_WIFI_NETWORK_MODEL)
+ wifiRepository.setWifiActivity(
+ WifiActivityModel(hasActivityIn = true, hasActivityOut = true)
+ )
var latest: Boolean? = null
val job = underTest
@@ -111,8 +123,10 @@
@Test
fun hasActivityIn_ssidNull_outputsFalse() = runBlocking(IMMEDIATE) {
- repository.setWifiNetwork(WifiNetworkModel.Active(networkId = 1, ssid = null))
- repository.setWifiActivity(WifiActivityModel(hasActivityIn = true, hasActivityOut = true))
+ wifiRepository.setWifiNetwork(WifiNetworkModel.Active(networkId = 1, ssid = null))
+ wifiRepository.setWifiActivity(
+ WifiActivityModel(hasActivityIn = true, hasActivityOut = true)
+ )
var latest: Boolean? = null
val job = underTest
@@ -127,8 +141,10 @@
@Test
fun hasActivityIn_inactiveNetwork_outputsFalse() = runBlocking(IMMEDIATE) {
- repository.setWifiNetwork(WifiNetworkModel.Inactive)
- repository.setWifiActivity(WifiActivityModel(hasActivityIn = true, hasActivityOut = true))
+ wifiRepository.setWifiNetwork(WifiNetworkModel.Inactive)
+ wifiRepository.setWifiActivity(
+ WifiActivityModel(hasActivityIn = true, hasActivityOut = true)
+ )
var latest: Boolean? = null
val job = underTest
@@ -143,8 +159,10 @@
@Test
fun hasActivityIn_carrierMergedNetwork_outputsFalse() = runBlocking(IMMEDIATE) {
- repository.setWifiNetwork(WifiNetworkModel.CarrierMerged)
- repository.setWifiActivity(WifiActivityModel(hasActivityIn = true, hasActivityOut = true))
+ wifiRepository.setWifiNetwork(WifiNetworkModel.CarrierMerged)
+ wifiRepository.setWifiActivity(
+ WifiActivityModel(hasActivityIn = true, hasActivityOut = true)
+ )
var latest: Boolean? = null
val job = underTest
@@ -159,7 +177,7 @@
@Test
fun hasActivityIn_multipleChanges_multipleOutputChanges() = runBlocking(IMMEDIATE) {
- repository.setWifiNetwork(VALID_WIFI_NETWORK_MODEL)
+ wifiRepository.setWifiNetwork(VALID_WIFI_NETWORK_MODEL)
var latest: Boolean? = null
val job = underTest
@@ -168,23 +186,33 @@
.launchIn(this)
// Conduct a series of changes and verify we catch each of them in succession
- repository.setWifiActivity(WifiActivityModel(hasActivityIn = true, hasActivityOut = false))
+ wifiRepository.setWifiActivity(
+ WifiActivityModel(hasActivityIn = true, hasActivityOut = false)
+ )
yield()
assertThat(latest).isTrue()
- repository.setWifiActivity(WifiActivityModel(hasActivityIn = false, hasActivityOut = true))
+ wifiRepository.setWifiActivity(
+ WifiActivityModel(hasActivityIn = false, hasActivityOut = true)
+ )
yield()
assertThat(latest).isFalse()
- repository.setWifiActivity(WifiActivityModel(hasActivityIn = true, hasActivityOut = true))
+ wifiRepository.setWifiActivity(
+ WifiActivityModel(hasActivityIn = true, hasActivityOut = true)
+ )
yield()
assertThat(latest).isTrue()
- repository.setWifiActivity(WifiActivityModel(hasActivityIn = true, hasActivityOut = false))
+ wifiRepository.setWifiActivity(
+ WifiActivityModel(hasActivityIn = true, hasActivityOut = false)
+ )
yield()
assertThat(latest).isTrue()
- repository.setWifiActivity(WifiActivityModel(hasActivityIn = false, hasActivityOut = false))
+ wifiRepository.setWifiActivity(
+ WifiActivityModel(hasActivityIn = false, hasActivityOut = false)
+ )
yield()
assertThat(latest).isFalse()
@@ -200,7 +228,7 @@
ssid = "AB",
passpointProviderFriendlyName = "friendly"
)
- repository.setWifiNetwork(wifiNetwork)
+ wifiRepository.setWifiNetwork(wifiNetwork)
var latest: WifiNetworkModel? = null
val job = underTest
@@ -213,6 +241,36 @@
job.cancel()
}
+ @Test
+ fun isForceHidden_repoHasWifiHidden_outputsTrue() = runBlocking(IMMEDIATE) {
+ connectivityRepository.setForceHiddenIcons(setOf(ConnectivitySlot.WIFI))
+
+ var latest: Boolean? = null
+ val job = underTest
+ .isForceHidden
+ .onEach { latest = it }
+ .launchIn(this)
+
+ assertThat(latest).isTrue()
+
+ job.cancel()
+ }
+
+ @Test
+ fun isForceHidden_repoDoesNotHaveWifiHidden_outputsFalse() = runBlocking(IMMEDIATE) {
+ connectivityRepository.setForceHiddenIcons(setOf())
+
+ var latest: Boolean? = null
+ val job = underTest
+ .isForceHidden
+ .onEach { latest = it }
+ .launchIn(this)
+
+ assertThat(latest).isFalse()
+
+ job.cancel()
+ }
+
companion object {
val VALID_WIFI_NETWORK_MODEL = WifiNetworkModel.Active(networkId = 1, ssid = "AB")
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt
index f0a775b..43103a0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt
@@ -17,17 +17,24 @@
package com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel
import androidx.test.filters.SmallTest
+import com.android.settingslib.AccessibilityContentDescriptions.WIFI_CONNECTION_STRENGTH
+import com.android.settingslib.AccessibilityContentDescriptions.WIFI_NO_CONNECTION
import com.android.systemui.SysuiTestCase
+import com.android.systemui.common.shared.model.ContentDescription
+import com.android.systemui.common.shared.model.Icon
import com.android.systemui.statusbar.connectivity.WifiIcons.WIFI_FULL_ICONS
import com.android.systemui.statusbar.connectivity.WifiIcons.WIFI_NO_INTERNET_ICONS
import com.android.systemui.statusbar.connectivity.WifiIcons.WIFI_NO_NETWORK
import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
+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.pipeline.wifi.data.model.WifiActivityModel
import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel
import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository
import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.WifiInteractor
import com.android.systemui.statusbar.pipeline.wifi.shared.WifiConstants
+import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.WifiViewModel.Companion.NO_INTERNET
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -50,60 +57,34 @@
@Mock private lateinit var statusBarPipelineFlags: StatusBarPipelineFlags
@Mock private lateinit var logger: ConnectivityPipelineLogger
@Mock private lateinit var constants: WifiConstants
- private lateinit var repository: FakeWifiRepository
+ private lateinit var connectivityRepository: FakeConnectivityRepository
+ private lateinit var wifiRepository: FakeWifiRepository
private lateinit var interactor: WifiInteractor
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
- repository = FakeWifiRepository()
- interactor = WifiInteractor(repository)
+ connectivityRepository = FakeConnectivityRepository()
+ wifiRepository = FakeWifiRepository()
+ interactor = WifiInteractor(connectivityRepository, wifiRepository)
underTest = WifiViewModel(
statusBarPipelineFlags,
constants,
+ context,
logger,
interactor
)
}
@Test
- fun wifiIconResId_inactiveNetwork_outputsNoNetworkIcon() = runBlocking(IMMEDIATE) {
- repository.setWifiNetwork(WifiNetworkModel.Inactive)
+ fun wifiIcon_forceHidden_outputsNull() = runBlocking(IMMEDIATE) {
+ connectivityRepository.setForceHiddenIcons(setOf(ConnectivitySlot.WIFI))
+ wifiRepository.setWifiNetwork(WifiNetworkModel.Active(NETWORK_ID, level = 2))
- var latest: Int? = null
+ var latest: Icon? = null
val job = underTest
- .wifiIconResId
- .onEach { latest = it }
- .launchIn(this)
-
- assertThat(latest).isEqualTo(WIFI_NO_NETWORK)
-
- job.cancel()
- }
-
- @Test
- fun wifiIconResId_carrierMergedNetwork_outputsNull() = runBlocking(IMMEDIATE) {
- repository.setWifiNetwork(WifiNetworkModel.CarrierMerged)
-
- var latest: Int? = null
- val job = underTest
- .wifiIconResId
- .onEach { latest = it }
- .launchIn(this)
-
- assertThat(latest).isNull()
-
- job.cancel()
- }
-
- @Test
- fun wifiIconResId_isActiveNullLevel_outputsNull() = runBlocking(IMMEDIATE) {
- repository.setWifiNetwork(WifiNetworkModel.Active(NETWORK_ID, level = null))
-
- var latest: Int? = null
- val job = underTest
- .wifiIconResId
+ .wifiIcon
.onEach { latest = it }
.launchIn(this)
@@ -113,10 +94,77 @@
}
@Test
- fun wifiIconResId_isActiveAndValidated_level1_outputsFull1Icon() = runBlocking(IMMEDIATE) {
+ fun wifiIcon_notForceHidden_outputsVisible() = runBlocking(IMMEDIATE) {
+ connectivityRepository.setForceHiddenIcons(setOf())
+ wifiRepository.setWifiNetwork(WifiNetworkModel.Active(NETWORK_ID, level = 2))
+
+ var latest: Icon? = null
+ val job = underTest
+ .wifiIcon
+ .onEach { latest = it }
+ .launchIn(this)
+
+ assertThat(latest).isInstanceOf(Icon.Resource::class.java)
+
+ job.cancel()
+ }
+
+ @Test
+ fun wifiIcon_inactiveNetwork_outputsNoNetworkIcon() = runBlocking(IMMEDIATE) {
+ wifiRepository.setWifiNetwork(WifiNetworkModel.Inactive)
+
+ var latest: Icon? = null
+ val job = underTest
+ .wifiIcon
+ .onEach { latest = it }
+ .launchIn(this)
+
+ assertThat(latest).isInstanceOf(Icon.Resource::class.java)
+ val icon = latest as Icon.Resource
+ assertThat(icon.res).isEqualTo(WIFI_NO_NETWORK)
+ assertThat(icon.contentDescription?.getAsString())
+ .contains(context.getString(WIFI_NO_CONNECTION))
+ assertThat(icon.contentDescription?.getAsString())
+ .contains(context.getString(NO_INTERNET))
+
+ job.cancel()
+ }
+
+ @Test
+ fun wifiIcon_carrierMergedNetwork_outputsNull() = runBlocking(IMMEDIATE) {
+ wifiRepository.setWifiNetwork(WifiNetworkModel.CarrierMerged)
+
+ var latest: Icon? = null
+ val job = underTest
+ .wifiIcon
+ .onEach { latest = it }
+ .launchIn(this)
+
+ assertThat(latest).isNull()
+
+ job.cancel()
+ }
+
+ @Test
+ fun wifiIcon_isActiveNullLevel_outputsNull() = runBlocking(IMMEDIATE) {
+ wifiRepository.setWifiNetwork(WifiNetworkModel.Active(NETWORK_ID, level = null))
+
+ var latest: Icon? = null
+ val job = underTest
+ .wifiIcon
+ .onEach { latest = it }
+ .launchIn(this)
+
+ assertThat(latest).isNull()
+
+ job.cancel()
+ }
+
+ @Test
+ fun wifiIcon_isActiveAndValidated_level1_outputsFull1Icon() = runBlocking(IMMEDIATE) {
val level = 1
- repository.setWifiNetwork(
+ wifiRepository.setWifiNetwork(
WifiNetworkModel.Active(
NETWORK_ID,
isValidated = true,
@@ -124,22 +172,28 @@
)
)
- var latest: Int? = null
+ var latest: Icon? = null
val job = underTest
- .wifiIconResId
- .onEach { latest = it }
- .launchIn(this)
+ .wifiIcon
+ .onEach { latest = it }
+ .launchIn(this)
- assertThat(latest).isEqualTo(WIFI_FULL_ICONS[level])
+ assertThat(latest).isInstanceOf(Icon.Resource::class.java)
+ val icon = latest as Icon.Resource
+ assertThat(icon.res).isEqualTo(WIFI_FULL_ICONS[level])
+ assertThat(icon.contentDescription?.getAsString())
+ .contains(context.getString(WIFI_CONNECTION_STRENGTH[level]))
+ assertThat(icon.contentDescription?.getAsString())
+ .doesNotContain(context.getString(NO_INTERNET))
job.cancel()
}
@Test
- fun wifiIconResId_isActiveAndNotValidated_level4_outputsEmpty4Icon() = runBlocking(IMMEDIATE) {
+ fun wifiIcon_isActiveAndNotValidated_level4_outputsEmpty4Icon() = runBlocking(IMMEDIATE) {
val level = 4
- repository.setWifiNetwork(
+ wifiRepository.setWifiNetwork(
WifiNetworkModel.Active(
NETWORK_ID,
isValidated = false,
@@ -147,13 +201,19 @@
)
)
- var latest: Int? = null
+ var latest: Icon? = null
val job = underTest
- .wifiIconResId
- .onEach { latest = it }
- .launchIn(this)
+ .wifiIcon
+ .onEach { latest = it }
+ .launchIn(this)
- assertThat(latest).isEqualTo(WIFI_NO_INTERNET_ICONS[level])
+ assertThat(latest).isInstanceOf(Icon.Resource::class.java)
+ val icon = latest as Icon.Resource
+ assertThat(icon.res).isEqualTo(WIFI_NO_INTERNET_ICONS[level])
+ assertThat(icon.contentDescription?.getAsString())
+ .contains(context.getString(WIFI_CONNECTION_STRENGTH[level]))
+ assertThat(icon.contentDescription?.getAsString())
+ .contains(context.getString(NO_INTERNET))
job.cancel()
}
@@ -161,7 +221,7 @@
@Test
fun activityInVisible_showActivityConfigFalse_outputsFalse() = runBlocking(IMMEDIATE) {
whenever(constants.shouldShowActivityConfig).thenReturn(false)
- repository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK)
+ wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK)
var latest: Boolean? = null
val job = underTest
@@ -178,7 +238,7 @@
@Test
fun activityInVisible_showActivityConfigFalse_noUpdatesReceived() = runBlocking(IMMEDIATE) {
whenever(constants.shouldShowActivityConfig).thenReturn(false)
- repository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK)
+ wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK)
var latest: Boolean? = null
val job = underTest
@@ -187,7 +247,9 @@
.launchIn(this)
// Update the repo to have activityIn
- repository.setWifiActivity(WifiActivityModel(hasActivityIn = true, hasActivityOut = false))
+ wifiRepository.setWifiActivity(
+ WifiActivityModel(hasActivityIn = true, hasActivityOut = false)
+ )
yield()
// Verify that we didn't update to activityIn=true (because our config is false)
@@ -199,7 +261,7 @@
@Test
fun activityInVisible_showActivityConfigTrue_outputsUpdate() = runBlocking(IMMEDIATE) {
whenever(constants.shouldShowActivityConfig).thenReturn(true)
- repository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK)
+ wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK)
var latest: Boolean? = null
val job = underTest
@@ -208,7 +270,9 @@
.launchIn(this)
// Update the repo to have activityIn
- repository.setWifiActivity(WifiActivityModel(hasActivityIn = true, hasActivityOut = false))
+ wifiRepository.setWifiActivity(
+ WifiActivityModel(hasActivityIn = true, hasActivityOut = false)
+ )
yield()
// Verify that we updated to activityIn=true
@@ -217,6 +281,13 @@
job.cancel()
}
+ private fun ContentDescription.getAsString(): String? {
+ return when (this) {
+ is ContentDescription.Loaded -> this.description
+ is ContentDescription.Resource -> context.getString(this.res)
+ }
+ }
+
companion object {
private const val NETWORK_ID = 2
private val ACTIVE_VALID_WIFI_NETWORK = WifiNetworkModel.Active(NETWORK_ID, ssid = "AB")
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardStateControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardStateControllerTest.java
index 4a8170f..8f363ef 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardStateControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardStateControllerTest.java
@@ -31,6 +31,7 @@
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.keyguard.logging.KeyguardUpdateMonitorLogger;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
@@ -57,6 +58,8 @@
private DumpManager mDumpManager;
@Mock
private Lazy<KeyguardUnlockAnimationController> mKeyguardUnlockAnimationControllerLazy;
+ @Mock
+ private KeyguardUpdateMonitorLogger mLogger;
@Before
public void setup() {
@@ -66,6 +69,7 @@
mKeyguardUpdateMonitor,
mLockPatternUtils,
mKeyguardUnlockAnimationControllerLazy,
+ mLogger,
mDumpManager);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherAdapterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherAdapterTest.kt
index c3805ad..8290dab 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherAdapterTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherAdapterTest.kt
@@ -57,8 +57,6 @@
@Mock
private lateinit var inflatedUserDetailItemView: KeyguardUserDetailItemView
@Mock
- private lateinit var userInfo: UserInfo
- @Mock
private lateinit var layoutInflater: LayoutInflater
@Mock
private lateinit var keyguardUserSwitcherController: KeyguardUserSwitcherController
@@ -188,7 +186,7 @@
private fun createUserRecord(isCurrentUser: Boolean, isGuestUser: Boolean) =
UserRecord(
- userInfo,
+ UserInfo(0 /* id */, "name", 0 /* flags */),
picture,
isGuestUser,
isCurrentUser,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt
similarity index 61%
rename from packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt
rename to packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt
index f133068..e616c26 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.media.taptotransfer.common
+package com.android.systemui.temporarydisplay
import android.content.Context
import android.content.pm.ApplicationInfo
@@ -30,6 +30,7 @@
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.media.taptotransfer.common.MediaTttLogger
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener
import com.android.systemui.util.concurrency.DelayableExecutor
@@ -38,7 +39,6 @@
import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.capture
import com.android.systemui.util.time.FakeSystemClock
-import com.android.systemui.util.view.ViewUtil
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
@@ -52,8 +52,8 @@
import org.mockito.MockitoAnnotations
@SmallTest
-class MediaTttChipControllerCommonTest : SysuiTestCase() {
- private lateinit var controllerCommon: TestControllerCommon
+class TemporaryViewDisplayControllerTest : SysuiTestCase() {
+ private lateinit var underTest: TestController
private lateinit var fakeClock: FakeSystemClock
private lateinit var fakeExecutor: FakeExecutor
@@ -72,8 +72,6 @@
@Mock
private lateinit var windowManager: WindowManager
@Mock
- private lateinit var viewUtil: ViewUtil
- @Mock
private lateinit var powerManager: PowerManager
@Before
@@ -97,11 +95,10 @@
fakeClock = FakeSystemClock()
fakeExecutor = FakeExecutor(fakeClock)
- controllerCommon = TestControllerCommon(
+ underTest = TestController(
context,
logger,
windowManager,
- viewUtil,
fakeExecutor,
accessibilityManager,
configurationController,
@@ -110,43 +107,43 @@
}
@Test
- fun displayChip_chipAdded() {
- controllerCommon.displayChip(getState())
+ fun displayView_viewAdded() {
+ underTest.displayView(getState())
verify(windowManager).addView(any(), any())
}
@Test
- fun displayChip_screenOff_screenWakes() {
+ fun displayView_screenOff_screenWakes() {
whenever(powerManager.isScreenOn).thenReturn(false)
- controllerCommon.displayChip(getState())
+ underTest.displayView(getState())
verify(powerManager).wakeUp(any(), any(), any())
}
@Test
- fun displayChip_screenAlreadyOn_screenNotWoken() {
+ fun displayView_screenAlreadyOn_screenNotWoken() {
whenever(powerManager.isScreenOn).thenReturn(true)
- controllerCommon.displayChip(getState())
+ underTest.displayView(getState())
verify(powerManager, never()).wakeUp(any(), any(), any())
}
@Test
- fun displayChip_twice_chipNotAddedTwice() {
- controllerCommon.displayChip(getState())
+ fun displayView_twice_viewNotAddedTwice() {
+ underTest.displayView(getState())
reset(windowManager)
- controllerCommon.displayChip(getState())
+ underTest.displayView(getState())
verify(windowManager, never()).addView(any(), any())
}
@Test
- fun displayChip_chipDoesNotDisappearsBeforeTimeout() {
+ fun displayView_viewDoesNotDisappearsBeforeTimeout() {
val state = getState()
- controllerCommon.displayChip(state)
+ underTest.displayView(state)
reset(windowManager)
fakeClock.advanceTime(TIMEOUT_MS - 1)
@@ -155,9 +152,9 @@
}
@Test
- fun displayChip_chipDisappearsAfterTimeout() {
+ fun displayView_viewDisappearsAfterTimeout() {
val state = getState()
- controllerCommon.displayChip(state)
+ underTest.displayView(state)
reset(windowManager)
fakeClock.advanceTime(TIMEOUT_MS + 1)
@@ -166,176 +163,176 @@
}
@Test
- fun displayChip_calledAgainBeforeTimeout_timeoutReset() {
- // First, display the chip
+ fun displayView_calledAgainBeforeTimeout_timeoutReset() {
+ // First, display the view
val state = getState()
- controllerCommon.displayChip(state)
+ underTest.displayView(state)
- // After some time, re-display the chip
+ // After some time, re-display the view
val waitTime = 1000L
fakeClock.advanceTime(waitTime)
- controllerCommon.displayChip(getState())
+ underTest.displayView(getState())
// Wait until the timeout for the first display would've happened
fakeClock.advanceTime(TIMEOUT_MS - waitTime + 1)
- // Verify we didn't hide the chip
+ // Verify we didn't hide the view
verify(windowManager, never()).removeView(any())
}
@Test
- fun displayChip_calledAgainBeforeTimeout_eventuallyTimesOut() {
- // First, display the chip
+ fun displayView_calledAgainBeforeTimeout_eventuallyTimesOut() {
+ // First, display the view
val state = getState()
- controllerCommon.displayChip(state)
+ underTest.displayView(state)
- // After some time, re-display the chip
+ // After some time, re-display the view
fakeClock.advanceTime(1000L)
- controllerCommon.displayChip(getState())
+ underTest.displayView(getState())
- // Ensure we still hide the chip eventually
+ // Ensure we still hide the view eventually
fakeClock.advanceTime(TIMEOUT_MS + 1)
verify(windowManager).removeView(any())
}
@Test
- fun displayScaleChange_chipReinflatedWithMostRecentState() {
- controllerCommon.displayChip(getState(name = "First name"))
- controllerCommon.displayChip(getState(name = "Second name"))
+ fun displayScaleChange_viewReinflatedWithMostRecentState() {
+ underTest.displayView(getState(name = "First name"))
+ underTest.displayView(getState(name = "Second name"))
reset(windowManager)
getConfigurationListener().onDensityOrFontScaleChanged()
verify(windowManager).removeView(any())
verify(windowManager).addView(any(), any())
- assertThat(controllerCommon.mostRecentChipInfo?.name).isEqualTo("Second name")
+ assertThat(underTest.mostRecentViewInfo?.name).isEqualTo("Second name")
}
@Test
- fun removeChip_chipRemovedAndRemovalLogged() {
- // First, add the chip
- controllerCommon.displayChip(getState())
+ fun removeView_viewRemovedAndRemovalLogged() {
+ // First, add the view
+ underTest.displayView(getState())
// Then, remove it
val reason = "test reason"
- controllerCommon.removeChip(reason)
+ underTest.removeView(reason)
verify(windowManager).removeView(any())
verify(logger).logChipRemoval(reason)
}
@Test
- fun removeChip_noAdd_viewNotRemoved() {
- controllerCommon.removeChip("reason")
+ fun removeView_noAdd_viewNotRemoved() {
+ underTest.removeView("reason")
verify(windowManager, never()).removeView(any())
}
@Test
fun setIcon_nullAppIconDrawableAndNullPackageName_stillHasIcon() {
- controllerCommon.displayChip(getState())
- val chipView = getChipView()
+ underTest.displayView(getState())
+ val view = getView()
- controllerCommon.setIcon(chipView, appPackageName = null, appIconDrawableOverride = null)
+ underTest.setIcon(view, appPackageName = null, appIconDrawableOverride = null)
- assertThat(chipView.getAppIconView().drawable).isNotNull()
+ assertThat(view.getAppIconView().drawable).isNotNull()
}
@Test
fun setIcon_nullAppIconDrawableAndInvalidPackageName_stillHasIcon() {
- controllerCommon.displayChip(getState())
- val chipView = getChipView()
+ underTest.displayView(getState())
+ val view = getView()
- controllerCommon.setIcon(
- chipView, appPackageName = "fakePackageName", appIconDrawableOverride = null
+ underTest.setIcon(
+ view, appPackageName = "fakePackageName", appIconDrawableOverride = null
)
- assertThat(chipView.getAppIconView().drawable).isNotNull()
+ assertThat(view.getAppIconView().drawable).isNotNull()
}
@Test
fun setIcon_nullAppIconDrawable_iconIsFromPackageName() {
- controllerCommon.displayChip(getState())
- val chipView = getChipView()
+ underTest.displayView(getState())
+ val view = getView()
- controllerCommon.setIcon(chipView, PACKAGE_NAME, appIconDrawableOverride = null, null)
+ underTest.setIcon(view, PACKAGE_NAME, appIconDrawableOverride = null, null)
- assertThat(chipView.getAppIconView().drawable).isEqualTo(appIconFromPackageName)
+ assertThat(view.getAppIconView().drawable).isEqualTo(appIconFromPackageName)
}
@Test
fun setIcon_hasAppIconDrawable_iconIsDrawable() {
- controllerCommon.displayChip(getState())
- val chipView = getChipView()
+ underTest.displayView(getState())
+ val view = getView()
val drawable = context.getDrawable(R.drawable.ic_alarm)!!
- controllerCommon.setIcon(chipView, PACKAGE_NAME, drawable, null)
+ underTest.setIcon(view, PACKAGE_NAME, drawable, null)
- assertThat(chipView.getAppIconView().drawable).isEqualTo(drawable)
+ assertThat(view.getAppIconView().drawable).isEqualTo(drawable)
}
@Test
fun setIcon_nullAppNameAndNullPackageName_stillHasContentDescription() {
- controllerCommon.displayChip(getState())
- val chipView = getChipView()
+ underTest.displayView(getState())
+ val view = getView()
- controllerCommon.setIcon(chipView, appPackageName = null, appNameOverride = null)
+ underTest.setIcon(view, appPackageName = null, appNameOverride = null)
- assertThat(chipView.getAppIconView().contentDescription.toString()).isNotEmpty()
+ assertThat(view.getAppIconView().contentDescription.toString()).isNotEmpty()
}
@Test
fun setIcon_nullAppNameAndInvalidPackageName_stillHasContentDescription() {
- controllerCommon.displayChip(getState())
- val chipView = getChipView()
+ underTest.displayView(getState())
+ val view = getView()
- controllerCommon.setIcon(
- chipView, appPackageName = "fakePackageName", appNameOverride = null
+ underTest.setIcon(
+ view, appPackageName = "fakePackageName", appNameOverride = null
)
- assertThat(chipView.getAppIconView().contentDescription.toString()).isNotEmpty()
+ assertThat(view.getAppIconView().contentDescription.toString()).isNotEmpty()
}
@Test
fun setIcon_nullAppName_iconContentDescriptionIsFromPackageName() {
- controllerCommon.displayChip(getState())
- val chipView = getChipView()
+ underTest.displayView(getState())
+ val view = getView()
- controllerCommon.setIcon(chipView, PACKAGE_NAME, null, appNameOverride = null)
+ underTest.setIcon(view, PACKAGE_NAME, null, appNameOverride = null)
- assertThat(chipView.getAppIconView().contentDescription).isEqualTo(APP_NAME)
+ assertThat(view.getAppIconView().contentDescription).isEqualTo(APP_NAME)
}
@Test
fun setIcon_hasAppName_iconContentDescriptionIsAppNameOverride() {
- controllerCommon.displayChip(getState())
- val chipView = getChipView()
+ underTest.displayView(getState())
+ val view = getView()
val appName = "Override App Name"
- controllerCommon.setIcon(chipView, PACKAGE_NAME, null, appName)
+ underTest.setIcon(view, PACKAGE_NAME, null, appName)
- assertThat(chipView.getAppIconView().contentDescription).isEqualTo(appName)
+ assertThat(view.getAppIconView().contentDescription).isEqualTo(appName)
}
@Test
fun setIcon_iconSizeMatchesGetIconSize() {
- controllerCommon.displayChip(getState())
- val chipView = getChipView()
+ underTest.displayView(getState())
+ val view = getView()
- controllerCommon.setIcon(chipView, PACKAGE_NAME)
- chipView.measure(
+ underTest.setIcon(view, PACKAGE_NAME)
+ view.measure(
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
)
- assertThat(chipView.getAppIconView().measuredWidth).isEqualTo(ICON_SIZE)
- assertThat(chipView.getAppIconView().measuredHeight).isEqualTo(ICON_SIZE)
+ assertThat(view.getAppIconView().measuredWidth).isEqualTo(ICON_SIZE)
+ assertThat(view.getAppIconView().measuredHeight).isEqualTo(ICON_SIZE)
}
- private fun getState(name: String = "name") = ChipInfo(name)
+ private fun getState(name: String = "name") = ViewInfo(name)
- private fun getChipView(): ViewGroup {
+ private fun getView(): ViewGroup {
val viewCaptor = ArgumentCaptor.forClass(View::class.java)
verify(windowManager).addView(viewCaptor.capture(), any())
return viewCaptor.value as ViewGroup
@@ -349,37 +346,35 @@
return callbackCaptor.value
}
- inner class TestControllerCommon(
+ inner class TestController(
context: Context,
logger: MediaTttLogger,
windowManager: WindowManager,
- viewUtil: ViewUtil,
@Main mainExecutor: DelayableExecutor,
accessibilityManager: AccessibilityManager,
configurationController: ConfigurationController,
powerManager: PowerManager,
- ) : MediaTttChipControllerCommon<ChipInfo>(
+ ) : TemporaryViewDisplayController<ViewInfo>(
context,
logger,
windowManager,
- viewUtil,
mainExecutor,
accessibilityManager,
configurationController,
powerManager,
R.layout.media_ttt_chip,
) {
- var mostRecentChipInfo: ChipInfo? = null
+ var mostRecentViewInfo: ViewInfo? = null
override val windowLayoutParams = commonWindowLayoutParams
- override fun updateChipView(newChipInfo: ChipInfo, currentChipView: ViewGroup) {
- super.updateChipView(newChipInfo, currentChipView)
- mostRecentChipInfo = newChipInfo
+ override fun updateView(newInfo: ViewInfo, currentView: ViewGroup) {
+ super.updateView(newInfo, currentView)
+ mostRecentViewInfo = newInfo
}
override fun getIconSize(isAppIcon: Boolean): Int = ICON_SIZE
}
- inner class ChipInfo(val name: String) : ChipInfoCommon {
+ inner class ViewInfo(val name: String) : TemporaryViewInfo {
override fun getTimeoutMs() = 1L
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt
index f51f783..8645298 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt
@@ -18,24 +18,28 @@
import android.hardware.devicestate.DeviceStateManager
import android.hardware.devicestate.DeviceStateManager.FoldStateListener
-import android.os.Handler
import android.os.PowerManager
import android.testing.AndroidTestingRunner
-import android.testing.TestableLooper
-import android.testing.TestableLooper.RunWithLooper
import android.view.ViewGroup
import android.view.ViewTreeObserver
import androidx.test.filters.SmallTest
import com.android.internal.util.LatencyTracker
import com.android.systemui.SysuiTestCase
import com.android.systemui.keyguard.WakefulnessLifecycle
+import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.shade.NotificationPanelViewController
import com.android.systemui.statusbar.LightRevealScrim
import com.android.systemui.statusbar.phone.CentralSurfaces
import com.android.systemui.unfold.util.FoldableDeviceStates
import com.android.systemui.unfold.util.FoldableTestUtils
+import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.any
import com.android.systemui.util.settings.GlobalSettings
+import com.android.systemui.util.time.FakeSystemClock
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.yield
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -49,7 +53,6 @@
@RunWith(AndroidTestingRunner::class)
@SmallTest
-@RunWithLooper
class FoldAodAnimationControllerTest : SysuiTestCase() {
@Mock lateinit var deviceStateManager: DeviceStateManager
@@ -74,26 +77,15 @@
private lateinit var deviceStates: FoldableDeviceStates
- private lateinit var testableLooper: TestableLooper
+ lateinit var keyguardRepository: FakeKeyguardRepository
- lateinit var foldAodAnimationController: FoldAodAnimationController
+ lateinit var underTest: FoldAodAnimationController
+ private val fakeExecutor = FakeExecutor(FakeSystemClock())
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
- testableLooper = TestableLooper.get(this)
- foldAodAnimationController =
- FoldAodAnimationController(
- Handler(testableLooper.looper),
- context.mainExecutor,
- context,
- deviceStateManager,
- wakefulnessLifecycle,
- globalSettings,
- latencyTracker,
- )
- .apply { initialize(centralSurfaces, lightRevealScrim) }
deviceStates = FoldableTestUtils.findDeviceStates(context)
whenever(notificationPanelViewController.view).thenReturn(viewGroup)
@@ -107,60 +99,102 @@
val onActionStarted = it.arguments[0] as Runnable
onActionStarted.run()
}
- verify(deviceStateManager).registerCallback(any(), foldStateListenerCaptor.capture())
- foldAodAnimationController.setIsDozing(dozing = true)
- setAodEnabled(enabled = true)
- sendFoldEvent(folded = false)
+ keyguardRepository = FakeKeyguardRepository()
+ val keyguardInteractor = KeyguardInteractor(repository = keyguardRepository)
+
+ // Needs to be run on the main thread
+ runBlocking(IMMEDIATE) {
+ underTest =
+ FoldAodAnimationController(
+ fakeExecutor,
+ context,
+ deviceStateManager,
+ wakefulnessLifecycle,
+ globalSettings,
+ latencyTracker,
+ { keyguardInteractor },
+ )
+ .apply { initialize(centralSurfaces, lightRevealScrim) }
+
+ verify(deviceStateManager).registerCallback(any(), foldStateListenerCaptor.capture())
+
+ setAodEnabled(enabled = true)
+ sendFoldEvent(folded = false)
+ }
}
@Test
- fun onFolded_aodDisabled_doesNotLogLatency() {
- setAodEnabled(enabled = false)
+ fun onFolded_aodDisabled_doesNotLogLatency() =
+ runBlocking(IMMEDIATE) {
+ val job = underTest.listenForDozing(this)
+ keyguardRepository.setDozing(true)
+ setAodEnabled(enabled = false)
- fold()
- simulateScreenTurningOn()
+ yield()
- verifyNoMoreInteractions(latencyTracker)
- }
+ fold()
+ simulateScreenTurningOn()
+
+ verifyNoMoreInteractions(latencyTracker)
+
+ job.cancel()
+ }
@Test
- fun onFolded_aodEnabled_logsLatency() {
- setAodEnabled(enabled = true)
+ fun onFolded_aodEnabled_logsLatency() =
+ runBlocking(IMMEDIATE) {
+ val job = underTest.listenForDozing(this)
+ keyguardRepository.setDozing(true)
+ setAodEnabled(enabled = true)
- fold()
- simulateScreenTurningOn()
+ yield()
- verify(latencyTracker).onActionStart(any())
- verify(latencyTracker).onActionEnd(any())
- }
+ fold()
+ simulateScreenTurningOn()
+
+ verify(latencyTracker).onActionStart(any())
+ verify(latencyTracker).onActionEnd(any())
+
+ job.cancel()
+ }
@Test
- fun onFolded_animationCancelled_doesNotLogLatency() {
- setAodEnabled(enabled = true)
+ fun onFolded_animationCancelled_doesNotLogLatency() =
+ runBlocking(IMMEDIATE) {
+ val job = underTest.listenForDozing(this)
+ keyguardRepository.setDozing(true)
+ setAodEnabled(enabled = true)
- fold()
- foldAodAnimationController.onScreenTurningOn({})
- foldAodAnimationController.onStartedWakingUp()
- testableLooper.processAllMessages()
+ yield()
- verify(latencyTracker).onActionStart(any())
- verify(latencyTracker).onActionCancel(any())
- }
+ fold()
+ underTest.onScreenTurningOn({})
+ underTest.onStartedWakingUp()
+ fakeExecutor.runAllReady()
+
+ verify(latencyTracker).onActionStart(any())
+ verify(latencyTracker).onActionCancel(any())
+
+ job.cancel()
+ }
private fun simulateScreenTurningOn() {
- foldAodAnimationController.onScreenTurningOn({})
- foldAodAnimationController.onScreenTurnedOn()
- testableLooper.processAllMessages()
+ underTest.onScreenTurningOn({})
+ underTest.onScreenTurnedOn()
+ fakeExecutor.runAllReady()
}
private fun fold() = sendFoldEvent(folded = true)
- private fun setAodEnabled(enabled: Boolean) =
- foldAodAnimationController.onAlwaysOnChanged(alwaysOn = enabled)
+ private fun setAodEnabled(enabled: Boolean) = underTest.onAlwaysOnChanged(alwaysOn = enabled)
private fun sendFoldEvent(folded: Boolean) {
val state = if (folded) deviceStates.folded else deviceStates.unfolded
foldStateListenerCaptor.value.onStateChanged(state)
}
+
+ companion object {
+ private val IMMEDIATE = Dispatchers.Main.immediate
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/UserSwitcherActivityTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/UserSwitcherActivityTest.kt
index 66367ec..3968bb7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/user/UserSwitcherActivityTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/UserSwitcherActivityTest.kt
@@ -16,23 +16,44 @@
package com.android.systemui.user
+import android.app.Application
import android.os.UserManager
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
import android.view.LayoutInflater
+import android.view.View
+import android.view.Window
+import android.window.OnBackInvokedCallback
+import android.window.OnBackInvokedDispatcher
import androidx.test.filters.SmallTest
+import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.classifier.FalsingCollector
+import com.android.systemui.flags.FeatureFlags
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.settings.UserTracker
import com.android.systemui.statusbar.policy.UserSwitcherController
+import com.android.systemui.user.ui.viewmodel.UserSwitcherViewModel
+import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.Captor
import org.mockito.Mock
+import org.mockito.Mockito.`when`
+import org.mockito.Mockito.any
+import org.mockito.Mockito.anyInt
+import org.mockito.Mockito.doNothing
+import org.mockito.Mockito.eq
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.spy
+import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
+import java.util.concurrent.Executor
@SmallTest
@RunWith(AndroidTestingRunner::class)
@@ -54,19 +75,49 @@
private lateinit var userManager: UserManager
@Mock
private lateinit var userTracker: UserTracker
+ @Mock
+ private lateinit var flags: FeatureFlags
+ @Mock
+ private lateinit var viewModelFactoryLazy: dagger.Lazy<UserSwitcherViewModel.Factory>
+ @Mock
+ private lateinit var onBackDispatcher: OnBackInvokedDispatcher
+ @Mock
+ private lateinit var decorView: View
+ @Mock
+ private lateinit var window: Window
+ @Mock
+ private lateinit var userSwitcherRootView: UserSwitcherRootView
+ @Captor
+ private lateinit var onBackInvokedCallback: ArgumentCaptor<OnBackInvokedCallback>
+ var isFinished = false
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
- activity = UserSwitcherActivity(
+ activity = spy(object : UserSwitcherActivity(
userSwitcherController,
broadcastDispatcher,
- layoutInflater,
falsingCollector,
falsingManager,
userManager,
- userTracker
- )
+ userTracker,
+ flags,
+ viewModelFactoryLazy,
+ ) {
+ override fun getOnBackInvokedDispatcher() = onBackDispatcher
+ override fun getMainExecutor(): Executor = FakeExecutor(FakeSystemClock())
+ override fun finish() {
+ isFinished = true
+ }
+ })
+ `when`(activity.window).thenReturn(window)
+ `when`(window.decorView).thenReturn(decorView)
+ `when`(activity.findViewById<UserSwitcherRootView>(R.id.user_switcher_root))
+ .thenReturn(userSwitcherRootView)
+ `when`(activity.findViewById<View>(R.id.cancel)).thenReturn(mock(View::class.java))
+ `when`(activity.findViewById<View>(R.id.add)).thenReturn(mock(View::class.java))
+ `when`(activity.application).thenReturn(mock(Application::class.java))
+ doNothing().`when`(activity).setContentView(anyInt())
}
@Test
@@ -78,4 +129,24 @@
assertThat(activity.getMaxColumns(7)).isEqualTo(4)
assertThat(activity.getMaxColumns(9)).isEqualTo(5)
}
+
+ @Test
+ fun onCreate_callbackRegistration() {
+ activity.createActivity()
+ verify(onBackDispatcher).registerOnBackInvokedCallback(
+ eq(OnBackInvokedDispatcher.PRIORITY_DEFAULT), any())
+
+ activity.destroyActivity()
+ verify(onBackDispatcher).unregisterOnBackInvokedCallback(any())
+ }
+
+ @Test
+ fun onBackInvokedCallback_finishesActivity() {
+ activity.createActivity()
+ verify(onBackDispatcher).registerOnBackInvokedCallback(
+ eq(OnBackInvokedDispatcher.PRIORITY_DEFAULT), onBackInvokedCallback.capture())
+
+ onBackInvokedCallback.value.onBackInvoked()
+ assertThat(isFinished).isTrue()
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/data/repository/UserRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/data/repository/UserRepositoryImplTest.kt
new file mode 100644
index 0000000..6b466e1
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/data/repository/UserRepositoryImplTest.kt
@@ -0,0 +1,217 @@
+/*
+ * 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.user.data.repository
+
+import android.content.pm.UserInfo
+import android.os.UserManager
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.policy.UserSwitcherController
+import com.android.systemui.user.data.source.UserRecord
+import com.android.systemui.user.shared.model.UserActionModel
+import com.android.systemui.user.shared.model.UserModel
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.capture
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.runBlocking
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.ArgumentCaptor
+import org.mockito.Captor
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(JUnit4::class)
+class UserRepositoryImplTest : SysuiTestCase() {
+
+ @Mock private lateinit var manager: UserManager
+ @Mock private lateinit var controller: UserSwitcherController
+ @Captor
+ private lateinit var userSwitchCallbackCaptor:
+ ArgumentCaptor<UserSwitcherController.UserSwitchCallback>
+
+ private lateinit var underTest: UserRepositoryImpl
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ whenever(controller.addUsersFromLockScreen).thenReturn(MutableStateFlow(false))
+ whenever(controller.isGuestUserAutoCreated).thenReturn(false)
+ whenever(controller.isGuestUserResetting).thenReturn(false)
+
+ underTest =
+ UserRepositoryImpl(
+ appContext = context,
+ manager = manager,
+ controller = controller,
+ )
+ }
+
+ @Test
+ fun `users - registers for updates`() =
+ runBlocking(IMMEDIATE) {
+ val job = underTest.users.onEach {}.launchIn(this)
+
+ verify(controller).addUserSwitchCallback(any())
+
+ job.cancel()
+ }
+
+ @Test
+ fun `users - unregisters from updates`() =
+ runBlocking(IMMEDIATE) {
+ val job = underTest.users.onEach {}.launchIn(this)
+ verify(controller).addUserSwitchCallback(capture(userSwitchCallbackCaptor))
+
+ job.cancel()
+
+ verify(controller).removeUserSwitchCallback(userSwitchCallbackCaptor.value)
+ }
+
+ @Test
+ fun `users - does not include actions`() =
+ runBlocking(IMMEDIATE) {
+ whenever(controller.users)
+ .thenReturn(
+ arrayListOf(
+ createUserRecord(0, isSelected = true),
+ createActionRecord(UserActionModel.ADD_USER),
+ createUserRecord(1),
+ createUserRecord(2),
+ createActionRecord(UserActionModel.ADD_SUPERVISED_USER),
+ createActionRecord(UserActionModel.ENTER_GUEST_MODE),
+ )
+ )
+ var models: List<UserModel>? = null
+ val job = underTest.users.onEach { models = it }.launchIn(this)
+
+ assertThat(models).hasSize(3)
+ assertThat(models?.get(0)?.id).isEqualTo(0)
+ assertThat(models?.get(0)?.isSelected).isTrue()
+ assertThat(models?.get(1)?.id).isEqualTo(1)
+ assertThat(models?.get(1)?.isSelected).isFalse()
+ assertThat(models?.get(2)?.id).isEqualTo(2)
+ assertThat(models?.get(2)?.isSelected).isFalse()
+ job.cancel()
+ }
+
+ @Test
+ fun selectedUser() =
+ runBlocking(IMMEDIATE) {
+ whenever(controller.users)
+ .thenReturn(
+ arrayListOf(
+ createUserRecord(0, isSelected = true),
+ createUserRecord(1),
+ createUserRecord(2),
+ )
+ )
+ var id: Int? = null
+ val job = underTest.selectedUser.map { it.id }.onEach { id = it }.launchIn(this)
+
+ assertThat(id).isEqualTo(0)
+
+ whenever(controller.users)
+ .thenReturn(
+ arrayListOf(
+ createUserRecord(0),
+ createUserRecord(1),
+ createUserRecord(2, isSelected = true),
+ )
+ )
+ verify(controller).addUserSwitchCallback(capture(userSwitchCallbackCaptor))
+ userSwitchCallbackCaptor.value.onUserSwitched()
+ assertThat(id).isEqualTo(2)
+
+ job.cancel()
+ }
+
+ @Test
+ fun `actions - unregisters from updates`() =
+ runBlocking(IMMEDIATE) {
+ val job = underTest.actions.onEach {}.launchIn(this)
+ verify(controller).addUserSwitchCallback(capture(userSwitchCallbackCaptor))
+
+ job.cancel()
+
+ verify(controller).removeUserSwitchCallback(userSwitchCallbackCaptor.value)
+ }
+
+ @Test
+ fun `actions - registers for updates`() =
+ runBlocking(IMMEDIATE) {
+ val job = underTest.actions.onEach {}.launchIn(this)
+
+ verify(controller).addUserSwitchCallback(any())
+
+ job.cancel()
+ }
+
+ @Test
+ fun `actopms - does not include users`() =
+ runBlocking(IMMEDIATE) {
+ whenever(controller.users)
+ .thenReturn(
+ arrayListOf(
+ createUserRecord(0, isSelected = true),
+ createActionRecord(UserActionModel.ADD_USER),
+ createUserRecord(1),
+ createUserRecord(2),
+ createActionRecord(UserActionModel.ADD_SUPERVISED_USER),
+ createActionRecord(UserActionModel.ENTER_GUEST_MODE),
+ )
+ )
+ var models: List<UserActionModel>? = null
+ val job = underTest.actions.onEach { models = it }.launchIn(this)
+
+ assertThat(models).hasSize(3)
+ assertThat(models?.get(0)).isEqualTo(UserActionModel.ADD_USER)
+ assertThat(models?.get(1)).isEqualTo(UserActionModel.ADD_SUPERVISED_USER)
+ assertThat(models?.get(2)).isEqualTo(UserActionModel.ENTER_GUEST_MODE)
+ job.cancel()
+ }
+
+ private fun createUserRecord(id: Int, isSelected: Boolean = false): UserRecord {
+ return UserRecord(
+ info = UserInfo(id, "name$id", 0),
+ isCurrent = isSelected,
+ )
+ }
+
+ private fun createActionRecord(action: UserActionModel): UserRecord {
+ return UserRecord(
+ isAddUser = action == UserActionModel.ADD_USER,
+ isAddSupervisedUser = action == UserActionModel.ADD_SUPERVISED_USER,
+ isGuest = action == UserActionModel.ENTER_GUEST_MODE,
+ )
+ }
+
+ companion object {
+ private val IMMEDIATE = Dispatchers.Main.immediate
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt
new file mode 100644
index 0000000..e914e2e
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt
@@ -0,0 +1,213 @@
+/*
+ * 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.user.domain.interactor
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
+import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.statusbar.policy.UserSwitcherController
+import com.android.systemui.user.data.repository.FakeUserRepository
+import com.android.systemui.user.shared.model.UserActionModel
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.mockito.nullable
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.runBlocking
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.Mock
+import org.mockito.Mockito.anyBoolean
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(JUnit4::class)
+class UserInteractorTest : SysuiTestCase() {
+
+ @Mock private lateinit var controller: UserSwitcherController
+ @Mock private lateinit var activityStarter: ActivityStarter
+
+ private lateinit var underTest: UserInteractor
+
+ private lateinit var userRepository: FakeUserRepository
+ private lateinit var keyguardRepository: FakeKeyguardRepository
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+
+ userRepository = FakeUserRepository()
+ keyguardRepository = FakeKeyguardRepository()
+ underTest =
+ UserInteractor(
+ repository = userRepository,
+ controller = controller,
+ activityStarter = activityStarter,
+ keyguardInteractor =
+ KeyguardInteractor(
+ repository = keyguardRepository,
+ ),
+ )
+ }
+
+ @Test
+ fun `actions - not actionable when locked and locked - no actions`() =
+ runBlocking(IMMEDIATE) {
+ userRepository.setActions(UserActionModel.values().toList())
+ userRepository.setActionableWhenLocked(false)
+ keyguardRepository.setKeyguardShowing(true)
+
+ var actions: List<UserActionModel>? = null
+ val job = underTest.actions.onEach { actions = it }.launchIn(this)
+
+ assertThat(actions).isEmpty()
+ job.cancel()
+ }
+
+ @Test
+ fun `actions - not actionable when locked and not locked`() =
+ runBlocking(IMMEDIATE) {
+ userRepository.setActions(
+ listOf(
+ UserActionModel.ENTER_GUEST_MODE,
+ UserActionModel.ADD_USER,
+ UserActionModel.ADD_SUPERVISED_USER,
+ )
+ )
+ userRepository.setActionableWhenLocked(false)
+ keyguardRepository.setKeyguardShowing(false)
+
+ var actions: List<UserActionModel>? = null
+ val job = underTest.actions.onEach { actions = it }.launchIn(this)
+
+ assertThat(actions)
+ .isEqualTo(
+ listOf(
+ UserActionModel.ENTER_GUEST_MODE,
+ UserActionModel.ADD_USER,
+ UserActionModel.ADD_SUPERVISED_USER,
+ UserActionModel.NAVIGATE_TO_USER_MANAGEMENT,
+ )
+ )
+ job.cancel()
+ }
+
+ @Test
+ fun `actions - actionable when locked and not locked`() =
+ runBlocking(IMMEDIATE) {
+ userRepository.setActions(
+ listOf(
+ UserActionModel.ENTER_GUEST_MODE,
+ UserActionModel.ADD_USER,
+ UserActionModel.ADD_SUPERVISED_USER,
+ )
+ )
+ userRepository.setActionableWhenLocked(true)
+ keyguardRepository.setKeyguardShowing(false)
+
+ var actions: List<UserActionModel>? = null
+ val job = underTest.actions.onEach { actions = it }.launchIn(this)
+
+ assertThat(actions)
+ .isEqualTo(
+ listOf(
+ UserActionModel.ENTER_GUEST_MODE,
+ UserActionModel.ADD_USER,
+ UserActionModel.ADD_SUPERVISED_USER,
+ UserActionModel.NAVIGATE_TO_USER_MANAGEMENT,
+ )
+ )
+ job.cancel()
+ }
+
+ @Test
+ fun `actions - actionable when locked and locked`() =
+ runBlocking(IMMEDIATE) {
+ userRepository.setActions(
+ listOf(
+ UserActionModel.ENTER_GUEST_MODE,
+ UserActionModel.ADD_USER,
+ UserActionModel.ADD_SUPERVISED_USER,
+ )
+ )
+ userRepository.setActionableWhenLocked(true)
+ keyguardRepository.setKeyguardShowing(true)
+
+ var actions: List<UserActionModel>? = null
+ val job = underTest.actions.onEach { actions = it }.launchIn(this)
+
+ assertThat(actions)
+ .isEqualTo(
+ listOf(
+ UserActionModel.ENTER_GUEST_MODE,
+ UserActionModel.ADD_USER,
+ UserActionModel.ADD_SUPERVISED_USER,
+ UserActionModel.NAVIGATE_TO_USER_MANAGEMENT,
+ )
+ )
+ job.cancel()
+ }
+
+ @Test
+ fun selectUser() {
+ val userId = 3
+
+ underTest.selectUser(userId)
+
+ verify(controller).onUserSelected(eq(userId), nullable())
+ }
+
+ @Test
+ fun `executeAction - guest`() {
+ underTest.executeAction(UserActionModel.ENTER_GUEST_MODE)
+
+ verify(controller).createAndSwitchToGuestUser(nullable())
+ }
+
+ @Test
+ fun `executeAction - add user`() {
+ underTest.executeAction(UserActionModel.ADD_USER)
+
+ verify(controller).showAddUserDialog(nullable())
+ }
+
+ @Test
+ fun `executeAction - add supervised user`() {
+ underTest.executeAction(UserActionModel.ADD_SUPERVISED_USER)
+
+ verify(controller).startSupervisedUserActivity()
+ }
+
+ @Test
+ fun `executeAction - manage users`() {
+ underTest.executeAction(UserActionModel.NAVIGATE_TO_USER_MANAGEMENT)
+
+ verify(activityStarter).startActivity(any(), anyBoolean())
+ }
+
+ companion object {
+ private val IMMEDIATE = Dispatchers.Main.immediate
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt
new file mode 100644
index 0000000..ef4500d
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt
@@ -0,0 +1,297 @@
+/*
+ * 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.user.ui.viewmodel
+
+import android.graphics.drawable.Drawable
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.common.shared.model.Text
+import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
+import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.power.data.repository.FakePowerRepository
+import com.android.systemui.power.domain.interactor.PowerInteractor
+import com.android.systemui.statusbar.policy.UserSwitcherController
+import com.android.systemui.user.data.repository.FakeUserRepository
+import com.android.systemui.user.domain.interactor.UserInteractor
+import com.android.systemui.user.legacyhelper.ui.LegacyUserUiHelper
+import com.android.systemui.user.shared.model.UserActionModel
+import com.android.systemui.user.shared.model.UserModel
+import com.android.systemui.util.mockito.mock
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.yield
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(JUnit4::class)
+class UserSwitcherViewModelTest : SysuiTestCase() {
+
+ @Mock private lateinit var controller: UserSwitcherController
+ @Mock private lateinit var activityStarter: ActivityStarter
+
+ private lateinit var underTest: UserSwitcherViewModel
+
+ private lateinit var userRepository: FakeUserRepository
+ private lateinit var keyguardRepository: FakeKeyguardRepository
+ private lateinit var powerRepository: FakePowerRepository
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+
+ userRepository = FakeUserRepository()
+ keyguardRepository = FakeKeyguardRepository()
+ powerRepository = FakePowerRepository()
+ underTest =
+ UserSwitcherViewModel.Factory(
+ userInteractor =
+ UserInteractor(
+ repository = userRepository,
+ controller = controller,
+ activityStarter = activityStarter,
+ keyguardInteractor =
+ KeyguardInteractor(
+ repository = keyguardRepository,
+ )
+ ),
+ powerInteractor =
+ PowerInteractor(
+ repository = powerRepository,
+ ),
+ )
+ .create(UserSwitcherViewModel::class.java)
+ }
+
+ @Test
+ fun users() =
+ runBlocking(IMMEDIATE) {
+ userRepository.setUsers(
+ listOf(
+ UserModel(
+ id = 0,
+ name = Text.Loaded("zero"),
+ image = USER_IMAGE,
+ isSelected = true,
+ isSelectable = true,
+ ),
+ UserModel(
+ id = 1,
+ name = Text.Loaded("one"),
+ image = USER_IMAGE,
+ isSelected = false,
+ isSelectable = true,
+ ),
+ UserModel(
+ id = 2,
+ name = Text.Loaded("two"),
+ image = USER_IMAGE,
+ isSelected = false,
+ isSelectable = false,
+ ),
+ )
+ )
+
+ var userViewModels: List<UserViewModel>? = null
+ val job = underTest.users.onEach { userViewModels = it }.launchIn(this)
+
+ assertThat(userViewModels).hasSize(3)
+ assertUserViewModel(
+ viewModel = userViewModels?.get(0),
+ viewKey = 0,
+ name = "zero",
+ isSelectionMarkerVisible = true,
+ alpha = LegacyUserUiHelper.USER_SWITCHER_USER_VIEW_SELECTABLE_ALPHA,
+ isClickable = true,
+ )
+ assertUserViewModel(
+ viewModel = userViewModels?.get(1),
+ viewKey = 1,
+ name = "one",
+ isSelectionMarkerVisible = false,
+ alpha = LegacyUserUiHelper.USER_SWITCHER_USER_VIEW_SELECTABLE_ALPHA,
+ isClickable = true,
+ )
+ assertUserViewModel(
+ viewModel = userViewModels?.get(2),
+ viewKey = 2,
+ name = "two",
+ isSelectionMarkerVisible = false,
+ alpha = LegacyUserUiHelper.USER_SWITCHER_USER_VIEW_NOT_SELECTABLE_ALPHA,
+ isClickable = false,
+ )
+ job.cancel()
+ }
+
+ @Test
+ fun `maximumUserColumns - few users`() =
+ runBlocking(IMMEDIATE) {
+ setUsers(count = 2)
+ var value: Int? = null
+ val job = underTest.maximumUserColumns.onEach { value = it }.launchIn(this)
+
+ assertThat(value).isEqualTo(4)
+ job.cancel()
+ }
+
+ @Test
+ fun `maximumUserColumns - many users`() =
+ runBlocking(IMMEDIATE) {
+ setUsers(count = 5)
+ var value: Int? = null
+ val job = underTest.maximumUserColumns.onEach { value = it }.launchIn(this)
+
+ assertThat(value).isEqualTo(3)
+ job.cancel()
+ }
+
+ @Test
+ fun `isOpenMenuButtonVisible - has actions - true`() =
+ runBlocking(IMMEDIATE) {
+ userRepository.setActions(UserActionModel.values().toList())
+
+ var isVisible: Boolean? = null
+ val job = underTest.isOpenMenuButtonVisible.onEach { isVisible = it }.launchIn(this)
+
+ assertThat(isVisible).isTrue()
+ job.cancel()
+ }
+
+ @Test
+ fun `isOpenMenuButtonVisible - no actions - false`() =
+ runBlocking(IMMEDIATE) {
+ userRepository.setActions(emptyList())
+
+ var isVisible: Boolean? = null
+ val job = underTest.isOpenMenuButtonVisible.onEach { isVisible = it }.launchIn(this)
+
+ assertThat(isVisible).isFalse()
+ job.cancel()
+ }
+
+ @Test
+ fun menu() =
+ runBlocking(IMMEDIATE) {
+ userRepository.setActions(UserActionModel.values().toList())
+ var isMenuVisible: Boolean? = null
+ val job = underTest.isMenuVisible.onEach { isMenuVisible = it }.launchIn(this)
+ assertThat(isMenuVisible).isFalse()
+
+ underTest.onOpenMenuButtonClicked()
+ assertThat(isMenuVisible).isTrue()
+
+ underTest.onMenuClosed()
+ assertThat(isMenuVisible).isFalse()
+
+ job.cancel()
+ }
+
+ @Test
+ fun `isFinishRequested - finishes when user is switched`() =
+ runBlocking(IMMEDIATE) {
+ setUsers(count = 2)
+ var isFinishRequested: Boolean? = null
+ val job = underTest.isFinishRequested.onEach { isFinishRequested = it }.launchIn(this)
+ assertThat(isFinishRequested).isFalse()
+
+ userRepository.setSelectedUser(1)
+ yield()
+ assertThat(isFinishRequested).isTrue()
+
+ job.cancel()
+ }
+
+ @Test
+ fun `isFinishRequested - finishes when the screen turns off`() =
+ runBlocking(IMMEDIATE) {
+ setUsers(count = 2)
+ powerRepository.setInteractive(true)
+ var isFinishRequested: Boolean? = null
+ val job = underTest.isFinishRequested.onEach { isFinishRequested = it }.launchIn(this)
+ assertThat(isFinishRequested).isFalse()
+
+ powerRepository.setInteractive(false)
+ yield()
+ assertThat(isFinishRequested).isTrue()
+
+ job.cancel()
+ }
+
+ @Test
+ fun `isFinishRequested - finishes when cancel button is clicked`() =
+ runBlocking(IMMEDIATE) {
+ setUsers(count = 2)
+ powerRepository.setInteractive(true)
+ var isFinishRequested: Boolean? = null
+ val job = underTest.isFinishRequested.onEach { isFinishRequested = it }.launchIn(this)
+ assertThat(isFinishRequested).isFalse()
+
+ underTest.onCancelButtonClicked()
+ yield()
+ assertThat(isFinishRequested).isTrue()
+
+ underTest.onFinished()
+ yield()
+ assertThat(isFinishRequested).isFalse()
+
+ job.cancel()
+ }
+
+ private fun setUsers(count: Int) {
+ userRepository.setUsers(
+ (0 until count).map { index ->
+ UserModel(
+ id = index,
+ name = Text.Loaded("$index"),
+ image = USER_IMAGE,
+ isSelected = index == 0,
+ isSelectable = true,
+ )
+ }
+ )
+ }
+
+ private fun assertUserViewModel(
+ viewModel: UserViewModel?,
+ viewKey: Int,
+ name: String,
+ isSelectionMarkerVisible: Boolean,
+ alpha: Float,
+ isClickable: Boolean,
+ ) {
+ checkNotNull(viewModel)
+ assertThat(viewModel.viewKey).isEqualTo(viewKey)
+ assertThat(viewModel.name).isEqualTo(Text.Loaded(name))
+ assertThat(viewModel.isSelectionMarkerVisible).isEqualTo(isSelectionMarkerVisible)
+ assertThat(viewModel.alpha).isEqualTo(alpha)
+ assertThat(viewModel.onClicked != null).isEqualTo(isClickable)
+ }
+
+ companion object {
+ private val IMMEDIATE = Dispatchers.Main.immediate
+ private val USER_IMAGE = mock<Drawable>()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/FlowUtilTests.kt b/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/FlowUtilTests.kt
index 092e82c..7df7077 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/FlowUtilTests.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/FlowUtilTests.kt
@@ -28,12 +28,14 @@
import kotlinx.coroutines.flow.asFlow
import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.flow.filterIsInstance
+import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.takeWhile
import kotlinx.coroutines.flow.toList
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.yield
import org.junit.Test
import org.junit.runner.RunWith
@@ -127,6 +129,53 @@
)
)
}
+
+ @Test
+ fun dontEmitFirstEvent() = runBlocking {
+ assertThatFlow(flowOf(setOf(1, 2), setOf(2, 3)).setChanges(emitFirstEvent = false))
+ .emitsExactly(
+ SetChanges(
+ removed = setOf(1),
+ added = setOf(3),
+ )
+ )
+ }
+}
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class SampleFlowTest : SysuiTestCase() {
+ @Test
+ fun simple() = runBlocking {
+ assertThatFlow(flow { yield(); emit(1) }.sample(flowOf(2)) { a, b -> a to b })
+ .emitsExactly(1 to 2)
+ }
+
+ @Test
+ fun otherFlowNoValueYet() = runBlocking {
+ assertThatFlow(flowOf(1).sample(emptyFlow<Unit>()))
+ .emitsNothing()
+ }
+
+ @Test
+ fun multipleSamples() = runBlocking {
+ val samplee = MutableSharedFlow<Int>()
+ val sampler = flow {
+ emit(1)
+ samplee.emit(1)
+ emit(2)
+ samplee.emit(2)
+ samplee.emit(3)
+ emit(3)
+ emit(4)
+ }
+ assertThatFlow(sampler.sample(samplee) { a, b -> a to b })
+ .emitsExactly(
+ 2 to 1,
+ 3 to 3,
+ 4 to 3,
+ )
+ }
}
private fun <T> assertThatFlow(flow: Flow<T>) = object {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/SuspendUtilTests.kt b/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/SuspendUtilTests.kt
new file mode 100644
index 0000000..6848b83
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/SuspendUtilTests.kt
@@ -0,0 +1,55 @@
+/*
+ * 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.util.kotlin
+
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.CompletableDeferred
+import kotlinx.coroutines.async
+import kotlinx.coroutines.awaitCancellation
+import kotlinx.coroutines.runBlocking
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class RaceSuspendTest : SysuiTestCase() {
+ @Test
+ fun raceSimple() = runBlocking {
+ val winner = CompletableDeferred<Int>()
+ val result = async {
+ race(
+ { winner.await() },
+ { awaitCancellation() },
+ )
+ }
+ winner.complete(1)
+ assertThat(result.await()).isEqualTo(1)
+ }
+
+ @Test
+ fun raceImmediate() = runBlocking {
+ assertThat(
+ race<Int>(
+ { 1 },
+ { 2 },
+ )
+ ).isEqualTo(1)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ImageWallpaperTest.java b/packages/SystemUI/tests/src/com/android/systemui/wallpapers/ImageWallpaperTest.java
similarity index 97%
rename from packages/SystemUI/tests/src/com/android/systemui/ImageWallpaperTest.java
rename to packages/SystemUI/tests/src/com/android/systemui/wallpapers/ImageWallpaperTest.java
index e1ddaad..e47acd8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ImageWallpaperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wallpapers/ImageWallpaperTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui;
+package com.android.systemui.wallpapers;
import static com.google.common.truth.Truth.assertWithMessage;
@@ -40,7 +40,8 @@
import android.view.DisplayInfo;
import android.view.SurfaceHolder;
-import com.android.systemui.glwallpaper.ImageWallpaperRenderer;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.wallpapers.gl.ImageWallpaperRenderer;
import org.junit.Before;
import org.junit.Ignore;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/glwallpaper/EglHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/wallpapers/gl/EglHelperTest.java
similarity index 98%
rename from packages/SystemUI/tests/src/com/android/systemui/glwallpaper/EglHelperTest.java
rename to packages/SystemUI/tests/src/com/android/systemui/wallpapers/gl/EglHelperTest.java
index a3221b5..a42bade 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/glwallpaper/EglHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wallpapers/gl/EglHelperTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.glwallpaper;
+package com.android.systemui.wallpapers.gl;
import static com.google.common.truth.Truth.assertThat;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/glwallpaper/ImageWallpaperRendererTest.java b/packages/SystemUI/tests/src/com/android/systemui/wallpapers/gl/ImageWallpaperRendererTest.java
similarity index 98%
rename from packages/SystemUI/tests/src/com/android/systemui/glwallpaper/ImageWallpaperRendererTest.java
rename to packages/SystemUI/tests/src/com/android/systemui/wallpapers/gl/ImageWallpaperRendererTest.java
index 510b907..89b2222 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/glwallpaper/ImageWallpaperRendererTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wallpapers/gl/ImageWallpaperRendererTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.glwallpaper;
+package com.android.systemui.wallpapers.gl;
import static com.google.common.truth.Truth.assertThat;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
similarity index 99%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
rename to packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
index 11eb4e3..42b434a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
@@ -12,6 +12,7 @@
* WITHOUT 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.data.repository
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/power/data/repository/FakePowerRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/power/data/repository/FakePowerRepository.kt
new file mode 100644
index 0000000..15465f4
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/power/data/repository/FakePowerRepository.kt
@@ -0,0 +1,34 @@
+/*
+ * 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.power.data.repository
+
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asStateFlow
+
+class FakePowerRepository(
+ initialInteractive: Boolean = true,
+) : PowerRepository {
+
+ private val _isInteractive = MutableStateFlow(initialInteractive)
+ override val isInteractive: Flow<Boolean> = _isInteractive.asStateFlow()
+
+ fun setInteractive(value: Boolean) {
+ _isInteractive.value = value
+ }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/user/data/repository/FakeUserRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/user/data/repository/FakeUserRepository.kt
new file mode 100644
index 0000000..20f1e36
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/user/data/repository/FakeUserRepository.kt
@@ -0,0 +1,82 @@
+/*
+ * 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.user.data.repository
+
+import com.android.systemui.user.shared.model.UserActionModel
+import com.android.systemui.user.shared.model.UserModel
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.map
+
+class FakeUserRepository : UserRepository {
+
+ private val _users = MutableStateFlow<List<UserModel>>(emptyList())
+ override val users: Flow<List<UserModel>> = _users.asStateFlow()
+ override val selectedUser: Flow<UserModel> =
+ users.map { models -> models.first { model -> model.isSelected } }
+
+ private val _actions = MutableStateFlow<List<UserActionModel>>(emptyList())
+ override val actions: Flow<List<UserActionModel>> = _actions.asStateFlow()
+
+ private val _isActionableWhenLocked = MutableStateFlow(false)
+ override val isActionableWhenLocked: Flow<Boolean> = _isActionableWhenLocked.asStateFlow()
+
+ private var _isGuestUserAutoCreated: Boolean = false
+ override val isGuestUserAutoCreated: Boolean
+ get() = _isGuestUserAutoCreated
+ private var _isGuestUserResetting: Boolean = false
+ override val isGuestUserResetting: Boolean
+ get() = _isGuestUserResetting
+
+ fun setUsers(models: List<UserModel>) {
+ _users.value = models
+ }
+
+ fun setSelectedUser(userId: Int) {
+ check(_users.value.find { it.id == userId } != null) {
+ "Cannot select a user with ID $userId - no user with that ID found!"
+ }
+
+ setUsers(
+ _users.value.map { model ->
+ when {
+ model.isSelected && model.id != userId -> model.copy(isSelected = false)
+ !model.isSelected && model.id == userId -> model.copy(isSelected = true)
+ else -> model
+ }
+ }
+ )
+ }
+
+ fun setActions(models: List<UserActionModel>) {
+ _actions.value = models
+ }
+
+ fun setActionableWhenLocked(value: Boolean) {
+ _isActionableWhenLocked.value = value
+ }
+
+ fun setGuestUserAutoCreated(value: Boolean) {
+ _isGuestUserAutoCreated = value
+ }
+
+ fun setGuestUserResetting(value: Boolean) {
+ _isGuestUserResetting = value
+ }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/util/mockito/KotlinMockitoHelpers.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/util/mockito/KotlinMockitoHelpers.kt
index f539dbd..8d171be 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/util/mockito/KotlinMockitoHelpers.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/util/mockito/KotlinMockitoHelpers.kt
@@ -26,6 +26,7 @@
import org.mockito.ArgumentCaptor
import org.mockito.ArgumentMatcher
import org.mockito.Mockito
+import org.mockito.stubbing.OngoingStubbing
/**
* Returns Mockito.eq() as nullable type to avoid java.lang.IllegalStateException when
@@ -77,8 +78,18 @@
* Helper function for creating new mocks, without the need to pass in a [Class] instance.
*
* Generic T is nullable because implicitly bounded by Any?.
+ *
+ * @param apply builder function to simplify stub configuration by improving type inference.
*/
-inline fun <reified T : Any> mock(): T = Mockito.mock(T::class.java)
+inline fun <reified T : Any> mock(apply: T.() -> Unit = {}): T = Mockito.mock(T::class.java)
+ .apply(apply)
+
+/**
+ * Helper function for stubbing methods without the need to use backticks.
+ *
+ * @see Mockito.when
+ */
+fun <T> whenever(methodCall: T): OngoingStubbing<T> = Mockito.`when`(methodCall)
/**
* A kotlin implemented wrapper of [ArgumentCaptor] which prevents the following exception when
@@ -118,3 +129,17 @@
*/
inline fun <reified T : Any> withArgCaptor(block: KotlinArgumentCaptor<T>.() -> Unit): T =
kotlinArgumentCaptor<T>().apply { block() }.value
+
+/**
+ * Variant of [withArgCaptor] for capturing multiple arguments.
+ *
+ * val captor = argumentCaptor<Foo>()
+ * verify(...).someMethod(captor.capture())
+ * val captured: List<Foo> = captor.allValues
+ *
+ * becomes:
+ *
+ * val capturedList = captureMany<Foo> { verify(...).someMethod(capture()) }
+ */
+inline fun <reified T : Any> captureMany(block: KotlinArgumentCaptor<T>.() -> Unit): List<T> =
+ kotlinArgumentCaptor<T>().apply{ block() }.allValues
diff --git a/services/autofill/java/com/android/server/autofill/PresentationStatsEventLogger.java b/services/autofill/java/com/android/server/autofill/PresentationStatsEventLogger.java
index 01cee33..b5fdaca 100644
--- a/services/autofill/java/com/android/server/autofill/PresentationStatsEventLogger.java
+++ b/services/autofill/java/com/android/server/autofill/PresentationStatsEventLogger.java
@@ -41,7 +41,12 @@
import android.annotation.IntDef;
import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.provider.Settings;
import android.service.autofill.Dataset;
+import android.text.TextUtils;
import android.util.Slog;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillManager;
@@ -61,7 +66,7 @@
* Reasons why presentation was not shown. These are wrappers around
* {@link com.android.os.AtomsProto.AutofillPresentationEventReported.PresentationEventResult}.
*/
- @IntDef(prefix = { "NOT_SHOWN_REASON" }, value = {
+ @IntDef(prefix = {"NOT_SHOWN_REASON"}, value = {
NOT_SHOWN_REASON_ANY_SHOWN,
NOT_SHOWN_REASON_VIEW_FOCUS_CHANGED,
NOT_SHOWN_REASON_VIEW_CHANGED,
@@ -72,6 +77,7 @@
})
@Retention(RetentionPolicy.SOURCE)
public @interface NotShownReason {}
+
public static final int NOT_SHOWN_REASON_ANY_SHOWN = AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__ANY_SHOWN;
public static final int NOT_SHOWN_REASON_VIEW_FOCUS_CHANGED = AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_VIEW_FOCUS_CHANGED;
public static final int NOT_SHOWN_REASON_VIEW_CHANGED = AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_VIEW_CHANGED;
@@ -172,6 +178,45 @@
});
}
+ public void maybeSetInlinePresentationAndSuggestionHostUid(Context context, int userId) {
+ mEventInternal.ifPresent(event -> {
+ event.mDisplayPresentationType = UI_TYPE_INLINE;
+ String imeString = Settings.Secure.getStringForUser(context.getContentResolver(),
+ Settings.Secure.DEFAULT_INPUT_METHOD, userId);
+ if (TextUtils.isEmpty(imeString)) {
+ Slog.w(TAG, "No default IME found");
+ return;
+ }
+ ComponentName imeComponent = ComponentName.unflattenFromString(imeString);
+ if (imeComponent == null) {
+ Slog.w(TAG, "No default IME found");
+ return;
+ }
+ int imeUid;
+ String packageName = imeComponent.getPackageName();
+ try {
+ imeUid = context.getPackageManager().getApplicationInfoAsUser(packageName,
+ PackageManager.ApplicationInfoFlags.of(0), userId).uid;
+ } catch (PackageManager.NameNotFoundException e) {
+ Slog.w(TAG, "Couldn't find packageName: " + packageName);
+ return;
+ }
+ event.mInlineSuggestionHostUid = imeUid;
+ });
+ }
+
+ public void maybeSetAutofillServiceUid(int uid) {
+ mEventInternal.ifPresent(event -> {
+ event.mAutofillServiceUid = uid;
+ });
+ }
+
+ public void maybeSetIsNewRequest(boolean isRequestTriggered) {
+ mEventInternal.ifPresent(event -> {
+ event.mIsRequestTriggered = isRequestTriggered;
+ });
+ }
+
public void logAndEndEvent() {
if (!mEventInternal.isPresent()) {
Slog.w(TAG, "Shouldn't be logging AutofillPresentationEventReported again for same "
@@ -190,7 +235,10 @@
+ " mCountNotShownImePresentationNotDrawn="
+ event.mCountNotShownImePresentationNotDrawn
+ " mCountNotShownImeUserNotSeen=" + event.mCountNotShownImeUserNotSeen
- + " mDisplayPresentationType=" + event.mDisplayPresentationType);
+ + " mDisplayPresentationType=" + event.mDisplayPresentationType
+ + " mAutofillServiceUid=" + event.mAutofillServiceUid
+ + " mInlineSuggestionHostUid=" + event.mInlineSuggestionHostUid
+ + " mIsRequestTriggered=" + event.mIsRequestTriggered);
}
// TODO(b/234185326): Distinguish empty responses from other no presentation reasons.
@@ -208,7 +256,10 @@
event.mCountFilteredUserTyping,
event.mCountNotShownImePresentationNotDrawn,
event.mCountNotShownImeUserNotSeen,
- event.mDisplayPresentationType);
+ event.mDisplayPresentationType,
+ event.mAutofillServiceUid,
+ event.mInlineSuggestionHostUid,
+ event.mIsRequestTriggered);
mEventInternal = Optional.empty();
}
@@ -222,6 +273,9 @@
int mCountNotShownImePresentationNotDrawn;
int mCountNotShownImeUserNotSeen;
int mDisplayPresentationType = AUTOFILL_PRESENTATION_EVENT_REPORTED__DISPLAY_PRESENTATION_TYPE__UNKNOWN_AUTOFILL_DISPLAY_PRESENTATION_TYPE;
+ int mAutofillServiceUid = -1;
+ int mInlineSuggestionHostUid = -1;
+ boolean mIsRequestTriggered;
PresentationStatsEventInternal() {}
}
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 0fe9f8f..bd9c03a 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -66,6 +66,7 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentSender;
+import android.content.pm.ServiceInfo;
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
@@ -77,6 +78,7 @@
import android.os.IBinder;
import android.os.IBinder.DeathRecipient;
import android.os.Parcelable;
+import android.os.Process;
import android.os.RemoteCallback;
import android.os.RemoteException;
import android.os.SystemClock;
@@ -2968,6 +2970,7 @@
mSessionFlags.mFillDialogDisabled = true;
}
mPresentationStatsEventLogger.startNewEvent();
+ mPresentationStatsEventLogger.maybeSetAutofillServiceUid(getAutofillServiceUid());
requestNewFillResponseLocked(viewState, ViewState.STATE_STARTED_SESSION, flags);
break;
case ACTION_VALUE_CHANGED:
@@ -3057,6 +3060,7 @@
}
mPresentationStatsEventLogger.startNewEvent();
+ mPresentationStatsEventLogger.maybeSetAutofillServiceUid(getAutofillServiceUid());
if (requestNewFillResponseOnViewEnteredIfNecessaryLocked(id, viewState, flags)) {
return;
}
@@ -3292,7 +3296,8 @@
// shown, inflated, and filtered.
mPresentationStatsEventLogger.maybeSetCountShown(
response.getDatasets(), mCurrentViewId);
- mPresentationStatsEventLogger.maybeSetDisplayPresentationType(UI_TYPE_INLINE);
+ mPresentationStatsEventLogger.maybeSetInlinePresentationAndSuggestionHostUid(
+ mContext, userId);
return;
}
}
@@ -4639,4 +4644,9 @@
return "UNKNOWN_SESSION_STATE_" + sessionState;
}
}
+
+ private int getAutofillServiceUid() {
+ ServiceInfo serviceInfo = mService.getServiceInfo();
+ return serviceInfo == null ? Process.INVALID_UID : serviceInfo.applicationInfo.uid;
+ }
}
diff --git a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
index 593a63c..fc628cf 100644
--- a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
+++ b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
@@ -250,7 +250,9 @@
// The callback is fired only when windowFlags are changed. To let VirtualDevice owner
// aware that the virtual display has a secure window on top.
if ((windowFlags & FLAG_SECURE) != 0) {
- mSecureWindowCallback.onSecureWindowShown(mDisplayId, activityInfo.applicationInfo.uid);
+ // Post callback on the main thread, so it doesn't block activity launching.
+ mHandler.post(() -> mSecureWindowCallback.onSecureWindowShown(mDisplayId,
+ activityInfo.applicationInfo.uid));
}
if (!canContainActivity(activityInfo, windowFlags, systemWindowFlags)) {
diff --git a/services/core/java/com/android/server/VpnManagerService.java b/services/core/java/com/android/server/VpnManagerService.java
index 07b6843..7cb2fd0 100644
--- a/services/core/java/com/android/server/VpnManagerService.java
+++ b/services/core/java/com/android/server/VpnManagerService.java
@@ -28,6 +28,7 @@
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.UserInfo;
import android.net.ConnectivityManager;
import android.net.INetd;
import android.net.IVpnManager;
@@ -771,6 +772,12 @@
@VisibleForTesting
void onUserStarted(int userId) {
+ UserInfo user = mUserManager.getUserInfo(userId);
+ if (user == null) {
+ logw("Started user doesn't exist. UserId: " + userId);
+ return;
+ }
+
synchronized (mVpns) {
Vpn userVpn = mVpns.get(userId);
if (userVpn != null) {
@@ -779,7 +786,8 @@
}
userVpn = mDeps.createVpn(mHandler.getLooper(), mContext, mNMS, mNetd, userId);
mVpns.put(userId, userVpn);
- if (mUserManager.getUserInfo(userId).isPrimary() && isLockdownVpnEnabled()) {
+
+ if (user.isPrimary() && isLockdownVpnEnabled()) {
updateLockdownVpn();
}
}
@@ -896,9 +904,15 @@
}
private void onUserUnlocked(int userId) {
+ UserInfo user = mUserManager.getUserInfo(userId);
+ if (user == null) {
+ logw("Unlocked user doesn't exist. UserId: " + userId);
+ return;
+ }
+
synchronized (mVpns) {
// User present may be sent because of an unlock, which might mean an unlocked keystore.
- if (mUserManager.getUserInfo(userId).isPrimary() && isLockdownVpnEnabled()) {
+ if (user.isPrimary() && isLockdownVpnEnabled()) {
updateLockdownVpn();
} else {
startAlwaysOnVpn(userId);
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 8368b4d..9840e0f 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -190,6 +190,7 @@
import java.util.List;
import java.util.Objects;
import java.util.Set;
+import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Predicate;
public final class ActiveServices {
@@ -220,6 +221,11 @@
| ServiceInfo.FOREGROUND_SERVICE_TYPE_CONNECTED_DEVICE
| ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION;
+ // Keep track of number of foreground services and number of apps that have foreground
+ // services in the device. This field is made to be directly accessed without holding AMS lock.
+ static final AtomicReference<Pair<Integer, Integer>> sNumForegroundServices =
+ new AtomicReference(new Pair<>(0, 0));
+
// Foreground service is stopped for unknown reason.
static final int FGS_STOP_REASON_UNKNOWN = 0;
// Foreground service is stopped by app calling Service.stopForeground().
@@ -454,6 +460,7 @@
final ArrayList<ServiceRecord> mStartingBackground = new ArrayList<>();
final ArrayMap<String, ActiveForegroundApp> mActiveForegroundApps = new ArrayMap<>();
+
boolean mActiveForegroundAppsChanged;
static final int MSG_BG_START_TIMEOUT = 1;
@@ -2025,6 +2032,7 @@
logFGSStateChangeLocked(r,
FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__ENTER,
0, FGS_STOP_REASON_UNKNOWN);
+ updateNumForegroundServicesLocked();
}
// Even if the service is already a FGS, we need to update the notification,
// so we need to call it again.
@@ -2116,6 +2124,7 @@
mAm.updateLruProcessLocked(r.app, false, null);
updateServiceForegroundLocked(r.app.mServices, true);
}
+ updateNumForegroundServicesLocked();
}
}
}
@@ -4784,6 +4793,7 @@
}
smap.ensureNotStartingBackgroundLocked(r);
+ updateNumForegroundServicesLocked();
}
private void dropFgsNotificationStateLocked(ServiceRecord r) {
@@ -6975,6 +6985,10 @@
fgsStopReasonToString(fgsStopReason));
}
+ private void updateNumForegroundServicesLocked() {
+ sNumForegroundServices.set(mAm.mProcessList.getNumForegroundServices());
+ }
+
boolean canAllowWhileInUsePermissionInFgsLocked(int callingPid, int callingUid,
String callingPackage) {
return shouldAllowFgsWhileInUsePermissionLocked(callingPackage, callingPid, callingUid,
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index ef9b2ed..d4b760f 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -148,6 +148,7 @@
import static com.android.server.wm.ActivityTaskManagerService.DUMP_RECENTS_SHORT_CMD;
import static com.android.server.wm.ActivityTaskManagerService.DUMP_STARTER_CMD;
import static com.android.server.wm.ActivityTaskManagerService.DUMP_TOP_RESUMED_ACTIVITY;
+import static com.android.server.wm.ActivityTaskManagerService.DUMP_VISIBLE_ACTIVITIES;
import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_NONE;
import static com.android.server.wm.ActivityTaskManagerService.relaunchReasonToString;
@@ -9546,7 +9547,8 @@
|| DUMP_LASTANR_CMD.equals(cmd) || DUMP_LASTANR_TRACES_CMD.equals(cmd)
|| DUMP_STARTER_CMD.equals(cmd) || DUMP_CONTAINERS_CMD.equals(cmd)
|| DUMP_RECENTS_CMD.equals(cmd) || DUMP_RECENTS_SHORT_CMD.equals(cmd)
- || DUMP_TOP_RESUMED_ACTIVITY.equals(cmd)) {
+ || DUMP_TOP_RESUMED_ACTIVITY.equals(cmd)
+ || DUMP_VISIBLE_ACTIVITIES.equals(cmd)) {
mAtmInternal.dump(
cmd, fd, pw, args, opti, true /* dumpAll */, dumpClient, dumpPackage);
} else if ("binder-proxies".equals(cmd)) {
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index 0d3685d..9921956 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -1167,7 +1167,18 @@
return;
}
Slog.d(TAG_AM, "quick sync unfreeze " + pid);
- unfreezeAppLSP(app, reason);
+ try {
+ freezeBinder(pid, false);
+ } catch (RuntimeException e) {
+ Slog.e(TAG_AM, "Unable to quick unfreeze binder for " + pid);
+ return;
+ }
+
+ try {
+ Process.setProcessFrozen(pid, app.uid, false);
+ } catch (Exception e) {
+ Slog.e(TAG_AM, "Unable to quick unfreeze " + pid);
+ }
}
}
diff --git a/services/core/java/com/android/server/am/OWNERS b/services/core/java/com/android/server/am/OWNERS
index c4efbd7..7fa1e13 100644
--- a/services/core/java/com/android/server/am/OWNERS
+++ b/services/core/java/com/android/server/am/OWNERS
@@ -40,3 +40,7 @@
per-file CarUserSwitchingDialog.java = keunyoung@google.com, felipeal@google.com, gurunagarajan@google.com
per-file ContentProviderHelper.java = varunshah@google.com, omakoto@google.com, jsharkey@google.com, yamasani@google.com
+
+# Multiuser
+per-file User* = file:/MULTIUSER_OWNERS
+
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index a8d7e13..3eac406 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -814,12 +814,14 @@
< LmkdStatsReporter.KILL_OCCURRED_MSG_SIZE) {
return false;
}
- Pair<Integer, Integer> temp = getNumForegroundServices();
- final int totalForegroundServices = temp.first;
- final int procsWithForegroundServices = temp.second;
+ // Note: directly access
+ // ActiveServices.sNumForegroundServices, do not try to
+ // hold AMS lock here, otherwise it is a potential deadlock.
+ Pair<Integer, Integer> foregroundServices =
+ ActiveServices.sNumForegroundServices.get();
LmkdStatsReporter.logKillOccurred(inputData,
- totalForegroundServices,
- procsWithForegroundServices);
+ foregroundServices.first,
+ foregroundServices.second);
return true;
case LMK_STATE_CHANGED:
if (receivedLen
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 7ffea26..44b186e 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -106,6 +106,7 @@
import com.android.internal.policy.IKeyguardDismissCallback;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FrameworkStatsLog;
+import com.android.internal.util.Preconditions;
import com.android.internal.widget.LockPatternUtils;
import com.android.server.FactoryResetter;
import com.android.server.FgThread;
@@ -368,6 +369,11 @@
private boolean mDelayUserDataLocking;
/**
+ * Users are only allowed to be unlocked after boot complete.
+ */
+ private volatile boolean mAllowUserUnlocking;
+
+ /**
* Keep track of last active users for mDelayUserDataLocking.
* The latest stopped user is placed in front while the least recently stopped user in back.
*/
@@ -426,6 +432,11 @@
mUserLru.add(UserHandle.USER_SYSTEM);
mLockPatternUtils = mInjector.getLockPatternUtils();
updateStartedUserArrayLU();
+
+ // TODO(b/232452368): currently mAllowUserUnlocking is only used on devices with HSUM
+ // (Headless System User Mode), but on master it will be used by all devices (and hence this
+ // initial assignment should be removed).
+ mAllowUserUnlocking = !UserManager.isHeadlessSystemUserMode();
}
void setInitialConfig(boolean userSwitchUiEnabled, int maxRunningUsers,
@@ -1742,6 +1753,22 @@
private boolean unlockUserCleared(final @UserIdInt int userId, byte[] secret,
IProgressListener listener) {
+ // Delay user unlocking for headless system user mode until the system boot
+ // completes. When the system boot completes, the {@link #onBootCompleted()}
+ // method unlocks all started users for headless system user mode. This is done
+ // to prevent unlocking the users too early during the system boot up.
+ // Otherwise, emulated volumes are mounted too early during the system
+ // boot up. When vold is reset on boot complete, vold kills all apps/services
+ // (that use these emulated volumes) before unmounting the volumes(b/241929666).
+ // In the past, these killings have caused the system to become too unstable on
+ // some occasions.
+ // Any unlocks that get delayed by this will be done by onBootComplete() instead.
+ if (!mAllowUserUnlocking) {
+ Slogf.i(TAG, "Not unlocking user %d yet because boot hasn't completed", userId);
+ notifyFinished(userId, listener);
+ return false;
+ }
+
UserState uss;
if (!StorageManager.isUserKeyUnlocked(userId)) {
final UserInfo userInfo = getUserInfo(userId);
@@ -2331,7 +2358,44 @@
}
}
+ @VisibleForTesting
+ void setAllowUserUnlocking(boolean allowed) {
+ mAllowUserUnlocking = allowed;
+ if (DEBUG_MU) {
+ // TODO(b/245335748): use Slogf.d instead
+ // Slogf.d(TAG, new Exception(), "setAllowUserUnlocking(%b)", allowed);
+ android.util.Slog.d(TAG, "setAllowUserUnlocking():" + allowed, new Exception());
+ }
+ }
+
+ /**
+ * @deprecated TODO(b/232452368): this logic will be merged into sendBootCompleted
+ */
+ @Deprecated
+ private void onBootCompletedOnHeadlessSystemUserModeDevices() {
+ setAllowUserUnlocking(true);
+
+ // Get a copy of mStartedUsers to use outside of lock.
+ SparseArray<UserState> startedUsers;
+ synchronized (mLock) {
+ startedUsers = mStartedUsers.clone();
+ }
+ // USER_SYSTEM must be processed first. It will be first in the array, as its ID is lowest.
+ Preconditions.checkArgument(startedUsers.keyAt(0) == UserHandle.USER_SYSTEM);
+ for (int i = 0; i < startedUsers.size(); i++) {
+ UserState uss = startedUsers.valueAt(i);
+ int userId = uss.mHandle.getIdentifier();
+ Slogf.i(TAG, "Attempting to unlock user %d on boot complete", userId);
+ maybeUnlockUser(userId);
+ }
+ }
+
void sendBootCompleted(IIntentReceiver resultTo) {
+ if (UserManager.isHeadlessSystemUserMode()) {
+ // Unlocking users is delayed until boot complete for headless system user mode.
+ onBootCompletedOnHeadlessSystemUserModeDevices();
+ }
+
// Get a copy of mStartedUsers to use outside of lock
SparseArray<UserState> startedUsers;
synchronized (mLock) {
@@ -2773,6 +2837,7 @@
pw.println(" mTargetUserId:" + mTargetUserId);
pw.println(" mLastActiveUsers:" + mLastActiveUsers);
pw.println(" mDelayUserDataLocking:" + mDelayUserDataLocking);
+ pw.println(" mAllowUserUnlocking:" + mAllowUserUnlocking);
pw.println(" shouldStopUserOnSwitch():" + shouldStopUserOnSwitch());
pw.println(" mStopUserOnSwitch:" + mStopUserOnSwitch);
pw.println(" mMaxRunningUsers:" + mMaxRunningUsers);
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 2b8d6a33..0d08db9 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -17,9 +17,12 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.compat.CompatChanges;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothProfile;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledSince;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
@@ -118,8 +121,39 @@
// TODO do not "share" the lock between AudioService and BtHelpr, see b/123769055
/*package*/ final Object mSetModeLock = new Object();
- /** PID of current audio mode owner communicated by AudioService */
- private int mModeOwnerPid = 0;
+ /** AudioModeInfo contains information on current audio mode owner
+ * communicated by AudioService */
+ /* package */ static final class AudioModeInfo {
+ /** Current audio mode */
+ final int mMode;
+ /** PID of current audio mode owner */
+ final int mPid;
+ /** UID of current audio mode owner */
+ final int mUid;
+
+ AudioModeInfo(int mode, int pid, int uid) {
+ mMode = mode;
+ mPid = pid;
+ mUid = uid;
+ }
+
+ @Override
+ public String toString() {
+ return "AudioModeInfo: mMode=" + AudioSystem.modeToString(mMode)
+ + ", mPid=" + mPid
+ + ", mUid=" + mUid;
+ }
+ };
+
+ private AudioModeInfo mAudioModeOwner = new AudioModeInfo(AudioSystem.MODE_NORMAL, 0, 0);
+
+ /**
+ * Indicates that default communication device is chosen by routing rules in audio policy
+ * manager and not forced by AudioDeviceBroker.
+ */
+ @ChangeId
+ @EnabledSince(targetSdkVersion = android.os.Build.VERSION_CODES.S_V2)
+ public static final long USE_SET_COMMUNICATION_DEVICE = 243827847L;
//-------------------------------------------------------------------
/*package*/ AudioDeviceBroker(@NonNull Context context, @NonNull AudioService service) {
@@ -187,7 +221,7 @@
/*package*/ void onSystemReady() {
synchronized (mSetModeLock) {
synchronized (mDeviceStateLock) {
- mModeOwnerPid = mAudioService.getModeOwnerPid();
+ mAudioModeOwner = mAudioService.getAudioModeOwner();
mBtHelper.onSystemReady();
}
}
@@ -368,11 +402,11 @@
@GuardedBy("mDeviceStateLock")
private CommunicationRouteClient topCommunicationRouteClient() {
for (CommunicationRouteClient crc : mCommunicationRouteClients) {
- if (crc.getPid() == mModeOwnerPid) {
+ if (crc.getPid() == mAudioModeOwner.mPid) {
return crc;
}
}
- if (!mCommunicationRouteClients.isEmpty() && mModeOwnerPid == 0) {
+ if (!mCommunicationRouteClients.isEmpty() && mAudioModeOwner.mPid == 0) {
return mCommunicationRouteClients.get(0);
}
return null;
@@ -390,7 +424,7 @@
AudioDeviceAttributes device = crc != null ? crc.getDevice() : null;
if (AudioService.DEBUG_COMM_RTE) {
Log.v(TAG, "requestedCommunicationDevice, device: "
- + device + " mode owner pid: " + mModeOwnerPid);
+ + device + "mAudioModeOwner: " + mAudioModeOwner.toString());
}
return device;
}
@@ -774,8 +808,9 @@
sendLMsgNoDelay(MSG_II_SET_LE_AUDIO_OUT_VOLUME, SENDMSG_REPLACE, info);
}
- /*package*/ void postSetModeOwnerPid(int pid, int mode) {
- sendIIMsgNoDelay(MSG_I_SET_MODE_OWNER_PID, SENDMSG_REPLACE, pid, mode);
+ /*package*/ void postSetModeOwner(int mode, int pid, int uid) {
+ sendLMsgNoDelay(MSG_I_SET_MODE_OWNER, SENDMSG_REPLACE,
+ new AudioModeInfo(mode, pid, uid));
}
/*package*/ void postBluetoothA2dpDeviceConfigChange(@NonNull BluetoothDevice device) {
@@ -1162,7 +1197,7 @@
pw.println(prefix + "mAccessibilityStrategyId: "
+ mAccessibilityStrategyId);
- pw.println("\n" + prefix + "mModeOwnerPid: " + mModeOwnerPid);
+ pw.println("\n" + prefix + "mAudioModeOwner: " + mAudioModeOwner);
mBtHelper.dump(pw, prefix);
}
@@ -1288,12 +1323,19 @@
}
break;
case MSG_L_SET_BT_ACTIVE_DEVICE:
- synchronized (mDeviceStateLock) {
- BtDeviceInfo btInfo = (BtDeviceInfo) msg.obj;
- mDeviceInventory.onSetBtActiveDevice(btInfo,
- (btInfo.mProfile != BluetoothProfile.LE_AUDIO || btInfo.mIsLeOutput)
- ? mAudioService.getBluetoothContextualVolumeStream()
- : AudioSystem.STREAM_DEFAULT);
+ synchronized (mSetModeLock) {
+ synchronized (mDeviceStateLock) {
+ BtDeviceInfo btInfo = (BtDeviceInfo) msg.obj;
+ mDeviceInventory.onSetBtActiveDevice(btInfo,
+ (btInfo.mProfile
+ != BluetoothProfile.LE_AUDIO || btInfo.mIsLeOutput)
+ ? mAudioService.getBluetoothContextualVolumeStream()
+ : AudioSystem.STREAM_DEFAULT);
+ if (btInfo.mProfile == BluetoothProfile.LE_AUDIO
+ || btInfo.mProfile == BluetoothProfile.HEARING_AID) {
+ onUpdateCommunicationRouteClient("setBluetoothActiveDevice");
+ }
+ }
}
break;
case MSG_BT_HEADSET_CNCT_FAILED:
@@ -1337,11 +1379,11 @@
mBtHelper.setAvrcpAbsoluteVolumeIndex(msg.arg1);
}
break;
- case MSG_I_SET_MODE_OWNER_PID:
+ case MSG_I_SET_MODE_OWNER:
synchronized (mSetModeLock) {
synchronized (mDeviceStateLock) {
- mModeOwnerPid = msg.arg1;
- if (msg.arg2 != AudioSystem.MODE_RINGTONE) {
+ mAudioModeOwner = (AudioModeInfo) msg.obj;
+ if (mAudioModeOwner.mMode != AudioSystem.MODE_RINGTONE) {
onUpdateCommunicationRouteClient("setNewModeOwner");
}
}
@@ -1503,7 +1545,7 @@
private static final int MSG_REPORT_NEW_ROUTES = 13;
private static final int MSG_II_SET_HEARING_AID_VOLUME = 14;
private static final int MSG_I_SET_AVRCP_ABSOLUTE_VOLUME = 15;
- private static final int MSG_I_SET_MODE_OWNER_PID = 16;
+ private static final int MSG_I_SET_MODE_OWNER = 16;
private static final int MSG_I_BT_SERVICE_DISCONNECTED_PROFILE = 22;
private static final int MSG_IL_BT_SERVICE_CONNECTED_PROFILE = 23;
@@ -1825,8 +1867,16 @@
AudioSystem.setParameters("BT_SCO=on");
}
if (preferredCommunicationDevice == null) {
- removePreferredDevicesForStrategySync(mCommunicationStrategyId);
- removePreferredDevicesForStrategySync(mAccessibilityStrategyId);
+ AudioDeviceAttributes defaultDevice = getDefaultCommunicationDevice();
+ if (defaultDevice != null) {
+ setPreferredDevicesForStrategySync(
+ mCommunicationStrategyId, Arrays.asList(defaultDevice));
+ setPreferredDevicesForStrategySync(
+ mAccessibilityStrategyId, Arrays.asList(defaultDevice));
+ } else {
+ removePreferredDevicesForStrategySync(mCommunicationStrategyId);
+ removePreferredDevicesForStrategySync(mAccessibilityStrategyId);
+ }
} else {
setPreferredDevicesForStrategySync(
mCommunicationStrategyId, Arrays.asList(preferredCommunicationDevice));
@@ -1855,26 +1905,24 @@
}
}
+ // @GuardedBy("mSetModeLock")
+ @GuardedBy("mDeviceStateLock")
private void onUpdatePhoneStrategyDevice(AudioDeviceAttributes device) {
- synchronized (mSetModeLock) {
- synchronized (mDeviceStateLock) {
- boolean wasSpeakerphoneActive = isSpeakerphoneActive();
- mPreferredCommunicationDevice = device;
- updateActiveCommunicationDevice();
- if (wasSpeakerphoneActive != isSpeakerphoneActive()) {
- try {
- mContext.sendBroadcastAsUser(
- new Intent(AudioManager.ACTION_SPEAKERPHONE_STATE_CHANGED)
- .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
- UserHandle.ALL);
- } catch (Exception e) {
- Log.w(TAG, "failed to broadcast ACTION_SPEAKERPHONE_STATE_CHANGED: " + e);
- }
- }
- mAudioService.postUpdateRingerModeServiceInt();
- dispatchCommunicationDevice();
+ boolean wasSpeakerphoneActive = isSpeakerphoneActive();
+ mPreferredCommunicationDevice = device;
+ updateActiveCommunicationDevice();
+ if (wasSpeakerphoneActive != isSpeakerphoneActive()) {
+ try {
+ mContext.sendBroadcastAsUser(
+ new Intent(AudioManager.ACTION_SPEAKERPHONE_STATE_CHANGED)
+ .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
+ UserHandle.ALL);
+ } catch (Exception e) {
+ Log.w(TAG, "failed to broadcast ACTION_SPEAKERPHONE_STATE_CHANGED: " + e);
}
}
+ mAudioService.postUpdateRingerModeServiceInt();
+ dispatchCommunicationDevice();
}
private CommunicationRouteClient removeCommunicationRouteClient(
@@ -1914,6 +1962,32 @@
return null;
}
+ @GuardedBy("mDeviceStateLock")
+ private boolean communnicationDeviceCompatOn() {
+ return mAudioModeOwner.mMode == AudioSystem.MODE_IN_COMMUNICATION
+ && !(CompatChanges.isChangeEnabled(
+ USE_SET_COMMUNICATION_DEVICE, mAudioModeOwner.mUid)
+ || mAudioModeOwner.mUid == android.os.Process.SYSTEM_UID);
+ }
+
+ @GuardedBy("mDeviceStateLock")
+ AudioDeviceAttributes getDefaultCommunicationDevice() {
+ // For system server (Telecom) and APKs targeting S and above, we let the audio
+ // policy routing rules select the default communication device.
+ // For older APKs, we force Hearing Aid or LE Audio headset when connected as
+ // those APKs cannot select a LE Audio or Hearing Aid device explicitly.
+ AudioDeviceAttributes device = null;
+ if (communnicationDeviceCompatOn()) {
+ // If both LE and Hearing Aid are active (thie should not happen),
+ // priority to Hearing Aid.
+ device = mDeviceInventory.getDeviceOfType(AudioSystem.DEVICE_OUT_HEARING_AID);
+ if (device == null) {
+ device = mDeviceInventory.getDeviceOfType(AudioSystem.DEVICE_OUT_BLE_HEADSET);
+ }
+ }
+ return device;
+ }
+
@Nullable UUID getDeviceSensorUuid(AudioDeviceAttributes device) {
synchronized (mDeviceStateLock) {
return mDeviceInventory.getDeviceSensorUuid(device);
diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
index 54b2d56..ee0d79f 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
@@ -294,6 +294,7 @@
}
}
+ // @GuardedBy("AudioDeviceBroker.mSetModeLock")
@GuardedBy("AudioDeviceBroker.mDeviceStateLock")
void onSetBtActiveDevice(@NonNull AudioDeviceBroker.BtDeviceInfo btInfo, int streamType) {
if (AudioService.DEBUG_DEVICES) {
@@ -1510,6 +1511,19 @@
return di.mSensorUuid;
}
}
+
+ /* package */ AudioDeviceAttributes getDeviceOfType(int type) {
+ synchronized (mDevicesLock) {
+ for (DeviceInfo di : mConnectedDevices.values()) {
+ if (di.mDeviceType == type) {
+ return new AudioDeviceAttributes(
+ di.mDeviceType, di.mDeviceAddress, di.mDeviceName);
+ }
+ }
+ }
+ return null;
+ }
+
//----------------------------------------------------------
// For tests only
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 0a081bf..0b6b890 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -1005,7 +1005,9 @@
mSfxHelper = new SoundEffectsHelper(mContext);
- mSpatializerHelper = new SpatializerHelper(this, mAudioSystem);
+ final boolean headTrackingDefault = mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_spatial_audio_head_tracking_enabled_default);
+ mSpatializerHelper = new SpatializerHelper(this, mAudioSystem, headTrackingDefault);
mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
mHasVibrator = mVibrator == null ? false : mVibrator.hasVibrator();
@@ -3353,8 +3355,7 @@
dispatchAbsoluteVolumeChanged(streamType, info, newIndex);
}
- if ((device == AudioSystem.DEVICE_OUT_BLE_HEADSET
- || device == AudioSystem.DEVICE_OUT_BLE_BROADCAST)
+ if (AudioSystem.isLeAudioDeviceType(device)
&& streamType == getBluetoothContextualVolumeStream()
&& (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
if (DEBUG_VOL) {
@@ -4110,8 +4111,7 @@
dispatchAbsoluteVolumeChanged(streamType, info, index);
}
- if ((device == AudioSystem.DEVICE_OUT_BLE_HEADSET
- || device == AudioSystem.DEVICE_OUT_BLE_BROADCAST)
+ if (AudioSystem.isLeAudioDeviceType(device)
&& streamType == getBluetoothContextualVolumeStream()
&& (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
if (DEBUG_VOL) {
@@ -5225,16 +5225,17 @@
}
/**
- * Return the pid of the current audio mode owner
+ * Return information on the current audio mode owner
* @return 0 if nobody owns the mode
*/
@GuardedBy("mDeviceBroker.mSetModeLock")
- /*package*/ int getModeOwnerPid() {
+ /*package*/ AudioDeviceBroker.AudioModeInfo getAudioModeOwner() {
SetModeDeathHandler hdlr = getAudioModeOwnerHandler();
if (hdlr != null) {
- return hdlr.getPid();
+ return new AudioDeviceBroker.AudioModeInfo(
+ hdlr.getMode(), hdlr.getPid(), hdlr.getUid());
}
- return 0;
+ return new AudioDeviceBroker.AudioModeInfo(AudioSystem.MODE_NORMAL, 0 , 0);
}
/**
@@ -5420,7 +5421,7 @@
// when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all SCO
// connections not started by the application changing the mode when pid changes
- mDeviceBroker.postSetModeOwnerPid(pid, mode);
+ mDeviceBroker.postSetModeOwner(mode, pid, uid);
} else {
Log.w(TAG, "onUpdateAudioMode: failed to set audio mode to: " + mode);
}
@@ -5748,7 +5749,10 @@
}
return deviceIds.stream().mapToInt(Integer::intValue).toArray();
}
- /** @see AudioManager#setCommunicationDevice(int) */
+ /**
+ * @see AudioManager#setCommunicationDevice(int)
+ * @see AudioManager#clearCommunicationDevice()
+ */
public boolean setCommunicationDevice(IBinder cb, int portId) {
final int uid = Binder.getCallingUid();
final int pid = Binder.getCallingPid();
@@ -5763,7 +5767,8 @@
throw new IllegalArgumentException("invalid device type " + device.getType());
}
}
- final String eventSource = new StringBuilder("setCommunicationDevice(")
+ final String eventSource = new StringBuilder()
+ .append(device == null ? "clearCommunicationDevice(" : "setCommunicationDevice(")
.append(") from u/pid:").append(uid).append("/")
.append(pid).toString();
@@ -6950,7 +6955,8 @@
return AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE;
}
if (isAbsoluteVolumeDevice(audioSystemDeviceOut)
- || isA2dpAbsoluteVolumeDevice(audioSystemDeviceOut)) {
+ || isA2dpAbsoluteVolumeDevice(audioSystemDeviceOut)
+ || AudioSystem.isLeAudioDeviceType(audioSystemDeviceOut)) {
return AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE;
}
return AudioManager.DEVICE_VOLUME_BEHAVIOR_VARIABLE;
@@ -7717,7 +7723,9 @@
int index;
if (isFullyMuted()) {
index = 0;
- } else if (isAbsoluteVolumeDevice(device) || isA2dpAbsoluteVolumeDevice(device)) {
+ } else if (isAbsoluteVolumeDevice(device)
+ || isA2dpAbsoluteVolumeDevice(device)
+ || AudioSystem.isLeAudioDeviceType(device)) {
index = getAbsoluteVolumeIndex((getIndex(device) + 5)/10);
} else if (isFullVolumeDevice(device)) {
index = (mIndexMax + 5)/10;
@@ -7739,7 +7747,8 @@
if (isFullyMuted()) {
index = 0;
} else if (isAbsoluteVolumeDevice(device)
- || isA2dpAbsoluteVolumeDevice(device)) {
+ || isA2dpAbsoluteVolumeDevice(device)
+ || AudioSystem.isLeAudioDeviceType(device)) {
index = getAbsoluteVolumeIndex((getIndex(device) + 5)/10);
} else if (isFullVolumeDevice(device)) {
index = (mIndexMax + 5)/10;
@@ -8160,7 +8169,8 @@
int streamDevice = getDeviceForStream(streamType);
if ((device != streamDevice)
&& (isAbsoluteVolumeDevice(device)
- || isA2dpAbsoluteVolumeDevice(device))) {
+ || isA2dpAbsoluteVolumeDevice(device)
+ || AudioSystem.isLeAudioDeviceType(device))) {
mStreamStates[streamType].applyDeviceVolume_syncVSS(device);
}
mStreamStates[streamType].applyDeviceVolume_syncVSS(streamDevice);
diff --git a/services/core/java/com/android/server/audio/AudioServiceEvents.java b/services/core/java/com/android/server/audio/AudioServiceEvents.java
index b5835ce..30a9e0a7 100644
--- a/services/core/java/com/android/server/audio/AudioServiceEvents.java
+++ b/services/core/java/com/android/server/audio/AudioServiceEvents.java
@@ -433,7 +433,7 @@
case VOL_SET_LE_AUDIO_VOL:
return new StringBuilder("setLeAudioVolume:")
.append(" index:").append(mVal1)
- .append(" gain dB:").append(mVal2)
+ .append(" maxIndex:").append(mVal2)
.toString();
case VOL_SET_AVRCP_VOL:
return new StringBuilder("setAvrcpVolume:")
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index 9a7c6626..d0f5470 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -412,9 +412,8 @@
}
return;
}
- /* leaudio expect volume value in range 0 to 255
- */
- int volume = (index * (BT_LE_AUDIO_MAX_VOL - BT_LE_AUDIO_MIN_VOL)) / maxIndex ;
+ /* leaudio expect volume value in range 0 to 255 */
+ int volume = (int) Math.round((double) index * BT_LE_AUDIO_MAX_VOL / maxIndex);
if (AudioService.DEBUG_VOL) {
Log.i(TAG, "setLeAudioVolume: calling mLeAudio.setVolume idx="
diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
index b3e7e31..93841fe 100644
--- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
+++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
@@ -49,6 +49,7 @@
import java.util.Iterator;
import java.util.List;
import java.util.Set;
+import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.function.Consumer;
/**
@@ -104,11 +105,7 @@
private static final VolumeShaper.Operation PLAY_SKIP_RAMP =
new VolumeShaper.Operation.Builder(PLAY_CREATE_IF_NEEDED).setXOffset(1.0f).build();
- private final ArrayList<PlayMonitorClient> mClients = new ArrayList<PlayMonitorClient>();
- // a public client is one that needs an anonymized version of the playback configurations, we
- // keep track of whether there is at least one to know when we need to create the list of
- // playback configurations that do not contain uid/pid/package name information.
- private boolean mHasPublicClients = false;
+ private final ConcurrentLinkedQueue<PlayMonitorClient> mClients = new ConcurrentLinkedQueue<>();
private final Object mPlayerLock = new Object();
@GuardedBy("mPlayerLock")
@@ -458,11 +455,9 @@
+ DateFormat.getTimeInstance().format(new Date()));
synchronized(mPlayerLock) {
pw.println("\n playback listeners:");
- synchronized(mClients) {
- for (PlayMonitorClient pmc : mClients) {
- pw.print(" " + (pmc.mIsPrivileged ? "(S)" : "(P)")
- + pmc.toString());
- }
+ for (PlayMonitorClient pmc : mClients) {
+ pw.print(" " + (pmc.isPrivileged() ? "(S)" : "(P)")
+ + pmc.toString());
}
pw.println("\n");
// all players
@@ -534,48 +529,33 @@
* @param iplayerReleased indicates if the change was due to a player being released
*/
private void dispatchPlaybackChange(boolean iplayerReleased) {
- synchronized (mClients) {
- // typical use case, nobody is listening, don't do any work
- if (mClients.isEmpty()) {
- return;
- }
- }
if (DEBUG) { Log.v(TAG, "dispatchPlaybackChange to " + mClients.size() + " clients"); }
final List<AudioPlaybackConfiguration> configsSystem;
- // list of playback configurations for "public consumption". It is only computed if there
+ // list of playback configurations for "public consumption". It is computed lazy if there
// are non-system playback activity listeners.
- final List<AudioPlaybackConfiguration> configsPublic;
+ List<AudioPlaybackConfiguration> configsPublic = null;
synchronized (mPlayerLock) {
if (mPlayers.isEmpty()) {
return;
}
- configsSystem = new ArrayList<AudioPlaybackConfiguration>(mPlayers.values());
+ configsSystem = new ArrayList<>(mPlayers.values());
}
- synchronized (mClients) {
- // was done at beginning of method, but could have changed
- if (mClients.isEmpty()) {
- return;
- }
- configsPublic = mHasPublicClients ? anonymizeForPublicConsumption(configsSystem) : null;
- final Iterator<PlayMonitorClient> clientIterator = mClients.iterator();
- while (clientIterator.hasNext()) {
- final PlayMonitorClient pmc = clientIterator.next();
- try {
- // do not spam the logs if there are problems communicating with this client
- if (pmc.mErrorCount < PlayMonitorClient.MAX_ERRORS) {
- if (pmc.mIsPrivileged) {
- pmc.mDispatcherCb.dispatchPlaybackConfigChange(configsSystem,
- iplayerReleased);
- } else {
- // non-system clients don't have the control interface IPlayer, so
- // they don't need to flush commands when a player was released
- pmc.mDispatcherCb.dispatchPlaybackConfigChange(configsPublic, false);
- }
+
+ final Iterator<PlayMonitorClient> clientIterator = mClients.iterator();
+ while (clientIterator.hasNext()) {
+ final PlayMonitorClient pmc = clientIterator.next();
+ // do not spam the logs if there are problems communicating with this client
+ if (!pmc.reachedMaxErrorCount()) {
+ if (pmc.isPrivileged()) {
+ pmc.dispatchPlaybackConfigChange(configsSystem,
+ iplayerReleased);
+ } else {
+ if (configsPublic == null) {
+ configsPublic = anonymizeForPublicConsumption(configsSystem);
}
- } catch (RemoteException e) {
- pmc.mErrorCount++;
- Log.e(TAG, "Error (" + pmc.mErrorCount +
- ") trying to dispatch playback config change to " + pmc, e);
+ // non-system clients don't have the control interface IPlayer, so
+ // they don't need to flush commands when a player was released
+ pmc.dispatchPlaybackConfigChange(configsPublic, false);
}
}
}
@@ -798,14 +778,9 @@
if (pcdb == null) {
return;
}
- synchronized(mClients) {
- final PlayMonitorClient pmc = new PlayMonitorClient(pcdb, isPrivileged);
- if (pmc.init()) {
- if (!isPrivileged) {
- mHasPublicClients = true;
- }
- mClients.add(pmc);
- }
+ final PlayMonitorClient pmc = new PlayMonitorClient(pcdb, isPrivileged);
+ if (pmc.init()) {
+ mClients.add(pmc);
}
}
@@ -813,23 +788,14 @@
if (pcdb == null) {
return;
}
- synchronized(mClients) {
- final Iterator<PlayMonitorClient> clientIterator = mClients.iterator();
- boolean hasPublicClients = false;
- // iterate over the clients to remove the dispatcher to remove, and reevaluate at
- // the same time if we still have a public client.
- while (clientIterator.hasNext()) {
- PlayMonitorClient pmc = clientIterator.next();
- if (pcdb.asBinder().equals(pmc.mDispatcherCb.asBinder())) {
- pmc.release();
- clientIterator.remove();
- } else {
- if (!pmc.mIsPrivileged) {
- hasPublicClients = true;
- }
- }
+ final Iterator<PlayMonitorClient> clientIterator = mClients.iterator();
+ // iterate over the clients to remove the dispatcher
+ while (clientIterator.hasNext()) {
+ PlayMonitorClient pmc = clientIterator.next();
+ if (pmc.equalsDispatcher(pcdb)) {
+ pmc.release();
+ clientIterator.remove();
}
- mHasPublicClients = hasPublicClients;
}
}
@@ -857,24 +823,34 @@
// can afford to be static because only one PlaybackActivityMonitor ever instantiated
static PlaybackActivityMonitor sListenerDeathMonitor;
- final IPlaybackConfigDispatcher mDispatcherCb;
- final boolean mIsPrivileged;
-
- int mErrorCount = 0;
// number of errors after which we don't update this client anymore to not spam the logs
- static final int MAX_ERRORS = 5;
+ private static final int MAX_ERRORS = 5;
+
+ private final IPlaybackConfigDispatcher mDispatcherCb;
+
+ @GuardedBy("this")
+ private final boolean mIsPrivileged;
+ @GuardedBy("this")
+ private boolean mIsReleased = false;
+ @GuardedBy("this")
+ private int mErrorCount = 0;
PlayMonitorClient(IPlaybackConfigDispatcher pcdb, boolean isPrivileged) {
mDispatcherCb = pcdb;
mIsPrivileged = isPrivileged;
}
+ @Override
public void binderDied() {
Log.w(TAG, "client died");
sListenerDeathMonitor.unregisterPlaybackCallback(mDispatcherCb);
}
- boolean init() {
+ synchronized boolean init() {
+ if (mIsReleased) {
+ // Do not init after release
+ return false;
+ }
try {
mDispatcherCb.asBinder().linkToDeath(this, 0);
return true;
@@ -884,8 +860,43 @@
}
}
- void release() {
+ synchronized void release() {
mDispatcherCb.asBinder().unlinkToDeath(this, 0);
+ mIsReleased = true;
+ }
+
+ void dispatchPlaybackConfigChange(List<AudioPlaybackConfiguration> configs,
+ boolean flush) {
+ synchronized (this) {
+ if (mIsReleased) {
+ // Do not dispatch anything after release
+ return;
+ }
+ }
+ try {
+ mDispatcherCb.dispatchPlaybackConfigChange(configs, flush);
+ } catch (RemoteException e) {
+ synchronized (this) {
+ mErrorCount++;
+ Log.e(TAG, "Error (" + mErrorCount
+ + ") trying to dispatch playback config change to " + this, e);
+ }
+ }
+ }
+
+ synchronized boolean isPrivileged() {
+ return mIsPrivileged;
+ }
+
+ synchronized boolean reachedMaxErrorCount() {
+ return mErrorCount >= MAX_ERRORS;
+ }
+
+ synchronized boolean equalsDispatcher(IPlaybackConfigDispatcher pcdb) {
+ if (pcdb == null) {
+ return false;
+ }
+ return pcdb.asBinder().equals(mDispatcherCb.asBinder());
}
}
diff --git a/services/core/java/com/android/server/audio/SpatializerHelper.java b/services/core/java/com/android/server/audio/SpatializerHelper.java
index c143675..8e8fd05 100644
--- a/services/core/java/com/android/server/audio/SpatializerHelper.java
+++ b/services/core/java/com/android/server/audio/SpatializerHelper.java
@@ -169,9 +169,20 @@
//------------------------------------------------------
// initialization
- SpatializerHelper(@NonNull AudioService mother, @NonNull AudioSystemAdapter asa) {
+ @SuppressWarnings("StaticAssignmentInConstructor")
+ SpatializerHelper(@NonNull AudioService mother, @NonNull AudioSystemAdapter asa,
+ boolean headTrackingEnabledByDefault) {
mAudioService = mother;
mASA = asa;
+ // "StaticAssignmentInConstructor" warning is suppressed as the SpatializerHelper being
+ // constructed here is the factory for SADeviceState, thus SADeviceState and its
+ // private static field sHeadTrackingEnabledDefault should never be accessed directly.
+ SADeviceState.sHeadTrackingEnabledDefault = headTrackingEnabledByDefault;
+ }
+
+ synchronized void initForTest(boolean hasBinaural, boolean hasTransaural) {
+ mBinauralSupported = hasBinaural;
+ mTransauralSupported = hasTransaural;
}
synchronized void init(boolean effectExpected, @Nullable String settings) {
@@ -1502,18 +1513,26 @@
}
/*package*/ static final class SADeviceState {
+ private static boolean sHeadTrackingEnabledDefault = false;
final @AudioDeviceInfo.AudioDeviceType int mDeviceType;
final @NonNull String mDeviceAddress;
boolean mEnabled = true; // by default, SA is enabled on any device
boolean mHasHeadTracker = false;
- boolean mHeadTrackerEnabled = true; // by default, if head tracker is present, use it
+ boolean mHeadTrackerEnabled;
static final String SETTING_FIELD_SEPARATOR = ",";
static final String SETTING_DEVICE_SEPARATOR_CHAR = "|";
static final String SETTING_DEVICE_SEPARATOR = "\\|";
- SADeviceState(@AudioDeviceInfo.AudioDeviceType int deviceType, @NonNull String address) {
+ /**
+ * Constructor
+ * @param deviceType
+ * @param address must be non-null for wireless devices
+ * @throws NullPointerException if a null address is passed for a wireless device
+ */
+ SADeviceState(@AudioDeviceInfo.AudioDeviceType int deviceType, @Nullable String address) {
mDeviceType = deviceType;
mDeviceAddress = isWireless(deviceType) ? Objects.requireNonNull(address) : "";
+ mHeadTrackerEnabled = sHeadTrackingEnabledDefault;
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/ClientMonitorCallbackConverter.java b/services/core/java/com/android/server/biometrics/sensors/ClientMonitorCallbackConverter.java
index 46d863d..2e1a363 100644
--- a/services/core/java/com/android/server/biometrics/sensors/ClientMonitorCallbackConverter.java
+++ b/services/core/java/com/android/server/biometrics/sensors/ClientMonitorCallbackConverter.java
@@ -59,7 +59,7 @@
// The following apply to all clients
- void onAcquired(int sensorId, int acquiredInfo, int vendorCode) throws RemoteException {
+ public void onAcquired(int sensorId, int acquiredInfo, int vendorCode) throws RemoteException {
if (mSensorReceiver != null) {
mSensorReceiver.onAcquired(sensorId, acquiredInfo, vendorCode);
} else if (mFaceServiceReceiver != null) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
index e0393b5..612d906 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
@@ -50,12 +50,14 @@
import com.android.server.biometrics.sensors.EnrollClient;
import com.android.server.biometrics.sensors.SensorOverlays;
import com.android.server.biometrics.sensors.fingerprint.FingerprintUtils;
+import com.android.server.biometrics.sensors.fingerprint.PowerPressHandler;
import com.android.server.biometrics.sensors.fingerprint.Udfps;
import com.android.server.biometrics.sensors.fingerprint.UdfpsHelper;
import java.util.function.Supplier;
-class FingerprintEnrollClient extends EnrollClient<AidlSession> implements Udfps {
+class FingerprintEnrollClient extends EnrollClient<AidlSession> implements Udfps,
+ PowerPressHandler {
private static final String TAG = "FingerprintEnrollClient";
@@ -266,4 +268,10 @@
Slog.e(TAG, "Unable to send UI ready", e);
}
}
+
+ @Override
+ public void onPowerPressed() {
+ onAcquired(BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_POWER_PRESSED,
+ 0 /* vendorCode */);
+ }
}
diff --git a/services/core/java/com/android/server/camera/CameraServiceProxy.java b/services/core/java/com/android/server/camera/CameraServiceProxy.java
index b425420..aec60de 100644
--- a/services/core/java/com/android/server/camera/CameraServiceProxy.java
+++ b/services/core/java/com/android/server/camera/CameraServiceProxy.java
@@ -582,13 +582,18 @@
}
@Override
- public boolean isCameraDisabled() {
+ public boolean isCameraDisabled(int userId) {
DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
if (dpm == null) {
Slog.e(TAG, "Failed to get the device policy manager service");
return false;
}
- return dpm.getCameraDisabled(null);
+ try {
+ return dpm.getCameraDisabled(null, userId);
+ } catch (Exception e) {
+ e.printStackTrace();
+ return false;
+ }
}
};
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 98238cc..481c5db 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -222,6 +222,11 @@
*/
private static final int VPN_DEFAULT_SCORE = 101;
+ /**
+ * The initial token value of IKE session.
+ */
+ private static final int STARTING_TOKEN = -1;
+
// TODO: create separate trackers for each unique VPN to support
// automated reconnection
@@ -747,7 +752,7 @@
return true;
}
- private boolean sendEventToVpnManagerApp(@NonNull String category, int errorClass,
+ private Intent buildVpnManagerEventIntent(@NonNull String category, int errorClass,
int errorCode, @NonNull final String packageName, @Nullable final String sessionKey,
@NonNull final VpnProfileState profileState, @Nullable final Network underlyingNetwork,
@Nullable final NetworkCapabilities nc, @Nullable final LinkProperties lp) {
@@ -766,6 +771,20 @@
intent.putExtra(VpnManager.EXTRA_ERROR_CODE, errorCode);
}
+ return intent;
+ }
+
+ private boolean sendEventToVpnManagerApp(@NonNull String category, int errorClass,
+ int errorCode, @NonNull final String packageName, @Nullable final String sessionKey,
+ @NonNull final VpnProfileState profileState, @Nullable final Network underlyingNetwork,
+ @Nullable final NetworkCapabilities nc, @Nullable final LinkProperties lp) {
+ final Intent intent = buildVpnManagerEventIntent(category, errorClass, errorCode,
+ packageName, sessionKey, profileState, underlyingNetwork, nc, lp);
+ return sendEventToVpnManagerApp(intent, packageName);
+ }
+
+ private boolean sendEventToVpnManagerApp(@NonNull final Intent intent,
+ @NonNull final String packageName) {
// Allow VpnManager app to temporarily run background services to handle this error.
// If an app requires anything beyond this grace period, they MUST either declare
// themselves as a foreground service, or schedule a job/workitem.
@@ -781,7 +800,7 @@
}
}
- private boolean isVpnApp(String packageName) {
+ private static boolean isVpnApp(String packageName) {
return packageName != null && !VpnConfig.LEGACY_VPN.equals(packageName);
}
@@ -1177,23 +1196,7 @@
mContext.unbindService(mConnection);
cleanupVpnStateLocked();
} else if (mVpnRunner != null) {
- if (!VpnConfig.LEGACY_VPN.equals(mPackage)) {
- mAppOpsManager.finishOp(
- AppOpsManager.OPSTR_ESTABLISH_VPN_MANAGER, mOwnerUID, mPackage, null);
- // The underlying network, NetworkCapabilities and LinkProperties are not
- // necessary to send to VPN app since the purpose of this event is to notify
- // VPN app that VPN is deactivated by the user.
- // TODO(b/230548427): Remove SDK check once VPN related stuff are decoupled from
- // ConnectivityServiceTest.
- if (SdkLevel.isAtLeastT()) {
- sendEventToVpnManagerApp(VpnManager.CATEGORY_EVENT_DEACTIVATED_BY_USER,
- -1 /* errorClass */, -1 /* errorCode*/, mPackage,
- getSessionKeyLocked(), makeVpnProfileStateLocked(),
- null /* underlyingNetwork */, null /* nc */, null /* lp */);
- }
- }
- // cleanupVpnStateLocked() is called from mVpnRunner.exit()
- mVpnRunner.exit();
+ stopVpnRunnerAndNotifyAppLocked(mPackage);
}
try {
@@ -2595,7 +2598,7 @@
}
@Nullable
- protected synchronized NetworkCapabilities getRedactedNetworkCapabilitiesOfUnderlyingNetwork(
+ private synchronized NetworkCapabilities getRedactedNetworkCapabilities(
NetworkCapabilities nc) {
if (nc == null) return null;
return mConnectivityManager.getRedactedNetworkCapabilitiesForPackage(
@@ -2603,8 +2606,7 @@
}
@Nullable
- protected synchronized LinkProperties getRedactedLinkPropertiesOfUnderlyingNetwork(
- LinkProperties lp) {
+ private synchronized LinkProperties getRedactedLinkProperties(LinkProperties lp) {
if (lp == null) return null;
return mConnectivityManager.getRedactedLinkPropertiesForPackage(lp, mOwnerUID, mPackage);
}
@@ -2718,11 +2720,13 @@
private boolean mIsRunning = true;
/**
- * The token used by the primary/current/active IKE session.
+ * The token that identifies the most recently created IKE session.
*
- * <p>This token MUST be updated when the VPN switches to use a new IKE session.
+ * <p>This token is monotonically increasing and will never be reset in the lifetime of this
+ * Ikev2VpnRunner, but it does get reset across runs. It also MUST be accessed on the
+ * executor thread and updated when a new IKE session is created.
*/
- private int mCurrentToken = -1;
+ private int mCurrentToken = STARTING_TOKEN;
@Nullable private IpSecTunnelInterface mTunnelIface;
@Nullable private Network mActiveNetwork;
@@ -2887,6 +2891,9 @@
final LinkProperties lp;
synchronized (Vpn.this) {
+ // Ignore stale runner.
+ if (mVpnRunner != this) return;
+
mInterface = interfaceName;
mConfig.mtu = maxMtu;
mConfig.interfaze = mInterface;
@@ -2988,6 +2995,9 @@
try {
synchronized (Vpn.this) {
+ // Ignore stale runner.
+ if (mVpnRunner != this) return;
+
mConfig.underlyingNetworks = new Network[] {network};
mNetworkCapabilities =
new NetworkCapabilities.Builder(mNetworkCapabilities)
@@ -3077,7 +3087,12 @@
// Clear mInterface to prevent Ikev2VpnRunner being cleared when
// interfaceRemoved() is called.
- mInterface = null;
+ synchronized (Vpn.this) {
+ // Ignore stale runner.
+ if (mVpnRunner != this) return;
+
+ mInterface = null;
+ }
// Without MOBIKE, we have no way to seamlessly migrate. Close on old
// (non-default) network, and start the new one.
resetIkeState();
@@ -3214,7 +3229,7 @@
mExecutor.schedule(
() -> {
if (isActiveToken(token)) {
- handleSessionLost(null, network);
+ handleSessionLost(null /* exception */, network);
} else {
Log.d(
TAG,
@@ -3231,7 +3246,7 @@
TimeUnit.MILLISECONDS);
} else {
Log.d(TAG, "Call handleSessionLost for losing network " + network);
- handleSessionLost(null, network);
+ handleSessionLost(null /* exception */, network);
}
}
@@ -3262,6 +3277,9 @@
/** Marks the state as FAILED, and disconnects. */
private void markFailedAndDisconnect(Exception exception) {
synchronized (Vpn.this) {
+ // Ignore stale runner.
+ if (mVpnRunner != this) return;
+
updateState(DetailedState.FAILED, exception.getMessage());
}
@@ -3299,116 +3317,71 @@
// already terminated due to other failures.
cancelHandleNetworkLostTimeout();
- synchronized (Vpn.this) {
- if (exception instanceof IkeProtocolException) {
- final IkeProtocolException ikeException = (IkeProtocolException) exception;
+ String category = null;
+ int errorClass = -1;
+ int errorCode = -1;
+ if (exception instanceof IllegalArgumentException) {
+ // Failed to build IKE/ChildSessionParams; fatal profile configuration error
+ markFailedAndDisconnect(exception);
+ return;
+ }
- switch (ikeException.getErrorType()) {
- case IkeProtocolException.ERROR_TYPE_NO_PROPOSAL_CHOSEN: // Fallthrough
- case IkeProtocolException.ERROR_TYPE_INVALID_KE_PAYLOAD: // Fallthrough
- case IkeProtocolException.ERROR_TYPE_AUTHENTICATION_FAILED: // Fallthrough
- case IkeProtocolException.ERROR_TYPE_SINGLE_PAIR_REQUIRED: // Fallthrough
- case IkeProtocolException.ERROR_TYPE_FAILED_CP_REQUIRED: // Fallthrough
- case IkeProtocolException.ERROR_TYPE_TS_UNACCEPTABLE:
- // All the above failures are configuration errors, and are terminal
- // TODO(b/230548427): Remove SDK check once VPN related stuff are
- // decoupled from ConnectivityServiceTest.
- if (SdkLevel.isAtLeastT() && isVpnApp(mPackage)) {
- sendEventToVpnManagerApp(VpnManager.CATEGORY_EVENT_IKE_ERROR,
- VpnManager.ERROR_CLASS_NOT_RECOVERABLE,
- ikeException.getErrorType(),
- getPackage(), mSessionKey, makeVpnProfileStateLocked(),
- network,
- getRedactedNetworkCapabilitiesOfUnderlyingNetwork(
- mUnderlyingNetworkCapabilities),
- getRedactedLinkPropertiesOfUnderlyingNetwork(
- mUnderlyingLinkProperties));
- }
- markFailedAndDisconnect(exception);
- return;
- // All other cases possibly recoverable.
- default:
- // All the above failures are configuration errors, and are terminal
- // TODO(b/230548427): Remove SDK check once VPN related stuff are
- // decoupled from ConnectivityServiceTest.
- if (SdkLevel.isAtLeastT() && isVpnApp(mPackage)) {
- sendEventToVpnManagerApp(VpnManager.CATEGORY_EVENT_IKE_ERROR,
- VpnManager.ERROR_CLASS_RECOVERABLE,
- ikeException.getErrorType(),
- getPackage(), mSessionKey, makeVpnProfileStateLocked(),
- network,
- getRedactedNetworkCapabilitiesOfUnderlyingNetwork(
- mUnderlyingNetworkCapabilities),
- getRedactedLinkPropertiesOfUnderlyingNetwork(
- mUnderlyingLinkProperties));
- }
- }
- } else if (exception instanceof IllegalArgumentException) {
- // Failed to build IKE/ChildSessionParams; fatal profile configuration error
- markFailedAndDisconnect(exception);
- return;
- } else if (exception instanceof IkeNetworkLostException) {
- // TODO(b/230548427): Remove SDK check once VPN related stuff are
- // decoupled from ConnectivityServiceTest.
- if (SdkLevel.isAtLeastT() && isVpnApp(mPackage)) {
- sendEventToVpnManagerApp(VpnManager.CATEGORY_EVENT_NETWORK_ERROR,
- VpnManager.ERROR_CLASS_RECOVERABLE,
- VpnManager.ERROR_CODE_NETWORK_LOST,
- getPackage(), mSessionKey, makeVpnProfileStateLocked(),
- network,
- getRedactedNetworkCapabilitiesOfUnderlyingNetwork(
- mUnderlyingNetworkCapabilities),
- getRedactedLinkPropertiesOfUnderlyingNetwork(
- mUnderlyingLinkProperties));
- }
- } else if (exception instanceof IkeNonProtocolException) {
- if (exception.getCause() instanceof UnknownHostException) {
- // TODO(b/230548427): Remove SDK check once VPN related stuff are
- // decoupled from ConnectivityServiceTest.
- if (SdkLevel.isAtLeastT() && isVpnApp(mPackage)) {
- sendEventToVpnManagerApp(VpnManager.CATEGORY_EVENT_NETWORK_ERROR,
- VpnManager.ERROR_CLASS_RECOVERABLE,
- VpnManager.ERROR_CODE_NETWORK_UNKNOWN_HOST,
- getPackage(), mSessionKey, makeVpnProfileStateLocked(),
- network,
- getRedactedNetworkCapabilitiesOfUnderlyingNetwork(
- mUnderlyingNetworkCapabilities),
- getRedactedLinkPropertiesOfUnderlyingNetwork(
- mUnderlyingLinkProperties));
- }
- } else if (exception.getCause() instanceof IkeTimeoutException) {
- // TODO(b/230548427): Remove SDK check once VPN related stuff are
- // decoupled from ConnectivityServiceTest.
- if (SdkLevel.isAtLeastT() && isVpnApp(mPackage)) {
- sendEventToVpnManagerApp(VpnManager.CATEGORY_EVENT_NETWORK_ERROR,
- VpnManager.ERROR_CLASS_RECOVERABLE,
- VpnManager.ERROR_CODE_NETWORK_PROTOCOL_TIMEOUT,
- getPackage(), mSessionKey, makeVpnProfileStateLocked(),
- network,
- getRedactedNetworkCapabilitiesOfUnderlyingNetwork(
- mUnderlyingNetworkCapabilities),
- getRedactedLinkPropertiesOfUnderlyingNetwork(
- mUnderlyingLinkProperties));
- }
- } else if (exception.getCause() instanceof IOException) {
- // TODO(b/230548427): Remove SDK check once VPN related stuff are
- // decoupled from ConnectivityServiceTest.
- if (SdkLevel.isAtLeastT() && isVpnApp(mPackage)) {
- sendEventToVpnManagerApp(VpnManager.CATEGORY_EVENT_NETWORK_ERROR,
- VpnManager.ERROR_CLASS_RECOVERABLE,
- VpnManager.ERROR_CODE_NETWORK_IO,
- getPackage(), mSessionKey, makeVpnProfileStateLocked(),
- network,
- getRedactedNetworkCapabilitiesOfUnderlyingNetwork(
- mUnderlyingNetworkCapabilities),
- getRedactedLinkPropertiesOfUnderlyingNetwork(
- mUnderlyingLinkProperties));
- }
- }
- } else if (exception != null) {
- Log.wtf(TAG, "onSessionLost: exception = " + exception);
+ if (exception instanceof IkeProtocolException) {
+ final IkeProtocolException ikeException = (IkeProtocolException) exception;
+ category = VpnManager.CATEGORY_EVENT_IKE_ERROR;
+ errorCode = ikeException.getErrorType();
+
+ switch (ikeException.getErrorType()) {
+ case IkeProtocolException.ERROR_TYPE_NO_PROPOSAL_CHOSEN: // Fallthrough
+ case IkeProtocolException.ERROR_TYPE_INVALID_KE_PAYLOAD: // Fallthrough
+ case IkeProtocolException.ERROR_TYPE_AUTHENTICATION_FAILED: // Fallthrough
+ case IkeProtocolException.ERROR_TYPE_SINGLE_PAIR_REQUIRED: // Fallthrough
+ case IkeProtocolException.ERROR_TYPE_FAILED_CP_REQUIRED: // Fallthrough
+ case IkeProtocolException.ERROR_TYPE_TS_UNACCEPTABLE:
+ // All the above failures are configuration errors, and are terminal
+ errorClass = VpnManager.ERROR_CLASS_NOT_RECOVERABLE;
+ break;
+ // All other cases possibly recoverable.
+ default:
+ errorClass = VpnManager.ERROR_CLASS_RECOVERABLE;
}
+ } else if (exception instanceof IkeNetworkLostException) {
+ category = VpnManager.CATEGORY_EVENT_NETWORK_ERROR;
+ errorClass = VpnManager.ERROR_CLASS_RECOVERABLE;
+ errorCode = VpnManager.ERROR_CODE_NETWORK_LOST;
+ } else if (exception instanceof IkeNonProtocolException) {
+ category = VpnManager.CATEGORY_EVENT_NETWORK_ERROR;
+ errorClass = VpnManager.ERROR_CLASS_RECOVERABLE;
+ if (exception.getCause() instanceof UnknownHostException) {
+ errorCode = VpnManager.ERROR_CODE_NETWORK_UNKNOWN_HOST;
+ } else if (exception.getCause() instanceof IkeTimeoutException) {
+ errorCode = VpnManager.ERROR_CODE_NETWORK_PROTOCOL_TIMEOUT;
+ } else if (exception.getCause() instanceof IOException) {
+ errorCode = VpnManager.ERROR_CODE_NETWORK_IO;
+ }
+ } else if (exception != null) {
+ Log.wtf(TAG, "onSessionLost: exception = " + exception);
+ }
+ synchronized (Vpn.this) {
+ // Ignore stale runner.
+ if (mVpnRunner != this) return;
+
+ // TODO(b/230548427): Remove SDK check once VPN related stuff are
+ // decoupled from ConnectivityServiceTest.
+ if (SdkLevel.isAtLeastT() && category != null && isVpnApp(mPackage)) {
+ sendEventToVpnManagerApp(category, errorClass, errorCode,
+ getPackage(), mSessionKey, makeVpnProfileStateLocked(),
+ mActiveNetwork,
+ getRedactedNetworkCapabilities(mUnderlyingNetworkCapabilities),
+ getRedactedLinkProperties(mUnderlyingLinkProperties));
+ }
+ }
+
+ if (errorClass == VpnManager.ERROR_CLASS_NOT_RECOVERABLE) {
+ markFailedAndDisconnect(exception);
+ return;
+ } else {
scheduleRetryNewIkeSession();
}
@@ -3420,6 +3393,9 @@
Log.d(TAG, "Resetting state for token: " + mCurrentToken);
synchronized (Vpn.this) {
+ // Ignore stale runner.
+ if (mVpnRunner != this) return;
+
// Since this method handles non-fatal errors only, set mInterface to null to
// prevent the NetworkManagementEventObserver from killing this VPN based on the
// interface going down (which we expect).
@@ -4074,6 +4050,29 @@
}
}
+ @GuardedBy("this")
+ private void stopVpnRunnerAndNotifyAppLocked(@NonNull String packageName) {
+ // Build intent first because the sessionKey will be reset after performing
+ // VpnRunner.exit(). Also, cache mOwnerUID even if ownerUID will not be changed in
+ // VpnRunner.exit() to prevent design being changed in the future.
+ // TODO(b/230548427): Remove SDK check once VPN related stuff are decoupled from
+ // ConnectivityServiceTest.
+ final int ownerUid = mOwnerUID;
+ Intent intent = null;
+ if (SdkLevel.isAtLeastT() && isVpnApp(packageName)) {
+ intent = buildVpnManagerEventIntent(
+ VpnManager.CATEGORY_EVENT_DEACTIVATED_BY_USER,
+ -1 /* errorClass */, -1 /* errorCode*/, packageName,
+ getSessionKeyLocked(), makeVpnProfileStateLocked(),
+ null /* underlyingNetwork */, null /* nc */, null /* lp */);
+ }
+ // cleanupVpnStateLocked() is called from mVpnRunner.exit()
+ mVpnRunner.exit();
+ if (intent != null && isVpnApp(packageName)) {
+ notifyVpnManagerVpnStopped(packageName, ownerUid, intent);
+ }
+ }
+
/**
* Stops an already running VPN Profile for the given package.
*
@@ -4090,7 +4089,21 @@
// To stop the VPN profile, the caller must be the current prepared package and must be
// running an Ikev2VpnProfile.
if (isCurrentIkev2VpnLocked(packageName)) {
- prepareInternal(VpnConfig.LEGACY_VPN);
+ stopVpnRunnerAndNotifyAppLocked(packageName);
+ }
+ }
+
+ private synchronized void notifyVpnManagerVpnStopped(String packageName, int ownerUID,
+ Intent intent) {
+ mAppOpsManager.finishOp(
+ AppOpsManager.OPSTR_ESTABLISH_VPN_MANAGER, ownerUID, packageName, null);
+ // The underlying network, NetworkCapabilities and LinkProperties are not
+ // necessary to send to VPN app since the purpose of this event is to notify
+ // VPN app that VPN is deactivated by the user.
+ // TODO(b/230548427): Remove SDK check once VPN related stuff are decoupled from
+ // ConnectivityServiceTest.
+ if (SdkLevel.isAtLeastT()) {
+ sendEventToVpnManagerApp(intent, packageName);
}
}
diff --git a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
index c835d2f..25d0752 100644
--- a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
+++ b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
@@ -116,10 +116,8 @@
luxLevels = getLuxLevels(resources.getIntArray(
com.android.internal.R.array.config_autoBrightnessLevelsIdle));
} else {
- brightnessLevelsNits = getFloatArray(resources.obtainTypedArray(
- com.android.internal.R.array.config_autoBrightnessDisplayValuesNits));
- luxLevels = getLuxLevels(resources.getIntArray(
- com.android.internal.R.array.config_autoBrightnessLevels));
+ brightnessLevelsNits = displayDeviceConfig.getAutoBrightnessBrighteningLevelsNits();
+ luxLevels = displayDeviceConfig.getAutoBrightnessBrighteningLevelsLux();
}
// Display independent, mode independent values
diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
index 4f3fd64..12b2f47 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
@@ -20,6 +20,7 @@
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.content.res.TypedArray;
import android.hardware.display.DisplayManagerInternal;
import android.hardware.display.DisplayManagerInternal.RefreshRateLimitation;
import android.os.Environment;
@@ -149,12 +150,22 @@
* </quirks>
*
* <autoBrightness>
- * <brighteningLightDebounceMillis>
+ * <brighteningLightDebounceMillis>
* 2000
- * </brighteningLightDebounceMillis>
+ * </brighteningLightDebounceMillis>
* <darkeningLightDebounceMillis>
* 1000
* </darkeningLightDebounceMillis>
+ * <displayBrightnessMapping>
+ * <displayBrightnessPoint>
+ * <lux>50</lux>
+ * <nits>45.32</nits>
+ * </displayBrightnessPoint>
+ * <displayBrightnessPoint>
+ * <lux>80</lux>
+ * <nits>75.43</nits>
+ * </displayBrightnessPoint>
+ * </displayBrightnessMapping>
* </autoBrightness>
*
* <screenBrightnessRampFastDecrease>0.01</screenBrightnessRampFastDecrease>
@@ -268,6 +279,34 @@
// for the corresponding values above
private float[] mBrightness;
+
+ /**
+ * Array of desired screen brightness in nits corresponding to the lux values
+ * in the mBrightnessLevelsLux array. The display brightness is defined as the
+ * measured brightness of an all-white image. The brightness values must be non-negative and
+ * non-decreasing. This must be overridden in platform specific overlays
+ */
+ private float[] mBrightnessLevelsNits;
+
+ /**
+ * Array of light sensor lux values to define our levels for auto backlight
+ * brightness support.
+
+ * The N + 1 entries of this array define N control points defined in mBrightnessLevelsNits,
+ * with first value always being 0 lux
+
+ * The control points must be strictly increasing. Each control point
+ * corresponds to an entry in the brightness backlight values arrays.
+ * For example, if lux == level[1] (second element of the levels array)
+ * then the brightness will be determined by value[0] (first element
+ * of the brightness values array).
+ *
+ * Spline interpolation is used to determine the auto-brightness
+ * backlight values for lux levels between these control points.
+ *
+ */
+ private float[] mBrightnessLevelsLux;
+
private float mBacklightMinimum = Float.NaN;
private float mBacklightMaximum = Float.NaN;
private float mBrightnessDefault = Float.NaN;
@@ -661,6 +700,20 @@
return mAutoBrightnessBrighteningLightDebounce;
}
+ /**
+ * @return Auto brightness brightening ambient lux levels
+ */
+ public float[] getAutoBrightnessBrighteningLevelsLux() {
+ return mBrightnessLevelsLux;
+ }
+
+ /**
+ * @return Auto brightness brightening nits levels
+ */
+ public float[] getAutoBrightnessBrighteningLevelsNits() {
+ return mBrightnessLevelsNits;
+ }
+
@Override
public String toString() {
return "DisplayDeviceConfig{"
@@ -703,6 +756,8 @@
+ mAutoBrightnessBrighteningLightDebounce
+ ", mAutoBrightnessDarkeningLightDebounce= "
+ mAutoBrightnessDarkeningLightDebounce
+ + ", mBrightnessLevelsLux= " + Arrays.toString(mBrightnessLevelsLux)
+ + ", mBrightnessLevelsNits= " + Arrays.toString(mBrightnessLevelsNits)
+ "}";
}
@@ -779,6 +834,7 @@
loadBrightnessRampsFromConfigXml();
loadAmbientLightSensorFromConfigXml();
setProxSensorUnspecified();
+ loadAutoBrightnessConfigsFromConfigXml();
mLoadedFrom = "<config.xml>";
}
@@ -991,6 +1047,7 @@
private void loadAutoBrightnessConfigValues(DisplayConfiguration config) {
loadAutoBrightnessBrighteningLightDebounce(config.getAutoBrightness());
loadAutoBrightnessDarkeningLightDebounce(config.getAutoBrightness());
+ loadAutoBrightnessDisplayBrightnessMapping(config.getAutoBrightness());
}
/**
@@ -1023,6 +1080,35 @@
}
}
+ /**
+ * Loads the auto-brightness display brightness mappings. Internally, this takes care of
+ * loading the value from the display config, and if not present, falls back to config.xml.
+ */
+ private void loadAutoBrightnessDisplayBrightnessMapping(AutoBrightness autoBrightnessConfig) {
+ if (autoBrightnessConfig == null
+ || autoBrightnessConfig.getDisplayBrightnessMapping() == null) {
+ mBrightnessLevelsNits = getFloatArray(mContext.getResources()
+ .obtainTypedArray(com.android.internal.R.array
+ .config_autoBrightnessDisplayValuesNits), PowerManager
+ .BRIGHTNESS_OFF_FLOAT);
+ mBrightnessLevelsLux = getLuxLevels(mContext.getResources()
+ .getIntArray(com.android.internal.R.array
+ .config_autoBrightnessLevels));
+ } else {
+ final int size = autoBrightnessConfig.getDisplayBrightnessMapping()
+ .getDisplayBrightnessPoint().size();
+ mBrightnessLevelsNits = new float[size];
+ // The first control point is implicit and always at 0 lux.
+ mBrightnessLevelsLux = new float[size + 1];
+ for (int i = 0; i < size; i++) {
+ mBrightnessLevelsNits[i] = autoBrightnessConfig.getDisplayBrightnessMapping()
+ .getDisplayBrightnessPoint().get(i).getNits().floatValue();
+ mBrightnessLevelsLux[i + 1] = autoBrightnessConfig.getDisplayBrightnessMapping()
+ .getDisplayBrightnessPoint().get(i).getLux().floatValue();
+ }
+ }
+ }
+
private void loadBrightnessMapFromConfigXml() {
// Use the config.xml mapping
final Resources res = mContext.getResources();
@@ -1248,6 +1334,10 @@
com.android.internal.R.string.config_displayLightSensorType);
}
+ private void loadAutoBrightnessConfigsFromConfigXml() {
+ loadAutoBrightnessDisplayBrightnessMapping(null /*AutoBrightnessConfig*/);
+ }
+
private void loadAmbientLightSensorFromDdc(DisplayConfiguration config) {
final SensorDetails sensorDetails = config.getLightSensor();
if (sensorDetails != null) {
@@ -1390,6 +1480,31 @@
}
}
+ /**
+ * Extracts a float array from the specified {@link TypedArray}.
+ *
+ * @param array The array to convert.
+ * @return the given array as a float array.
+ */
+ public static float[] getFloatArray(TypedArray array, float defaultValue) {
+ final int n = array.length();
+ float[] vals = new float[n];
+ for (int i = 0; i < n; i++) {
+ vals[i] = array.getFloat(i, defaultValue);
+ }
+ array.recycle();
+ return vals;
+ }
+
+ private static float[] getLuxLevels(int[] lux) {
+ // The first control point is implicit and always at 0 lux.
+ float[] levels = new float[lux.length + 1];
+ for (int i = 0; i < lux.length; i++) {
+ levels[i + 1] = (float) lux[i];
+ }
+ return levels;
+ }
+
static class SensorData {
public String type;
public String name;
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index d44a3b7..4e0cc61 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -4953,7 +4953,16 @@
}
enforcePolicyAccess(Binder.getCallingUid(), "addAutomaticZenRule");
- return mZenModeHelper.addAutomaticZenRule(pkg, automaticZenRule,
+ // If the caller is system, take the package name from the rule's owner rather than
+ // from the caller's package.
+ String rulePkg = pkg;
+ if (isCallingUidSystem()) {
+ if (automaticZenRule.getOwner() != null) {
+ rulePkg = automaticZenRule.getOwner().getPackageName();
+ }
+ }
+
+ return mZenModeHelper.addAutomaticZenRule(rulePkg, automaticZenRule,
"addAutomaticZenRule");
}
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 477b8da..d8aa469 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -106,7 +106,7 @@
private static final String NON_BLOCKABLE_CHANNEL_DELIM = ":";
@VisibleForTesting
- static final int NOTIFICATION_CHANNEL_COUNT_LIMIT = 50000;
+ static final int NOTIFICATION_CHANNEL_COUNT_LIMIT = 5000;
@VisibleForTesting
static final int NOTIFICATION_CHANNEL_GROUP_COUNT_LIMIT = 50000;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 0c4273f..e9d5426 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -5798,6 +5798,11 @@
final Computer snapshot = snapshotComputer();
enforceOwnerRights(snapshot, packageName, Binder.getCallingUid());
mimeTypes = CollectionUtils.emptyIfNull(mimeTypes);
+ for (String mimeType : mimeTypes) {
+ if (mimeType.length() > 255) {
+ throw new IllegalArgumentException("MIME type length exceeds 255 characters");
+ }
+ }
final PackageStateInternal packageState = snapshot.getPackageStateInternal(packageName);
Set<String> existingMimeTypes = packageState.getMimeGroups().get(mimeGroup);
if (existingMimeTypes == null) {
@@ -5808,6 +5813,10 @@
&& existingMimeTypes.containsAll(mimeTypes)) {
return;
}
+ if (mimeTypes.size() > 500) {
+ throw new IllegalStateException("Max limit on MIME types for MIME group "
+ + mimeGroup + " exceeded for package " + packageName);
+ }
ArraySet<String> mimeTypesSet = new ArraySet<>(mimeTypes);
commitPackageStateMutation(null, packageName, packageStateWrite -> {
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index f2bcf5e..0b20683 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -280,6 +280,7 @@
private final Object mLock = new Object();
private final Object mNonPersistentUsersLock = new Object();
+ private final Object mWtfLock = new Object();
private static List<ResolveInfo> EMPTY_RESOLVE_INFO = new ArrayList<>(0);
@@ -444,10 +445,10 @@
@interface ShortcutOperation {
}
- @GuardedBy("mLock")
+ @GuardedBy("mWtfLock")
private int mWtfCount = 0;
- @GuardedBy("mLock")
+ @GuardedBy("mWtfLock")
private Exception mLastWtfStacktrace;
@GuardedBy("mLock")
@@ -4727,13 +4728,15 @@
mStatLogger.dump(pw, " ");
- pw.println();
- pw.print(" #Failures: ");
- pw.println(mWtfCount);
+ synchronized (mWtfLock) {
+ pw.println();
+ pw.print(" #Failures: ");
+ pw.println(mWtfCount);
- if (mLastWtfStacktrace != null) {
- pw.print(" Last failure stack trace: ");
- pw.println(Log.getStackTraceString(mLastWtfStacktrace));
+ if (mLastWtfStacktrace != null) {
+ pw.print(" Last failure stack trace: ");
+ pw.println(Log.getStackTraceString(mLastWtfStacktrace));
+ }
}
pw.println();
@@ -5148,7 +5151,7 @@
if (e == null) {
e = new RuntimeException("Stacktrace");
}
- synchronized (mLock) {
+ synchronized (mWtfLock) {
mWtfCount++;
mLastWtfStacktrace = new Exception("Last failure was logged here:");
}
diff --git a/services/core/java/com/android/server/pm/SuspendPackageHelper.java b/services/core/java/com/android/server/pm/SuspendPackageHelper.java
index 908b12e..7ad4d22 100644
--- a/services/core/java/com/android/server/pm/SuspendPackageHelper.java
+++ b/services/core/java/com/android/server/pm/SuspendPackageHelper.java
@@ -160,9 +160,11 @@
}
}
- // If size one, the package will be unsuspended from this call
- boolean packageUnsuspended =
- !suspended && CollectionUtils.size(suspendParamsMap) <= 1;
+ // If only the callingPackage is suspending this package,
+ // it will be unsuspended when this change is committed
+ boolean packageUnsuspended = !suspended
+ && CollectionUtils.size(suspendParamsMap) == 1
+ && suspendParamsMap.containsKey(callingPackage);
if (suspended || packageUnsuspended) {
changedPackagesList.add(packageName);
changedUids.add(UserHandle.getUid(userId, packageState.getAppId()));
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index b3ba20b..37538db 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -1112,15 +1112,21 @@
resolvedAttributionSource, skipCurrentFinish);
}
- if (next == null || next.getNext() == null) {
- return;
- }
-
RegisteredAttribution registered =
sRunningAttributionSources.remove(current.getToken());
if (registered != null) {
registered.unregister();
}
+
+ if (next == null || next.getNext() == null) {
+ if (next != null) {
+ registered = sRunningAttributionSources.remove(next.getToken());
+ if (registered != null) {
+ registered.unregister();
+ }
+ }
+ return;
+ }
current = next;
}
}
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
index 1381614..014d580 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
@@ -2665,7 +2665,6 @@
final Permission bp = mRegistry.getPermission(permName);
final boolean appSupportsRuntimePermissions =
pkg.getTargetSdkVersion() >= Build.VERSION_CODES.M;
- String legacyActivityRecognitionPermission = null;
if (DEBUG_INSTALL && bp != null) {
Log.i(TAG, "Package " + friendlyName
@@ -2689,47 +2688,12 @@
// Cache newImplicitPermissions before modifing permissionsState as for the
// shared uids the original and new state are the same object
if (!origState.hasPermissionState(permName)
- && (pkg.getImplicitPermissions().contains(permName)
- || (permName.equals(Manifest.permission.ACTIVITY_RECOGNITION)))) {
- if (pkg.getImplicitPermissions().contains(permName)) {
+ && (pkg.getImplicitPermissions().contains(permName))) {
// If permName is an implicit permission, try to auto-grant
newImplicitPermissions.add(permName);
-
if (DEBUG_PERMISSIONS) {
Slog.i(TAG, permName + " is newly added for " + friendlyName);
}
- } else {
- // Special case for Activity Recognition permission. Even if AR
- // permission is not an implicit permission we want to add it to the
- // list (try to auto-grant it) if the app was installed on a device
- // before AR permission was split, regardless of if the app now requests
- // the new AR permission or has updated its target SDK and AR is no
- // longer implicit to it. This is a compatibility workaround for apps
- // when AR permission was split in Q.
- // TODO(zhanghai): This calls into SystemConfig, which generally
- // shouldn't cause deadlock, but maybe we should keep a cache of the
- // split permission list and just eliminate the possibility.
- final List<PermissionManager.SplitPermissionInfo> permissionList =
- getSplitPermissionInfos();
- int numSplitPerms = permissionList.size();
- for (int splitPermNum = 0; splitPermNum < numSplitPerms;
- splitPermNum++) {
- PermissionManager.SplitPermissionInfo sp = permissionList.get(
- splitPermNum);
- String splitPermName = sp.getSplitPermission();
- if (sp.getNewPermissions().contains(permName)
- && origState.isPermissionGranted(splitPermName)) {
- legacyActivityRecognitionPermission = splitPermName;
- newImplicitPermissions.add(permName);
-
- if (DEBUG_PERMISSIONS) {
- Slog.i(TAG, permName + " is newly added for "
- + friendlyName);
- }
- break;
- }
- }
- }
}
// TODO(b/140256621): The package instant app method has been removed
@@ -2863,8 +2827,7 @@
// Hard restricted permissions cannot be held.
} else if (!permissionPolicyInitialized
|| (!hardRestricted || restrictionExempt)) {
- if ((origPermState != null && origPermState.isGranted())
- || legacyActivityRecognitionPermission != null) {
+ if ((origPermState != null && origPermState.isGranted())) {
if (!uidState.grantPermission(bp)) {
wasChanged = true;
}
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageImpl.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageImpl.java
index 67d9aec..6c8e9f0 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageImpl.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageImpl.java
@@ -1856,6 +1856,9 @@
for (int i = component.getIntents().size() - 1; i >= 0; i--) {
IntentFilter filter = component.getIntents().get(i).getIntentFilter();
for (int groupIndex = filter.countMimeGroups() - 1; groupIndex >= 0; groupIndex--) {
+ if (mimeGroups != null && mimeGroups.size() > 500) {
+ throw new IllegalStateException("Max limit on number of MIME Groups reached");
+ }
mimeGroups = ArrayUtils.add(mimeGroups, filter.getMimeGroup(groupIndex));
}
}
diff --git a/services/core/java/com/android/server/powerstats/PowerStatsDataStorage.java b/services/core/java/com/android/server/powerstats/PowerStatsDataStorage.java
index 06253a0..8b30995 100644
--- a/services/core/java/com/android/server/powerstats/PowerStatsDataStorage.java
+++ b/services/core/java/com/android/server/powerstats/PowerStatsDataStorage.java
@@ -220,18 +220,17 @@
public void write(byte[] data) {
if (data != null && data.length > 0) {
mLock.lock();
-
- long currentTimeMillis = System.currentTimeMillis();
try {
+ long currentTimeMillis = System.currentTimeMillis();
DataElement dataElement = new DataElement(data);
mFileRotator.rewriteActive(new DataRewriter(dataElement.toByteArray()),
currentTimeMillis);
mFileRotator.maybeRotate(currentTimeMillis);
} catch (IOException e) {
Slog.e(TAG, "Failed to write to on-device storage: " + e);
+ } finally {
+ mLock.unlock();
}
-
- mLock.unlock();
}
}
@@ -240,21 +239,31 @@
* DataElement retrieved from on-device storage, callback is called.
*/
public void read(DataElementReadCallback callback) throws IOException {
- mFileRotator.readMatching(new DataReader(callback), Long.MIN_VALUE, Long.MAX_VALUE);
+ mLock.lock();
+ try {
+ mFileRotator.readMatching(new DataReader(callback), Long.MIN_VALUE, Long.MAX_VALUE);
+ } finally {
+ mLock.unlock();
+ }
}
/**
* Deletes all stored log data.
*/
public void deleteLogs() {
- File[] files = mDataStorageDir.listFiles();
- for (int i = 0; i < files.length; i++) {
- int versionDot = mDataStorageFilename.lastIndexOf('.');
- String beforeVersionDot = mDataStorageFilename.substring(0, versionDot);
- // Check that the stems before the version match.
- if (files[i].getName().startsWith(beforeVersionDot)) {
- files[i].delete();
+ mLock.lock();
+ try {
+ File[] files = mDataStorageDir.listFiles();
+ for (int i = 0; i < files.length; i++) {
+ int versionDot = mDataStorageFilename.lastIndexOf('.');
+ String beforeVersionDot = mDataStorageFilename.substring(0, versionDot);
+ // Check that the stems before the version match.
+ if (files[i].getName().startsWith(beforeVersionDot)) {
+ files[i].delete();
+ }
}
+ } finally {
+ mLock.unlock();
}
}
}
diff --git a/services/core/java/com/android/server/powerstats/PowerStatsLogger.java b/services/core/java/com/android/server/powerstats/PowerStatsLogger.java
index ca67597..39ead13 100644
--- a/services/core/java/com/android/server/powerstats/PowerStatsLogger.java
+++ b/services/core/java/com/android/server/powerstats/PowerStatsLogger.java
@@ -159,12 +159,12 @@
EnergyMeasurementUtils.packProtoMessage(energyMeasurement, pos);
if (DEBUG) EnergyMeasurementUtils.print(energyMeasurement);
} catch (IOException e) {
- Slog.e(TAG, "Failed to write energy meter data to incident report.");
+ Slog.e(TAG, "Failed to write energy meter data to incident report.", e);
}
}
});
} catch (IOException e) {
- Slog.e(TAG, "Failed to write energy meter info to incident report.");
+ Slog.e(TAG, "Failed to write energy meter info to incident report.", e);
}
pos.flush();
@@ -200,12 +200,12 @@
EnergyConsumerResultUtils.packProtoMessage(energyConsumerResult, pos, true);
if (DEBUG) EnergyConsumerResultUtils.print(energyConsumerResult);
} catch (IOException e) {
- Slog.e(TAG, "Failed to write energy model data to incident report.");
+ Slog.e(TAG, "Failed to write energy model data to incident report.", e);
}
}
});
} catch (IOException e) {
- Slog.e(TAG, "Failed to write energy model info to incident report.");
+ Slog.e(TAG, "Failed to write energy model info to incident report.", e);
}
pos.flush();
@@ -241,12 +241,12 @@
StateResidencyResultUtils.packProtoMessage(stateResidencyResult, pos);
if (DEBUG) StateResidencyResultUtils.print(stateResidencyResult);
} catch (IOException e) {
- Slog.e(TAG, "Failed to write residency data to incident report.");
+ Slog.e(TAG, "Failed to write residency data to incident report.", e);
}
}
});
} catch (IOException e) {
- Slog.e(TAG, "Failed to write residency data to incident report.");
+ Slog.e(TAG, "Failed to write residency data to incident report.", e);
}
pos.flush();
@@ -267,7 +267,7 @@
final FileInputStream fis = new FileInputStream(cachedFile.getPath());
fis.read(dataCached);
} catch (IOException e) {
- Slog.e(TAG, "Failed to read cached data from file");
+ Slog.e(TAG, "Failed to read cached data from file", e);
}
// If the cached and current data are different, delete the data store.
@@ -291,7 +291,7 @@
fos.write(data);
atomicCachedFile.finishWrite(fos);
} catch (IOException e) {
- Slog.e(TAG, "Failed to write current data to cached file");
+ Slog.e(TAG, "Failed to write current data to cached file", e);
}
}
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
index 53b8b53..690dd10 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
@@ -21,7 +21,6 @@
import android.hardware.fingerprint.IUdfpsHbmListener;
import android.os.Bundle;
import android.os.IBinder;
-import android.os.ParcelFileDescriptor;
import android.view.InsetsState.InternalInsetsType;
import android.view.InsetsVisibilities;
import android.view.WindowInsetsController.Appearance;
@@ -162,11 +161,6 @@
boolean requestWindowMagnificationConnection(boolean request);
/**
- * Handles a logging command from the WM shell command.
- */
- void handleWindowManagerLoggingCommand(String[] args, ParcelFileDescriptor outFd);
-
- /**
* @see com.android.internal.statusbar.IStatusBar#setNavigationBarLumaSamplingEnabled(int,
* boolean)
*/
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index bec3754..653b51a9 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -62,7 +62,6 @@
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
-import android.os.ParcelFileDescriptor;
import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteException;
@@ -664,15 +663,6 @@
}
@Override
- public void handleWindowManagerLoggingCommand(String[] args, ParcelFileDescriptor outFd) {
- if (mBar != null) {
- try {
- mBar.handleWindowManagerLoggingCommand(args, outFd);
- } catch (RemoteException ex) { }
- }
- }
-
- @Override
public void setNavigationBarLumaSamplingEnabled(int displayId, boolean enable) {
if (mBar != null) {
try {
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index 80ce70d..3707c8e 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -1211,7 +1211,7 @@
if (info.userId == userId
&& info.agent.isTrusted()
&& info.agent.shouldDisplayTrustGrantedMessage()
- && !TextUtils.isEmpty(info.agent.getMessage())) {
+ && info.agent.getMessage() != null) {
trustGrantedMessages.add(info.agent.getMessage().toString());
}
}
diff --git a/services/core/java/com/android/server/vibrator/Vibration.java b/services/core/java/com/android/server/vibrator/Vibration.java
index a375d0a..83caa0e 100644
--- a/services/core/java/com/android/server/vibrator/Vibration.java
+++ b/services/core/java/com/android/server/vibrator/Vibration.java
@@ -71,7 +71,8 @@
IGNORED_FOR_POWER(VibrationProto.IGNORED_FOR_POWER),
IGNORED_FOR_RINGER_MODE(VibrationProto.IGNORED_FOR_RINGER_MODE),
IGNORED_FOR_SETTINGS(VibrationProto.IGNORED_FOR_SETTINGS),
- IGNORED_SUPERSEDED(VibrationProto.IGNORED_SUPERSEDED);
+ IGNORED_SUPERSEDED(VibrationProto.IGNORED_SUPERSEDED),
+ IGNORED_FROM_VIRTUAL_DEVICE(VibrationProto.IGNORED_FROM_VIRTUAL_DEVICE);
private final int mProtoEnumValue;
@@ -87,6 +88,7 @@
public final VibrationAttributes attrs;
public final long id;
public final int uid;
+ public final int displayId;
public final String opPkg;
public final String reason;
public final IBinder token;
@@ -113,12 +115,13 @@
private final CountDownLatch mCompletionLatch = new CountDownLatch(1);
Vibration(IBinder token, int id, CombinedVibration effect,
- VibrationAttributes attrs, int uid, String opPkg, String reason) {
+ VibrationAttributes attrs, int uid, int displayId, String opPkg, String reason) {
this.token = token;
this.mEffect = effect;
this.id = id;
this.attrs = attrs;
this.uid = uid;
+ this.displayId = displayId;
this.opPkg = opPkg;
this.reason = reason;
mStatus = Vibration.Status.RUNNING;
@@ -236,7 +239,7 @@
/** Return {@link Vibration.DebugInfo} with read-only debug information about this vibration. */
public Vibration.DebugInfo getDebugInfo() {
return new Vibration.DebugInfo(mStatus, mStats, mEffect, mOriginalEffect, /* scale= */ 0,
- attrs, uid, opPkg, reason);
+ attrs, uid, displayId, opPkg, reason);
}
/** Return {@link VibrationStats.StatsInfo} with read-only metrics about this vibration. */
@@ -304,13 +307,14 @@
private final float mScale;
private final VibrationAttributes mAttrs;
private final int mUid;
+ private final int mDisplayId;
private final String mOpPkg;
private final String mReason;
private final Status mStatus;
DebugInfo(Status status, VibrationStats stats, @Nullable CombinedVibration effect,
@Nullable CombinedVibration originalEffect, float scale, VibrationAttributes attrs,
- int uid, String opPkg, String reason) {
+ int uid, int displayId, String opPkg, String reason) {
mCreateTime = stats.getCreateTimeDebug();
mStartTime = stats.getStartTimeDebug();
mEndTime = stats.getEndTimeDebug();
@@ -320,6 +324,7 @@
mScale = scale;
mAttrs = attrs;
mUid = uid;
+ mDisplayId = displayId;
mOpPkg = opPkg;
mReason = reason;
mStatus = status;
@@ -349,6 +354,8 @@
.append(mAttrs)
.append(", uid: ")
.append(mUid)
+ .append(", displayId: ")
+ .append(mDisplayId)
.append(", opPkg: ")
.append(mOpPkg)
.append(", reason: ")
diff --git a/services/core/java/com/android/server/vibrator/VibrationSettings.java b/services/core/java/com/android/server/vibrator/VibrationSettings.java
index 8e6a290..6012993 100644
--- a/services/core/java/com/android/server/vibrator/VibrationSettings.java
+++ b/services/core/java/com/android/server/vibrator/VibrationSettings.java
@@ -56,10 +56,12 @@
import android.util.SparseArray;
import android.util.SparseIntArray;
import android.util.proto.ProtoOutputStream;
+import android.view.Display;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.LocalServices;
+import com.android.server.companion.virtual.VirtualDeviceManagerInternal;
import java.util.ArrayList;
import java.util.Arrays;
@@ -157,6 +159,7 @@
final UidObserver mUidObserver;
@VisibleForTesting
final SettingsBroadcastReceiver mSettingChangeReceiver;
+ final VirtualDeviceListener mVirtualDeviceListener;
@GuardedBy("mLock")
private final List<OnVibratorSettingsChanged> mListeners = new ArrayList<>();
@@ -193,6 +196,7 @@
mSettingObserver = new SettingsContentObserver(handler);
mUidObserver = new UidObserver();
mSettingChangeReceiver = new SettingsBroadcastReceiver();
+ mVirtualDeviceListener = new VirtualDeviceListener();
mSystemUiPackage = LocalServices.getService(PackageManagerInternal.class)
.getSystemUiServiceComponent().getPackageName();
@@ -257,6 +261,13 @@
}
});
+ VirtualDeviceManagerInternal vdm = LocalServices.getService(
+ VirtualDeviceManagerInternal.class);
+ if (vdm != null) {
+ vdm.registerVirtualDisplayListener(mVirtualDeviceListener);
+ vdm.registerAppsOnVirtualDeviceListener(mVirtualDeviceListener);
+ }
+
registerSettingsChangeReceiver(USER_SWITCHED_INTENT_FILTER);
registerSettingsChangeReceiver(INTERNAL_RINGER_MODE_CHANGED_INTENT_FILTER);
@@ -364,13 +375,17 @@
* null otherwise.
*/
@Nullable
- public Vibration.Status shouldIgnoreVibration(int uid, VibrationAttributes attrs) {
+ public Vibration.Status shouldIgnoreVibration(int uid, int displayId,
+ VibrationAttributes attrs) {
final int usage = attrs.getUsage();
synchronized (mLock) {
if (!mUidObserver.isUidForeground(uid)
&& !BACKGROUND_PROCESS_USAGE_ALLOWLIST.contains(usage)) {
return Vibration.Status.IGNORED_BACKGROUND;
}
+ if (mVirtualDeviceListener.isAppOrDisplayOnAnyVirtualDevice(uid, displayId)) {
+ return Vibration.Status.IGNORED_FROM_VIRTUAL_DEVICE;
+ }
if (mBatterySaverMode && !BATTERY_SAVER_USAGE_ALLOWLIST.contains(usage)) {
return Vibration.Status.IGNORED_FOR_POWER;
@@ -741,4 +756,73 @@
public void onUidProcAdjChanged(int uid) {
}
}
+
+ /**
+ * Implementation of Virtual Device listeners for the changes of virtual displays and of apps
+ * running on any virtual device.
+ */
+ final class VirtualDeviceListener implements
+ VirtualDeviceManagerInternal.VirtualDisplayListener,
+ VirtualDeviceManagerInternal.AppsOnVirtualDeviceListener {
+ @GuardedBy("mLock")
+ private final Set<Integer> mVirtualDisplays = new HashSet<>();
+ @GuardedBy("mLock")
+ private final Set<Integer> mAppsOnVirtualDevice = new HashSet<>();
+
+
+ @Override
+ public void onVirtualDisplayCreated(int displayId) {
+ synchronized (mLock) {
+ mVirtualDisplays.add(displayId);
+ }
+ }
+
+ @Override
+ public void onVirtualDisplayRemoved(int displayId) {
+ synchronized (mLock) {
+ mVirtualDisplays.remove(displayId);
+ }
+ }
+
+
+ @Override
+ public void onAppsOnAnyVirtualDeviceChanged(Set<Integer> allRunningUids) {
+ synchronized (mLock) {
+ mAppsOnVirtualDevice.clear();
+ mAppsOnVirtualDevice.addAll(allRunningUids);
+ }
+ }
+
+ /**
+ * @param uid: uid of the calling app.
+ * @param displayId: the id of a Display.
+ * @return Returns true if:
+ * <ul>
+ * <li> the displayId is valid, and it's owned by a virtual device.</li>
+ * <li> the displayId is invalid, and the calling app (uid) is running on a virtual
+ * device.</li>
+ * </ul>
+ */
+ public boolean isAppOrDisplayOnAnyVirtualDevice(int uid, int displayId) {
+ if (displayId == Display.DEFAULT_DISPLAY) {
+ // The default display is the primary physical display on the phone.
+ return false;
+ }
+
+ synchronized (mLock) {
+ if (displayId == Display.INVALID_DISPLAY) {
+ // There is no Display object associated with the Context of calling
+ // {@link SystemVibratorManager}, checking the calling UID instead.
+ return mAppsOnVirtualDevice.contains(uid);
+ } else {
+ // Other valid display IDs representing valid logical displays will be
+ // checked
+ // against the active virtual displays set built with the registered
+ // {@link VirtualDisplayListener}.
+ return mVirtualDisplays.contains(displayId);
+ }
+ }
+ }
+
+ }
}
diff --git a/services/core/java/com/android/server/vibrator/VibratorManagerService.java b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
index 2f12a82..9727558 100644
--- a/services/core/java/com/android/server/vibrator/VibratorManagerService.java
+++ b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
@@ -58,6 +58,7 @@
import android.util.Slog;
import android.util.SparseArray;
import android.util.proto.ProtoOutputStream;
+import android.view.Display;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -378,9 +379,9 @@
}
@Override // Binder call
- public void vibrate(int uid, String opPkg, @NonNull CombinedVibration effect,
+ public void vibrate(int uid, int displayId, String opPkg, @NonNull CombinedVibration effect,
@Nullable VibrationAttributes attrs, String reason, IBinder token) {
- vibrateInternal(uid, opPkg, effect, attrs, reason, token);
+ vibrateInternal(uid, displayId, opPkg, effect, attrs, reason, token);
}
/**
@@ -389,8 +390,9 @@
*/
@Nullable
@VisibleForTesting
- Vibration vibrateInternal(int uid, String opPkg, @NonNull CombinedVibration effect,
- @Nullable VibrationAttributes attrs, String reason, IBinder token) {
+ Vibration vibrateInternal(int uid, int displayId, String opPkg,
+ @NonNull CombinedVibration effect, @Nullable VibrationAttributes attrs,
+ String reason, IBinder token) {
Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "vibrate, reason = " + reason);
try {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.VIBRATE, "vibrate");
@@ -406,7 +408,7 @@
attrs = fixupVibrationAttributes(attrs, effect);
// Create Vibration.Stats as close to the received request as possible, for tracking.
Vibration vib = new Vibration(token, mNextVibrationId.getAndIncrement(), effect, attrs,
- uid, opPkg, reason);
+ uid, displayId, opPkg, reason);
fillVibrationFallbacks(vib, effect);
if (attrs.isFlagSet(VibrationAttributes.FLAG_INVALIDATE_SETTINGS_CACHE)) {
@@ -424,7 +426,7 @@
Vibration.Status status = null;
// Check if user settings or DnD is set to ignore this vibration.
- status = shouldIgnoreVibrationLocked(vib.uid, vib.opPkg, vib.attrs);
+ status = shouldIgnoreVibrationLocked(vib.uid, vib.displayId, vib.opPkg, vib.attrs);
// Check if something has external control, assume it's more important.
if ((status == null) && (mCurrentExternalVibration != null)) {
@@ -629,7 +631,7 @@
Vibration vib = mCurrentVibration.getVibration();
Vibration.Status ignoreStatus = shouldIgnoreVibrationLocked(
- vib.uid, vib.opPkg, vib.attrs);
+ vib.uid, vib.displayId, vib.opPkg, vib.attrs);
if (inputDevicesChanged || (ignoreStatus != null)) {
if (DEBUG) {
@@ -659,7 +661,7 @@
continue;
}
Vibration.Status ignoreStatus = shouldIgnoreVibrationLocked(
- vib.uid, vib.opPkg, vib.attrs);
+ vib.uid, Display.DEFAULT_DISPLAY, vib.opPkg, vib.attrs);
if (ignoreStatus == null) {
effect = mVibrationScaler.scale(effect, vib.attrs.getUsage());
} else {
@@ -780,6 +782,12 @@
+ attrs);
}
break;
+ case IGNORED_FROM_VIRTUAL_DEVICE:
+ if (DEBUG) {
+ Slog.d(TAG, "Ignoring incoming vibration because it came from a virtual"
+ + " device, attrs= " + attrs);
+ }
+ break;
default:
if (DEBUG) {
Slog.d(TAG, "Vibration for uid=" + uid + " and with attrs=" + attrs
@@ -894,9 +902,10 @@
*/
@GuardedBy("mLock")
@Nullable
- private Vibration.Status shouldIgnoreVibrationLocked(int uid, String opPkg,
+ private Vibration.Status shouldIgnoreVibrationLocked(int uid, int displayId, String opPkg,
VibrationAttributes attrs) {
- Vibration.Status statusFromSettings = mVibrationSettings.shouldIgnoreVibration(uid, attrs);
+ Vibration.Status statusFromSettings = mVibrationSettings.shouldIgnoreVibration(uid,
+ displayId, attrs);
if (statusFromSettings != null) {
return statusFromSettings;
}
@@ -1442,6 +1451,9 @@
return new Vibration.DebugInfo(
mStatus, stats, /* effect= */ null, /* originalEffect= */ null, scale,
externalVibration.getVibrationAttributes(), externalVibration.getUid(),
+ // TODO(b/243604888): propagating displayID from IExternalVibration instead of
+ // using INVALID_DISPLAY for all external vibrations.
+ Display.INVALID_DISPLAY,
externalVibration.getPackage(), /* reason= */ null);
}
@@ -1647,8 +1659,10 @@
boolean alreadyUnderExternalControl = false;
boolean waitForCompletion = false;
synchronized (mLock) {
+ // TODO(b/243604888): propagating displayID from IExternalVibration instead of
+ // using INVALID_DISPLAY for all external vibrations.
Vibration.Status ignoreStatus = shouldIgnoreVibrationLocked(
- vib.getUid(), vib.getPackage(), attrs);
+ vib.getUid(), Display.INVALID_DISPLAY, vib.getPackage(), attrs);
if (ignoreStatus != null) {
vibHolder.scale = IExternalVibratorService.SCALE_MUTE;
// Failed to start the vibration, end it and report metrics right away.
@@ -1840,8 +1854,8 @@
// only cancel background vibrations.
IBinder deathBinder = commonOptions.background ? VibratorManagerService.this
: mShellCallbacksToken;
- Vibration vib = vibrateInternal(Binder.getCallingUid(), SHELL_PACKAGE_NAME, combined,
- attrs, commonOptions.description, deathBinder);
+ Vibration vib = vibrateInternal(Binder.getCallingUid(), Display.DEFAULT_DISPLAY,
+ SHELL_PACKAGE_NAME, combined, attrs, commonOptions.description, deathBinder);
if (vib != null && !commonOptions.background) {
try {
vib.waitForEnd();
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 6fcd285..6538ee3 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -79,6 +79,7 @@
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_ALLOWLISTED;
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER;
import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO;
+import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_EXCLUDE_PORTRAIT_FULLSCREEN;
import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_LARGE;
import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_MEDIUM;
import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY;
@@ -356,7 +357,6 @@
import com.android.server.wm.SurfaceAnimator.AnimationType;
import com.android.server.wm.WindowManagerService.H;
import com.android.server.wm.utils.InsetUtils;
-import com.android.server.wm.utils.WmDisplayCutout;
import dalvik.annotation.optimization.NeverCompile;
@@ -917,7 +917,6 @@
*/
private final Configuration mTmpConfig = new Configuration();
private final Rect mTmpBounds = new Rect();
- private final Rect mTmpOutNonDecorBounds = new Rect();
// Token for targeting this activity for assist purposes.
final Binder assistToken = new Binder();
@@ -2121,7 +2120,7 @@
mActivityRecordInputSink = new ActivityRecordInputSink(this, sourceRecord);
- updateEnterpriseThumbnailDrawable(mAtmService.mUiContext);
+ updateEnterpriseThumbnailDrawable(mAtmService.getUiContext());
}
/**
@@ -7434,7 +7433,7 @@
}
final Rect frame = win.getRelativeFrame();
final Drawable thumbnailDrawable = task.mUserId == mWmService.mCurrentUserId
- ? mAtmService.mUiContext.getDrawable(R.drawable.ic_account_circle)
+ ? mAtmService.getUiContext().getDrawable(R.drawable.ic_account_circle)
: mEnterpriseThumbnailDrawable;
final HardwareBuffer thumbnail = getDisplayContent().mAppTransition
.createCrossProfileAppsThumbnail(thumbnailDrawable, frame);
@@ -8151,10 +8150,12 @@
final int orientation = parentBounds.height() >= parentBounds.width()
? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
// Compute orientation from stable parent bounds (= parent bounds with insets applied)
+ final DisplayInfo di = isFixedRotationTransforming()
+ ? getFixedRotationTransformDisplayInfo()
+ : mDisplayContent.getDisplayInfo();
final Task task = getTask();
- task.calculateInsetFrames(mTmpOutNonDecorBounds /* outNonDecorBounds */,
- outStableBounds /* outStableBounds */, parentBounds /* bounds */,
- mDisplayContent.getDisplayInfo());
+ task.calculateInsetFrames(mTmpBounds /* outNonDecorBounds */,
+ outStableBounds /* outStableBounds */, parentBounds /* bounds */, di);
final int orientationWithInsets = outStableBounds.height() >= outStableBounds.width()
? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
// If orientation does not match the orientation with insets applied, then a
@@ -8818,9 +8819,25 @@
* Returns the min aspect ratio of this activity.
*/
float getMinAspectRatio() {
- if (info.applicationInfo == null || !info.isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO) || (
- info.isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY)
- && !ActivityInfo.isFixedOrientationPortrait(getRequestedOrientation()))) {
+ if (info.applicationInfo == null) {
+ return info.getMinAspectRatio();
+ }
+
+ if (!info.isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO)) {
+ return info.getMinAspectRatio();
+ }
+
+ if (info.isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY)
+ && !ActivityInfo.isFixedOrientationPortrait(getRequestedOrientation())) {
+ return info.getMinAspectRatio();
+ }
+
+ if (info.isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_EXCLUDE_PORTRAIT_FULLSCREEN)
+ && getParent().getConfiguration().orientation == ORIENTATION_PORTRAIT
+ && getParent().getWindowConfiguration().getWindowingMode()
+ == WINDOWING_MODE_FULLSCREEN) {
+ // We are using the parent configuration here as this is the most recent one that gets
+ // passed to onConfigurationChanged when a relevant change takes place
return info.getMinAspectRatio();
}
@@ -9701,10 +9718,10 @@
final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
final int dw = rotated ? display.mBaseDisplayHeight : display.mBaseDisplayWidth;
final int dh = rotated ? display.mBaseDisplayWidth : display.mBaseDisplayHeight;
- final WmDisplayCutout cutout = display.calculateDisplayCutoutForRotation(rotation);
- policy.getNonDecorInsetsLw(rotation, dw, dh, cutout, mNonDecorInsets[rotation]);
- mStableInsets[rotation].set(mNonDecorInsets[rotation]);
- policy.convertNonDecorInsetsToStableInsets(mStableInsets[rotation], rotation);
+ final DisplayPolicy.DecorInsets.Info decorInfo =
+ policy.getDecorInsetsInfo(rotation, dw, dh);
+ mNonDecorInsets[rotation].set(decorInfo.mNonDecorInsets);
+ mStableInsets[rotation].set(decorInfo.mConfigInsets);
if (unfilledContainerBounds == null) {
continue;
diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java
index 7c25b53..0707b81 100644
--- a/services/core/java/com/android/server/wm/ActivityStartController.java
+++ b/services/core/java/com/android/server/wm/ActivityStartController.java
@@ -384,6 +384,14 @@
callingUid, realCallingUid, UserHandle.USER_NULL);
final SparseArray<String> startingUidPkgs = new SparseArray<>();
final long origId = Binder.clearCallingIdentity();
+
+ SafeActivityOptions bottomOptions = null;
+ if (options != null) {
+ // To ensure the first N-1 activities (N == total # of activities) are also launched
+ // into the correct display, use a copy of the passed-in options (keeping only
+ // display-related info) for these activities.
+ bottomOptions = options.selectiveCloneDisplayOptions();
+ }
try {
intents = ArrayUtils.filterNotNull(intents, Intent[]::new);
final ActivityStarter[] starters = new ActivityStarter[intents.length];
@@ -432,7 +440,7 @@
final boolean top = i == intents.length - 1;
final SafeActivityOptions checkedOptions = top
? options
- : null;
+ : bottomOptions;
starters[i] = obtainStarter(intent, reason)
.setIntentGrants(intentGrants)
.setCaller(caller)
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index fedbe5b..027d485 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -203,6 +203,10 @@
private TaskFragment mAddingToTaskFragment;
@VisibleForTesting
boolean mAddingToTask;
+ // Activity that was moved to the top of its task in situations where activity-order changes
+ // due to launch flags (eg. REORDER_TO_TOP).
+ @VisibleForTesting
+ ActivityRecord mMovedToTopActivity;
private ActivityInfo mNewTaskInfo;
private Intent mNewTaskIntent;
@@ -1763,7 +1767,9 @@
// The activity is started new rather than just brought forward, so record it as an
// existence change.
transitionController.collectExistenceChange(started);
- } else if (result == START_DELIVERED_TO_TOP && newTransition != null) {
+ } else if (result == START_DELIVERED_TO_TOP && newTransition != null
+ // An activity has changed order/visibility so this isn't just deliver-to-top
+ && mMovedToTopActivity == null) {
// We just delivered to top, so there isn't an actual transition here.
if (!forceTransientTransition) {
newTransition.abort();
@@ -2343,10 +2349,15 @@
// In this situation we want to remove all activities from the task up to the one
// being started. In most cases this means we are resetting the task to its initial
// state.
+ int[] finishCount = new int[1];
final ActivityRecord clearTop = targetTask.performClearTop(mStartActivity,
- mLaunchFlags);
+ mLaunchFlags, finishCount);
if (clearTop != null && !clearTop.finishing) {
+ if (finishCount[0] > 0) {
+ // Only record if actually moved to top.
+ mMovedToTopActivity = clearTop;
+ }
if (clearTop.isRootOfTask()) {
// Activity aliases may mean we use different intents for the top activity,
// so make sure the task now has the identity of the new intent.
@@ -2379,10 +2390,15 @@
// already be running somewhere in the history, and we want to shuffle it to
// the front of the root task if so.
final ActivityRecord act =
- targetTask.findActivityInHistory(mStartActivity.mActivityComponent);
+ targetTask.findActivityInHistory(mStartActivity.mActivityComponent,
+ mStartActivity.mUserId);
if (act != null) {
final Task task = act.getTask();
- task.moveActivityToFrontLocked(act);
+ boolean actuallyMoved = task.moveActivityToFrontLocked(act);
+ if (actuallyMoved) {
+ // Only record if the activity actually moved.
+ mMovedToTopActivity = act;
+ }
act.updateOptionsLocked(mOptions);
deliverNewIntent(act, intentGrants);
act.getTaskFragment().clearLastPausedActivity();
@@ -3017,10 +3033,7 @@
newParent = candidateTf;
}
}
- if (newParent.canHaveEmbeddingActivityTransition(mStartActivity)) {
- // Make sure the embedded TaskFragment is included in the start activity transition.
- newParent.collectEmbeddedTaskFragmentIfNeeded();
- }
+ newParent.mTransitionController.collect(newParent);
if (mStartActivity.getTaskFragment() == null
|| mStartActivity.getTaskFragment() == newParent) {
newParent.addChild(mStartActivity, POSITION_TOP);
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 7e310b4..75e24a8 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -331,6 +331,7 @@
public static final String DUMP_RECENTS_CMD = "recents";
public static final String DUMP_RECENTS_SHORT_CMD = "r";
public static final String DUMP_TOP_RESUMED_ACTIVITY = "top-resumed";
+ public static final String DUMP_VISIBLE_ACTIVITIES = "visible";
/** This activity is not being relaunched, or being relaunched for a non-resize reason. */
public static final int RELAUNCH_REASON_NONE = 0;
@@ -345,7 +346,7 @@
* This Context is themable and meant for UI display (AlertDialogs, etc.). The theme can
* change at runtime. Use mContext for non-UI purposes.
*/
- final Context mUiContext;
+ private final Context mUiContext;
final ActivityThread mSystemThread;
H mH;
UiHandler mUiHandler;
@@ -1040,6 +1041,10 @@
}
}
+ Context getUiContext() {
+ return mUiContext;
+ }
+
UserManagerService getUserManager() {
if (mUserManager == null) {
IBinder b = ServiceManager.getService(Context.USER_SERVICE);
@@ -4054,6 +4059,25 @@
}
}
+ void dumpVisibleActivitiesLocked(PrintWriter pw) {
+ pw.println("ACTIVITY MANAGER VISIBLE ACTIVITIES (dumpsys activity visible)");
+ ArrayList<ActivityRecord> activities =
+ mRootWindowContainer.getDumpActivities("all", /* dumpVisibleRootTasksOnly */ true,
+ /* dumpFocusedRootTaskOnly */ false, UserHandle.USER_ALL);
+ boolean needSeparator = false;
+ for (int i = activities.size() - 1; i >= 0; i--) {
+ ActivityRecord activity = activities.get(i);
+ if (!activity.isVisible()) {
+ continue;
+ }
+ if (needSeparator) {
+ pw.println();
+ }
+ activity.dump(pw, "", true);
+ needSeparator = true;
+ }
+ }
+
void dumpActivitiesLocked(FileDescriptor fd, PrintWriter pw, String[] args,
int opti, boolean dumpAll, boolean dumpClient, String dumpPackage) {
dumpActivitiesLocked(fd, pw, args, opti, dumpAll, dumpClient, dumpPackage,
@@ -6286,6 +6310,8 @@
}
} else if (DUMP_TOP_RESUMED_ACTIVITY.equals(cmd)) {
dumpTopResumedActivityLocked(pw);
+ } else if (DUMP_VISIBLE_ACTIVITIES.equals(cmd)) {
+ dumpVisibleActivitiesLocked(pw);
}
}
}
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index 53f2c71..5c1a877 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -39,6 +39,7 @@
import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY;
import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_OCCLUDE;
+import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_OCCLUDE_BY_DREAM;
import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_UNOCCLUDE;
import static android.view.WindowManager.TRANSIT_OLD_NONE;
import static android.view.WindowManager.TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE;
@@ -758,7 +759,8 @@
if (isKeyguardGoingAwayTransitOld(transit) && enter) {
a = mTransitionAnimation.loadKeyguardExitAnimation(mNextAppTransitionFlags,
transit == TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER);
- } else if (transit == TRANSIT_OLD_KEYGUARD_OCCLUDE) {
+ } else if (transit == TRANSIT_OLD_KEYGUARD_OCCLUDE
+ || transit == TRANSIT_OLD_KEYGUARD_OCCLUDE_BY_DREAM) {
a = null;
} else if (transit == TRANSIT_OLD_KEYGUARD_UNOCCLUDE && !enter) {
a = mTransitionAnimation.loadKeyguardUnoccludeAnimation();
@@ -1170,6 +1172,9 @@
case TRANSIT_OLD_KEYGUARD_OCCLUDE: {
return "TRANSIT_OLD_KEYGUARD_OCCLUDE";
}
+ case TRANSIT_OLD_KEYGUARD_OCCLUDE_BY_DREAM: {
+ return "TRANSIT_OLD_KEYGUARD_OCCLUDE_BY_DREAM";
+ }
case TRANSIT_OLD_KEYGUARD_UNOCCLUDE: {
return "TRANSIT_OLD_KEYGUARD_UNOCCLUDE";
}
@@ -1425,6 +1430,7 @@
static boolean isKeyguardOccludeTransitOld(@TransitionOldType int transit) {
return transit == TRANSIT_OLD_KEYGUARD_OCCLUDE
+ || transit == TRANSIT_OLD_KEYGUARD_OCCLUDE_BY_DREAM
|| transit == TRANSIT_OLD_KEYGUARD_UNOCCLUDE;
}
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index 5ac5f2e..5599f2c 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -38,6 +38,7 @@
import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY;
import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_OCCLUDE;
+import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_OCCLUDE_BY_DREAM;
import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_UNOCCLUDE;
import static android.view.WindowManager.TRANSIT_OLD_NONE;
import static android.view.WindowManager.TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE;
@@ -363,8 +364,14 @@
// When there is a closing app, the keyguard has already been occluded by an
// activity, and another activity has started on top of that activity, so normal
// app transition animation should be used.
- return closingApps.isEmpty() ? TRANSIT_OLD_KEYGUARD_OCCLUDE
- : TRANSIT_OLD_ACTIVITY_OPEN;
+ if (!closingApps.isEmpty()) {
+ return TRANSIT_OLD_ACTIVITY_OPEN;
+ }
+ if (!openingApps.isEmpty() && openingApps.valueAt(0).getActivityType()
+ == ACTIVITY_TYPE_DREAM) {
+ return TRANSIT_OLD_KEYGUARD_OCCLUDE_BY_DREAM;
+ }
+ return TRANSIT_OLD_KEYGUARD_OCCLUDE;
case TRANSIT_KEYGUARD_UNOCCLUDE:
return TRANSIT_OLD_KEYGUARD_UNOCCLUDE;
}
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java
index 35a39c0..028d4b3 100644
--- a/services/core/java/com/android/server/wm/BackNavigationController.java
+++ b/services/core/java/com/android/server/wm/BackNavigationController.java
@@ -310,7 +310,7 @@
mBackNaviAnimationController = new BackNaviAnimationController(
backAnimationAdaptor.getRunner(), this,
currentActivity.getDisplayId());
- prepareBackToHomeTransition(currentTask, prevTask);
+ prepareBackToHomeTransition(currentActivity, prevTask);
infoBuilder.setPrepareAnimation(true);
}
} else {
@@ -489,8 +489,8 @@
mWindowManagerService = wm;
}
- private void prepareBackToHomeTransition(Task currentTask, Task homeTask) {
- final DisplayContent dc = currentTask.getDisplayContent();
+ private void prepareBackToHomeTransition(ActivityRecord currentActivity, Task homeTask) {
+ final DisplayContent dc = currentActivity.getDisplayContent();
final ActivityRecord homeActivity = homeTask.getTopNonFinishingActivity();
if (!homeActivity.mVisibleRequested) {
homeActivity.setVisibility(true);
@@ -499,7 +499,7 @@
dc.ensureActivitiesVisible(
null /* starting */, 0 /* configChanges */,
false /* preserveWindows */, true);
- mBackNaviAnimationController.initialize(homeActivity, currentTask.getTopMostActivity());
+ mBackNaviAnimationController.initialize(homeActivity, currentActivity);
}
void finishAnimation() {
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 4e92db2..b093d25 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -982,7 +982,9 @@
final int preferredModeId = getDisplayPolicy().getRefreshRatePolicy()
.getPreferredModeId(w);
- if (w.isFocused() && mTmpApplySurfaceChangesTransactionState.preferredModeId == 0
+
+ if (w.getWindowingMode() != WINDOWING_MODE_PINNED
+ && mTmpApplySurfaceChangesTransactionState.preferredModeId == 0
&& preferredModeId != 0) {
mTmpApplySurfaceChangesTransactionState.preferredModeId = preferredModeId;
}
@@ -1078,7 +1080,7 @@
* mDisplayMetrics.densityDpi / DENSITY_DEFAULT;
isDefaultDisplay = mDisplayId == DEFAULT_DISPLAY;
mInsetsStateController = new InsetsStateController(this);
- mDisplayFrames = new DisplayFrames(mDisplayId, mInsetsStateController.getRawInsetsState(),
+ mDisplayFrames = new DisplayFrames(mInsetsStateController.getRawInsetsState(),
mDisplayInfo, calculateDisplayCutoutForRotation(mDisplayInfo.rotation),
calculateRoundedCornersForRotation(mDisplayInfo.rotation),
calculatePrivacyIndicatorBoundsForRotation(mDisplayInfo.rotation));
@@ -1146,6 +1148,7 @@
mMinSizeOfResizeableTaskDp = getMinimalTaskSizeDp();
if (DEBUG_DISPLAY) Slog.v(TAG_WM, "Creating display=" + display);
+ setWindowingMode(WINDOWING_MODE_FULLSCREEN);
mWmService.mDisplayWindowSettings.applySettingsToDisplayLocked(this);
}
@@ -1612,24 +1615,6 @@
}
config = new Configuration();
computeScreenConfiguration(config);
- } else if (!(mTransitionController.isCollecting(this)
- // If waiting for a remote display change, don't prematurely update configuration.
- || mRemoteDisplayChangeController.isWaitingForRemoteDisplayChange())) {
- // No obvious action we need to take, but if our current state mismatches the
- // activity manager's, update it, disregarding font scale, which should remain set
- // to the value of the previous configuration.
- // Here we're calling Configuration#unset() instead of setToDefaults() because we
- // need to keep override configs clear of non-empty values (e.g. fontSize).
- final Configuration currentConfig = getRequestedOverrideConfiguration();
- mTmpConfiguration.unset();
- mTmpConfiguration.updateFrom(currentConfig);
- computeScreenConfiguration(mTmpConfiguration);
- if (currentConfig.diff(mTmpConfiguration) != 0) {
- mWaitingForConfig = true;
- setLayoutNeeded();
- mDisplayRotation.prepareNormalRotationAnimation();
- config = new Configuration(mTmpConfiguration);
- }
}
return config;
@@ -1934,11 +1919,11 @@
private void startFixedRotationTransform(WindowToken token, int rotation) {
mTmpConfiguration.unset();
final DisplayInfo info = computeScreenConfiguration(mTmpConfiguration, rotation);
- final WmDisplayCutout cutout = calculateDisplayCutoutForRotation(rotation);
+ final DisplayCutout cutout = calculateDisplayCutoutForRotation(rotation);
final RoundedCorners roundedCorners = calculateRoundedCornersForRotation(rotation);
final PrivacyIndicatorBounds indicatorBounds =
calculatePrivacyIndicatorBoundsForRotation(rotation);
- final DisplayFrames displayFrames = new DisplayFrames(mDisplayId, new InsetsState(), info,
+ final DisplayFrames displayFrames = new DisplayFrames(new InsetsState(), info,
cutout, roundedCorners, indicatorBounds);
token.applyFixedRotationTransform(info, displayFrames, mTmpConfiguration);
}
@@ -2145,12 +2130,10 @@
final int dh = rotated ? mBaseDisplayWidth : mBaseDisplayHeight;
// Update application display metrics.
- final WmDisplayCutout wmDisplayCutout = calculateDisplayCutoutForRotation(rotation);
- final DisplayCutout displayCutout = wmDisplayCutout.getDisplayCutout();
+ final DisplayCutout displayCutout = calculateDisplayCutoutForRotation(rotation);
final RoundedCorners roundedCorners = calculateRoundedCornersForRotation(rotation);
- final Rect appFrame = mDisplayPolicy.getNonDecorDisplayFrame(dw, dh, rotation,
- wmDisplayCutout);
+ final Rect appFrame = mDisplayPolicy.getDecorInsetsInfo(rotation, dw, dh).mNonDecorFrame;
mDisplayInfo.rotation = rotation;
mDisplayInfo.logicalWidth = dw;
mDisplayInfo.logicalHeight = dh;
@@ -2188,9 +2171,10 @@
return mDisplayInfo;
}
- WmDisplayCutout calculateDisplayCutoutForRotation(int rotation) {
+ DisplayCutout calculateDisplayCutoutForRotation(int rotation) {
return mDisplayCutoutCache.getOrCompute(
- mIsSizeForced ? mBaseDisplayCutout : mInitialDisplayCutout, rotation);
+ mIsSizeForced ? mBaseDisplayCutout : mInitialDisplayCutout, rotation)
+ .getDisplayCutout();
}
static WmDisplayCutout calculateDisplayCutoutForRotationAndDisplaySizeUncached(
@@ -2261,9 +2245,7 @@
final int dh = rotated ? mBaseDisplayWidth : mBaseDisplayHeight;
outConfig.windowConfiguration.setMaxBounds(0, 0, dw, dh);
outConfig.windowConfiguration.setBounds(outConfig.windowConfiguration.getMaxBounds());
-
- final WmDisplayCutout wmDisplayCutout = calculateDisplayCutoutForRotation(rotation);
- computeScreenAppConfiguration(outConfig, dw, dh, rotation, wmDisplayCutout);
+ computeScreenAppConfiguration(outConfig, dw, dh, rotation);
final DisplayInfo displayInfo = new DisplayInfo(mDisplayInfo);
displayInfo.rotation = rotation;
@@ -2272,7 +2254,7 @@
final Rect appBounds = outConfig.windowConfiguration.getAppBounds();
displayInfo.appWidth = appBounds.width();
displayInfo.appHeight = appBounds.height();
- final DisplayCutout displayCutout = wmDisplayCutout.getDisplayCutout();
+ final DisplayCutout displayCutout = calculateDisplayCutoutForRotation(rotation);
displayInfo.displayCutout = displayCutout.isEmpty() ? null : displayCutout;
computeSizeRangesAndScreenLayout(displayInfo, rotated, dw, dh,
mDisplayMetrics.density, outConfig);
@@ -2281,21 +2263,17 @@
/** Compute configuration related to application without changing current display. */
private void computeScreenAppConfiguration(Configuration outConfig, int dw, int dh,
- int rotation, WmDisplayCutout wmDisplayCutout) {
- final DisplayFrames displayFrames =
- mDisplayPolicy.getSimulatedDisplayFrames(rotation, dw, dh, wmDisplayCutout);
- final Rect appFrame =
- mDisplayPolicy.getNonDecorDisplayFrameWithSimulatedFrame(displayFrames);
+ int rotation) {
+ final DisplayPolicy.DecorInsets.Info info =
+ mDisplayPolicy.getDecorInsetsInfo(rotation, dw, dh);
// AppBounds at the root level should mirror the app screen size.
- outConfig.windowConfiguration.setAppBounds(appFrame);
+ outConfig.windowConfiguration.setAppBounds(info.mNonDecorFrame);
outConfig.windowConfiguration.setRotation(rotation);
outConfig.orientation = (dw <= dh) ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
final float density = mDisplayMetrics.density;
- final Point configSize =
- mDisplayPolicy.getConfigDisplaySizeWithSimulatedFrame(displayFrames);
- outConfig.screenWidthDp = (int) (configSize.x / density + 0.5f);
- outConfig.screenHeightDp = (int) (configSize.y / density + 0.5f);
+ outConfig.screenWidthDp = (int) (info.mConfigFrame.width() / density + 0.5f);
+ outConfig.screenHeightDp = (int) (info.mConfigFrame.height() / density + 0.5f);
outConfig.compatScreenWidthDp = (int) (outConfig.screenWidthDp / mCompatibleScreenScale);
outConfig.compatScreenHeightDp = (int) (outConfig.screenHeightDp / mCompatibleScreenScale);
@@ -2318,8 +2296,7 @@
config.windowConfiguration.setWindowingMode(getWindowingMode());
config.windowConfiguration.setDisplayWindowingMode(getWindowingMode());
- computeScreenAppConfiguration(config, dw, dh, displayInfo.rotation,
- calculateDisplayCutoutForRotation(getRotation()));
+ computeScreenAppConfiguration(config, dw, dh, displayInfo.rotation);
config.screenLayout = (config.screenLayout & ~Configuration.SCREENLAYOUT_ROUND_MASK)
| ((displayInfo.flags & Display.FLAG_ROUND) != 0
@@ -2428,9 +2405,8 @@
private int reduceCompatConfigWidthSize(int curSize, int rotation,
DisplayMetrics dm, int dw, int dh) {
- final WmDisplayCutout wmDisplayCutout = calculateDisplayCutoutForRotation(rotation);
- final Rect nonDecorSize = mDisplayPolicy.getNonDecorDisplayFrame(dw, dh, rotation,
- wmDisplayCutout);
+ final Rect nonDecorSize =
+ mDisplayPolicy.getDecorInsetsInfo(rotation, dw, dh).mNonDecorFrame;
dm.noncompatWidthPixels = nonDecorSize.width();
dm.noncompatHeightPixels = nonDecorSize.height();
float scale = CompatibilityInfo.computeCompatibleScaling(dm, null);
@@ -2479,11 +2455,8 @@
}
private int reduceConfigLayout(int curLayout, int rotation, float density, int dw, int dh) {
- // Get the display cutout at this rotation.
- final WmDisplayCutout wmDisplayCutout = calculateDisplayCutoutForRotation(rotation);
-
// Get the app screen size at this rotation.
- final Rect size = mDisplayPolicy.getNonDecorDisplayFrame(dw, dh, rotation, wmDisplayCutout);
+ final Rect size = mDisplayPolicy.getDecorInsetsInfo(rotation, dw, dh).mNonDecorFrame;
// Compute the screen layout size class for this rotation.
int longSize = size.width();
@@ -2499,19 +2472,21 @@
}
private void adjustDisplaySizeRanges(DisplayInfo displayInfo, int rotation, int dw, int dh) {
- final WmDisplayCutout wmDisplayCutout = calculateDisplayCutoutForRotation(rotation);
- final Point size = mDisplayPolicy.getConfigDisplaySize(dw, dh, rotation, wmDisplayCutout);
- if (size.x < displayInfo.smallestNominalAppWidth) {
- displayInfo.smallestNominalAppWidth = size.x;
+ final DisplayPolicy.DecorInsets.Info info = mDisplayPolicy.getDecorInsetsInfo(
+ rotation, dw, dh);
+ final int w = info.mConfigFrame.width();
+ final int h = info.mConfigFrame.height();
+ if (w < displayInfo.smallestNominalAppWidth) {
+ displayInfo.smallestNominalAppWidth = w;
}
- if (size.x > displayInfo.largestNominalAppWidth) {
- displayInfo.largestNominalAppWidth = size.x;
+ if (w > displayInfo.largestNominalAppWidth) {
+ displayInfo.largestNominalAppWidth = w;
}
- if (size.y < displayInfo.smallestNominalAppHeight) {
- displayInfo.smallestNominalAppHeight = size.y;
+ if (h < displayInfo.smallestNominalAppHeight) {
+ displayInfo.smallestNominalAppHeight = h;
}
- if (size.y > displayInfo.largestNominalAppHeight) {
- displayInfo.largestNominalAppHeight = size.y;
+ if (h > displayInfo.largestNominalAppHeight) {
+ displayInfo.largestNominalAppHeight = h;
}
}
@@ -2678,16 +2653,6 @@
}
@Override
- public void setWindowingMode(int windowingMode) {
- // Intentionally call onRequestedOverrideConfigurationChanged() directly to change windowing
- // mode and display windowing mode atomically.
- mTmpConfiguration.setTo(getRequestedOverrideConfiguration());
- mTmpConfiguration.windowConfiguration.setWindowingMode(windowingMode);
- mTmpConfiguration.windowConfiguration.setDisplayWindowingMode(windowingMode);
- onRequestedOverrideConfigurationChanged(mTmpConfiguration);
- }
-
- @Override
void setDisplayWindowingMode(int windowingMode) {
setWindowingMode(windowingMode);
}
@@ -2771,14 +2736,19 @@
}
private void updateDisplayFrames(boolean notifyInsetsChange) {
- if (mDisplayFrames.update(mDisplayInfo,
- calculateDisplayCutoutForRotation(mDisplayInfo.rotation),
- calculateRoundedCornersForRotation(mDisplayInfo.rotation),
- calculatePrivacyIndicatorBoundsForRotation(mDisplayInfo.rotation))) {
+ if (updateDisplayFrames(mDisplayFrames, mDisplayInfo.rotation,
+ mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight)) {
mInsetsStateController.onDisplayFramesUpdated(notifyInsetsChange);
}
}
+ boolean updateDisplayFrames(DisplayFrames displayFrames, int rotation, int w, int h) {
+ return displayFrames.update(rotation, w, h,
+ calculateDisplayCutoutForRotation(rotation),
+ calculateRoundedCornersForRotation(rotation),
+ calculatePrivacyIndicatorBoundsForRotation(rotation));
+ }
+
@Override
void onDisplayChanged(DisplayContent dc) {
super.onDisplayChanged(dc);
@@ -2941,6 +2911,9 @@
+ mBaseDisplayHeight + " on display:" + getDisplayId());
}
}
+ if (mDisplayReady) {
+ mDisplayPolicy.mDecorInsets.invalidate();
+ }
}
/**
@@ -5582,7 +5555,7 @@
outExclusionUnrestricted.setEmpty();
}
final Region unhandled = Region.obtain();
- unhandled.set(0, 0, mDisplayFrames.mDisplayWidth, mDisplayFrames.mDisplayHeight);
+ unhandled.set(0, 0, mDisplayFrames.mWidth, mDisplayFrames.mHeight);
final Rect leftEdge = mInsetsStateController.getSourceProvider(ITYPE_LEFT_GESTURES)
.getSource().getFrame();
diff --git a/services/core/java/com/android/server/wm/DisplayFrames.java b/services/core/java/com/android/server/wm/DisplayFrames.java
index 7ca38b8..33641f7 100644
--- a/services/core/java/com/android/server/wm/DisplayFrames.java
+++ b/services/core/java/com/android/server/wm/DisplayFrames.java
@@ -30,8 +30,6 @@
import android.view.PrivacyIndicatorBounds;
import android.view.RoundedCorners;
-import com.android.server.wm.utils.WmDisplayCutout;
-
import java.io.PrintWriter;
/**
@@ -39,8 +37,6 @@
* @hide
*/
public class DisplayFrames {
- public final int mDisplayId;
-
public final InsetsState mInsetsState;
/**
@@ -54,48 +50,45 @@
*/
public final Rect mDisplayCutoutSafe = new Rect();
- public int mDisplayWidth;
- public int mDisplayHeight;
+ public int mWidth;
+ public int mHeight;
public int mRotation;
- public DisplayFrames(int displayId, InsetsState insetsState, DisplayInfo info,
- WmDisplayCutout displayCutout, RoundedCorners roundedCorners,
- PrivacyIndicatorBounds indicatorBounds) {
- mDisplayId = displayId;
+ public DisplayFrames(InsetsState insetsState, DisplayInfo info, DisplayCutout cutout,
+ RoundedCorners roundedCorners, PrivacyIndicatorBounds indicatorBounds) {
mInsetsState = insetsState;
- update(info, displayCutout, roundedCorners, indicatorBounds);
+ update(info.rotation, info.logicalWidth, info.logicalHeight, cutout, roundedCorners,
+ indicatorBounds);
+ }
+
+ DisplayFrames() {
+ mInsetsState = new InsetsState();
}
/**
- * This is called when {@link DisplayInfo} or {@link PrivacyIndicatorBounds} is updated.
+ * This is called if the display info may be changed, e.g. rotation, size, insets.
*
- * @param info the updated {@link DisplayInfo}.
- * @param displayCutout the updated {@link DisplayCutout}.
- * @param roundedCorners the updated {@link RoundedCorners}.
- * @param indicatorBounds the updated {@link PrivacyIndicatorBounds}.
* @return {@code true} if anything has been changed; {@code false} otherwise.
*/
- public boolean update(DisplayInfo info, @NonNull WmDisplayCutout displayCutout,
+ public boolean update(int rotation, int w, int h, @NonNull DisplayCutout displayCutout,
@NonNull RoundedCorners roundedCorners,
@NonNull PrivacyIndicatorBounds indicatorBounds) {
final InsetsState state = mInsetsState;
final Rect safe = mDisplayCutoutSafe;
- final DisplayCutout cutout = displayCutout.getDisplayCutout();
- if (mDisplayWidth == info.logicalWidth && mDisplayHeight == info.logicalHeight
- && mRotation == info.rotation
- && state.getDisplayCutout().equals(cutout)
+ if (mRotation == rotation && mWidth == w && mHeight == h
+ && mInsetsState.getDisplayCutout().equals(displayCutout)
&& state.getRoundedCorners().equals(roundedCorners)
&& state.getPrivacyIndicatorBounds().equals(indicatorBounds)) {
return false;
}
- mDisplayWidth = info.logicalWidth;
- mDisplayHeight = info.logicalHeight;
- mRotation = info.rotation;
+ mRotation = rotation;
+ mWidth = w;
+ mHeight = h;
final Rect unrestricted = mUnrestricted;
- unrestricted.set(0, 0, mDisplayWidth, mDisplayHeight);
+ unrestricted.set(0, 0, w, h);
state.setDisplayFrame(unrestricted);
- state.setDisplayCutout(cutout);
+ state.setDisplayCutout(displayCutout);
state.setRoundedCorners(roundedCorners);
state.setPrivacyIndicatorBounds(indicatorBounds);
state.getDisplayCutoutSafe(safe);
@@ -132,7 +125,6 @@
}
public void dump(String prefix, PrintWriter pw) {
- pw.println(prefix + "DisplayFrames w=" + mDisplayWidth + " h=" + mDisplayHeight
- + " r=" + mRotation);
+ pw.println(prefix + "DisplayFrames w=" + mWidth + " h=" + mHeight + " r=" + mRotation);
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 713c13e..b26de07 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -19,19 +19,15 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.view.Display.TYPE_INTERNAL;
-import static android.view.InsetsState.ITYPE_BOTTOM_DISPLAY_CUTOUT;
import static android.view.InsetsState.ITYPE_BOTTOM_MANDATORY_GESTURES;
import static android.view.InsetsState.ITYPE_BOTTOM_TAPPABLE_ELEMENT;
import static android.view.InsetsState.ITYPE_CAPTION_BAR;
import static android.view.InsetsState.ITYPE_CLIMATE_BAR;
import static android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR;
-import static android.view.InsetsState.ITYPE_LEFT_DISPLAY_CUTOUT;
import static android.view.InsetsState.ITYPE_LEFT_GESTURES;
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
-import static android.view.InsetsState.ITYPE_RIGHT_DISPLAY_CUTOUT;
import static android.view.InsetsState.ITYPE_RIGHT_GESTURES;
import static android.view.InsetsState.ITYPE_STATUS_BAR;
-import static android.view.InsetsState.ITYPE_TOP_DISPLAY_CUTOUT;
import static android.view.InsetsState.ITYPE_TOP_MANDATORY_GESTURES;
import static android.view.InsetsState.ITYPE_TOP_TAPPABLE_ELEMENT;
import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;
@@ -107,7 +103,6 @@
import android.content.res.Resources;
import android.graphics.Insets;
import android.graphics.PixelFormat;
-import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Region;
import android.gui.DropInputMode;
@@ -132,8 +127,6 @@
import android.view.InsetsState;
import android.view.InsetsState.InternalInsetsType;
import android.view.InsetsVisibilities;
-import android.view.PrivacyIndicatorBounds;
-import android.view.RoundedCorners;
import android.view.Surface;
import android.view.View;
import android.view.ViewDebug;
@@ -151,7 +144,6 @@
import com.android.internal.policy.ForceShowNavBarSettingsObserver;
import com.android.internal.policy.GestureNavigationSettingsObserver;
import com.android.internal.policy.ScreenDecorationsUtils;
-import com.android.internal.policy.SystemBarUtils;
import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.statusbar.LetterboxDetails;
import com.android.internal.util.ScreenshotHelper;
@@ -166,7 +158,6 @@
import com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs;
import com.android.server.statusbar.StatusBarManagerInternal;
import com.android.server.wallpaper.WallpaperManagerInternal;
-import com.android.server.wm.utils.WmDisplayCutout;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -242,6 +233,8 @@
private final SystemGesturesPointerEventListener mSystemGestures;
+ final DecorInsets mDecorInsets;
+
private volatile int mLidState = LID_ABSENT;
private volatile int mDockMode = Intent.EXTRA_DOCK_STATE_UNDOCKED;
private volatile boolean mHdmiPlugged;
@@ -266,7 +259,6 @@
private WindowState mStatusBar = null;
private volatile WindowState mNotificationShade;
- private final int[] mStatusBarHeightForRotation = new int[4];
private WindowState mNavigationBar = null;
@NavigationBarPosition
private int mNavigationBarPosition = NAV_BAR_BOTTOM;
@@ -353,7 +345,6 @@
private static final Rect sTmpRect = new Rect();
private static final Rect sTmpRect2 = new Rect();
- private static final Rect sTmpLastParentFrame = new Rect();
private static final Rect sTmpDisplayCutoutSafe = new Rect();
private static final ClientWindowFrames sTmpClientFrames = new ClientWindowFrames();
@@ -391,16 +382,6 @@
private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS = 0;
private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION = 1;
- // TODO (b/235842600): Use public type once we can treat task bar as navigation bar.
- private static final int[] STABLE_TYPES = new int[]{
- ITYPE_TOP_DISPLAY_CUTOUT, ITYPE_RIGHT_DISPLAY_CUTOUT, ITYPE_BOTTOM_DISPLAY_CUTOUT,
- ITYPE_LEFT_DISPLAY_CUTOUT, ITYPE_NAVIGATION_BAR, ITYPE_STATUS_BAR, ITYPE_CLIMATE_BAR
- };
- private static final int[] NON_DECOR_TYPES = new int[]{
- ITYPE_TOP_DISPLAY_CUTOUT, ITYPE_RIGHT_DISPLAY_CUTOUT, ITYPE_BOTTOM_DISPLAY_CUTOUT,
- ITYPE_LEFT_DISPLAY_CUTOUT, ITYPE_NAVIGATION_BAR
- };
-
private final GestureNavigationSettingsObserver mGestureNavigationSettingsObserver;
private final WindowManagerInternal.AppTransitionListener mAppTransitionListener;
@@ -440,10 +421,11 @@
mService = service;
mContext = displayContent.isDefaultDisplay ? service.mContext
: service.mContext.createDisplayContext(displayContent.getDisplay());
- mUiContext = displayContent.isDefaultDisplay ? service.mAtmService.mUiContext
+ mUiContext = displayContent.isDefaultDisplay ? service.mAtmService.getUiContext()
: service.mAtmService.mSystemThread
.getSystemUiContext(displayContent.getDisplayId());
mDisplayContent = displayContent;
+ mDecorInsets = new DecorInsets(displayContent);
mLock = service.getWindowManagerLock();
final int displayId = displayContent.getDisplayId();
@@ -1227,7 +1209,7 @@
Math.max(displayFrames.mDisplayCutoutSafe.left, 0);
inOutFrame.left = 0;
inOutFrame.top = 0;
- inOutFrame.bottom = displayFrames.mDisplayHeight;
+ inOutFrame.bottom = displayFrames.mHeight;
inOutFrame.right = leftSafeInset + mLeftGestureInset;
});
mDisplayContent.setInsetProvider(ITYPE_RIGHT_GESTURES, win,
@@ -1237,8 +1219,8 @@
displayFrames.mUnrestricted.right);
inOutFrame.left = rightSafeInset - mRightGestureInset;
inOutFrame.top = 0;
- inOutFrame.bottom = displayFrames.mDisplayHeight;
- inOutFrame.right = displayFrames.mDisplayWidth;
+ inOutFrame.bottom = displayFrames.mHeight;
+ inOutFrame.right = displayFrames.mWidth;
});
mDisplayContent.setInsetProvider(ITYPE_BOTTOM_TAPPABLE_ELEMENT, win,
(displayFrames, windowContainer, inOutFrame) -> {
@@ -1429,11 +1411,6 @@
return Math.max(statusBarHeight, displayFrames.mDisplayCutoutSafe.top);
}
- @VisibleForTesting
- int getStatusBarHeightForRotation(@Surface.Rotation int rotation) {
- return SystemBarUtils.getStatusBarHeightForRotation(mUiContext, rotation);
- }
-
WindowState getStatusBar() {
return mStatusBar != null ? mStatusBar : mStatusBarAlt;
}
@@ -1929,25 +1906,11 @@
final Resources res = getCurrentUserResources();
final int portraitRotation = displayRotation.getPortraitRotation();
- final int upsideDownRotation = displayRotation.getUpsideDownRotation();
- final int landscapeRotation = displayRotation.getLandscapeRotation();
- final int seascapeRotation = displayRotation.getSeascapeRotation();
if (hasStatusBar()) {
- mStatusBarHeightForRotation[portraitRotation] =
- mStatusBarHeightForRotation[upsideDownRotation] =
- getStatusBarHeightForRotation(portraitRotation);
- mStatusBarHeightForRotation[landscapeRotation] =
- getStatusBarHeightForRotation(landscapeRotation);
- mStatusBarHeightForRotation[seascapeRotation] =
- getStatusBarHeightForRotation(seascapeRotation);
mDisplayCutoutTouchableRegionSize = res.getDimensionPixelSize(
R.dimen.display_cutout_touchable_region_size);
} else {
- mStatusBarHeightForRotation[portraitRotation] =
- mStatusBarHeightForRotation[upsideDownRotation] =
- mStatusBarHeightForRotation[landscapeRotation] =
- mStatusBarHeightForRotation[seascapeRotation] = 0;
mDisplayCutoutTouchableRegionSize = 0;
}
@@ -2053,33 +2016,9 @@
}
/**
- * Return the display frame available after excluding any screen decorations that could never be
- * removed in Honeycomb. That is, system bar or button bar.
- *
- * @return display frame excluding all non-decor insets.
- */
- Rect getNonDecorDisplayFrame(int fullWidth, int fullHeight, int rotation,
- WmDisplayCutout cutout) {
- final DisplayFrames displayFrames =
- getSimulatedDisplayFrames(rotation, fullWidth, fullHeight, cutout);
- return getNonDecorDisplayFrameWithSimulatedFrame(displayFrames);
- }
-
- Rect getNonDecorDisplayFrameWithSimulatedFrame(DisplayFrames displayFrames) {
- final Rect nonDecorInsets =
- getInsetsWithInternalTypes(displayFrames, NON_DECOR_TYPES).toRect();
- final Rect displayFrame = new Rect(displayFrames.mInsetsState.getDisplayFrame());
- displayFrame.inset(nonDecorInsets);
- return displayFrame;
- }
-
- /**
* Get the Navigation Bar Frame height. This dimension is the height of the navigation bar that
* is used for spacing to show additional buttons on the navigation bar (such as the ime
- * switcher when ime is visible) while {@link #getNavigationBarHeight} is used for the visible
- * height that we send to the app as content insets that can be smaller.
- * <p>
- * In car mode it will return the same height as {@link #getNavigationBarHeight}
+ * switcher when ime is visible).
*
* @param rotation specifies rotation to return dimension from
* @return navigation bar frame height
@@ -2092,26 +2031,6 @@
}
/**
- * Return the available screen size that we should report for the
- * configuration. This must be no larger than
- * {@link #getNonDecorDisplayFrame(int, int, int, DisplayCutout)}; it may be smaller
- * than that to account for more transient decoration like a status bar.
- */
- public Point getConfigDisplaySize(int fullWidth, int fullHeight, int rotation,
- WmDisplayCutout wmDisplayCutout) {
- final DisplayFrames displayFrames = getSimulatedDisplayFrames(rotation, fullWidth,
- fullHeight, wmDisplayCutout);
- return getConfigDisplaySizeWithSimulatedFrame(displayFrames);
- }
-
- Point getConfigDisplaySizeWithSimulatedFrame(DisplayFrames displayFrames) {
- final Insets insets = getInsetsWithInternalTypes(displayFrames, STABLE_TYPES);
- Rect configFrame = new Rect(displayFrames.mInsetsState.getDisplayFrame());
- configFrame.inset(insets);
- return new Point(configFrame.width(), configFrame.height());
- }
-
- /**
* Return corner radius in pixels that should be used on windows in order to cover the display.
*
* The radius is only valid for internal displays, since the corner radius of external displays
@@ -2126,89 +2045,150 @@
return mShowingDream;
}
- /**
- * Calculates the stable insets if we already have the non-decor insets.
- *
- * @param inOutInsets The known non-decor insets. It will be modified to stable insets.
- * @param rotation The current display rotation.
- */
- void convertNonDecorInsetsToStableInsets(Rect inOutInsets, int rotation) {
- inOutInsets.top = Math.max(inOutInsets.top, mStatusBarHeightForRotation[rotation]);
+ /** The latest insets and frames for screen configuration calculation. */
+ static class DecorInsets {
+ static class Info {
+ /**
+ * The insets for the areas that could never be removed, i.e. display cutout and
+ * navigation bar. Note that its meaning is actually "decor insets". The "non" is just
+ * because it is used to calculate {@link #mNonDecorFrame}.
+ */
+ final Rect mNonDecorInsets = new Rect();
+
+ /**
+ * The stable insets that can affect configuration. The sources are usually from
+ * display cutout, navigation bar, and status bar.
+ */
+ final Rect mConfigInsets = new Rect();
+
+ /** The display frame available after excluding {@link #mNonDecorInsets}. */
+ final Rect mNonDecorFrame = new Rect();
+
+ /**
+ * The available (stable) screen size that we should report for the configuration.
+ * This must be no larger than {@link #mNonDecorFrame}; it may be smaller than that
+ * to account for more transient decoration like a status bar.
+ */
+ final Rect mConfigFrame = new Rect();
+
+ private boolean mNeedUpdate = true;
+
+ void update(DisplayContent dc, int rotation, int w, int h) {
+ final DisplayFrames df = new DisplayFrames();
+ dc.updateDisplayFrames(df, rotation, w, h);
+ dc.getDisplayPolicy().simulateLayoutDisplay(df);
+ final InsetsState insetsState = df.mInsetsState;
+ final Rect displayFrame = insetsState.getDisplayFrame();
+ final Insets decor = calculateDecorInsetsWithInternalTypes(insetsState);
+ final Insets statusBar = insetsState.calculateInsets(displayFrame,
+ Type.statusBars(), true /* ignoreVisibility */);
+ mNonDecorInsets.set(decor.left, decor.top, decor.right, decor.bottom);
+ mConfigInsets.set(Math.max(statusBar.left, decor.left),
+ Math.max(statusBar.top, decor.top),
+ Math.max(statusBar.right, decor.right),
+ Math.max(statusBar.bottom, decor.bottom));
+ mNonDecorFrame.set(displayFrame);
+ mNonDecorFrame.inset(mNonDecorInsets);
+ mConfigFrame.set(displayFrame);
+ mConfigFrame.inset(mConfigInsets);
+ mNeedUpdate = false;
+ }
+
+ void set(Info other) {
+ mNonDecorInsets.set(other.mNonDecorInsets);
+ mConfigInsets.set(other.mConfigInsets);
+ mNonDecorFrame.set(other.mNonDecorFrame);
+ mConfigFrame.set(other.mConfigFrame);
+ mNeedUpdate = false;
+ }
+
+ @Override
+ public String toString() {
+ return "{nonDecorInsets=" + mNonDecorInsets
+ + ", configInsets=" + mConfigInsets
+ + ", nonDecorFrame=" + mNonDecorFrame
+ + ", configFrame=" + mConfigFrame + '}';
+ }
+ }
+
+ // TODO (b/235842600): Use public type once we can treat task bar as navigation bar.
+ static final int[] INTERNAL_DECOR_TYPES;
+ static {
+ final ArraySet<Integer> decorTypes = InsetsState.toInternalType(
+ Type.displayCutout() | Type.navigationBars());
+ decorTypes.remove(ITYPE_EXTRA_NAVIGATION_BAR);
+ INTERNAL_DECOR_TYPES = new int[decorTypes.size()];
+ for (int i = 0; i < INTERNAL_DECOR_TYPES.length; i++) {
+ INTERNAL_DECOR_TYPES[i] = decorTypes.valueAt(i);
+ }
+ }
+
+ private final DisplayContent mDisplayContent;
+ private final Info[] mInfoForRotation = new Info[4];
+ final Info mTmpInfo = new Info();
+
+ DecorInsets(DisplayContent dc) {
+ mDisplayContent = dc;
+ for (int i = mInfoForRotation.length - 1; i >= 0; i--) {
+ mInfoForRotation[i] = new Info();
+ }
+ }
+
+ Info get(int rotation, int w, int h) {
+ final Info info = mInfoForRotation[rotation];
+ if (info.mNeedUpdate) {
+ info.update(mDisplayContent, rotation, w, h);
+ }
+ return info;
+ }
+
+ /** Called when the screen decor insets providers have changed. */
+ void invalidate() {
+ for (Info info : mInfoForRotation) {
+ info.mNeedUpdate = true;
+ }
+ }
+
+ // TODO (b/235842600): Remove this method once we can treat task bar as navigation bar.
+ private static Insets calculateDecorInsetsWithInternalTypes(InsetsState state) {
+ final Rect frame = state.getDisplayFrame();
+ Insets insets = Insets.NONE;
+ for (int i = INTERNAL_DECOR_TYPES.length - 1; i >= 0; i--) {
+ final InsetsSource source = state.peekSource(INTERNAL_DECOR_TYPES[i]);
+ if (source != null) {
+ insets = Insets.max(source.calculateInsets(frame, true /* ignoreVisibility */),
+ insets);
+ }
+ }
+ return insets;
+ }
}
/**
- * Calculates the stable insets without running a layout.
- *
- * @param displayRotation the current display rotation
- * @param displayWidth full display width
- * @param displayHeight full display height
- * @param displayCutout the current display cutout
- * @param outInsets the insets to return
+ * If the decor insets changes, the display configuration may be affected. The caller should
+ * call {@link DisplayContent#sendNewConfiguration()} if this method returns {@code true}.
*/
- public void getStableInsetsLw(int displayRotation, int displayWidth, int displayHeight,
- WmDisplayCutout displayCutout, Rect outInsets) {
- final DisplayFrames displayFrames = getSimulatedDisplayFrames(displayRotation,
- displayWidth, displayHeight, displayCutout);
- getStableInsetsWithSimulatedFrame(displayFrames, outInsets);
+ boolean updateDecorInsetsInfoIfNeeded(WindowState win) {
+ if (!win.providesNonDecorInsets()) {
+ return false;
+ }
+ final DisplayFrames displayFrames = mDisplayContent.mDisplayFrames;
+ final int rotation = displayFrames.mRotation;
+ final int dw = displayFrames.mWidth;
+ final int dh = displayFrames.mHeight;
+ final DecorInsets.Info newInfo = mDecorInsets.mTmpInfo;
+ newInfo.update(mDisplayContent, rotation, dw, dh);
+ final DecorInsets.Info currentInfo = getDecorInsetsInfo(rotation, dw, dh);
+ if (newInfo.mNonDecorFrame.equals(currentInfo.mNonDecorFrame)) {
+ return false;
+ }
+ mDecorInsets.invalidate();
+ mDecorInsets.mInfoForRotation[rotation].set(newInfo);
+ return true;
}
- void getStableInsetsWithSimulatedFrame(DisplayFrames displayFrames, Rect outInsets) {
- // Navigation bar, status bar, and cutout.
- outInsets.set(getInsetsWithInternalTypes(displayFrames, STABLE_TYPES).toRect());
- }
-
- /**
- * Calculates the insets for the areas that could never be removed in Honeycomb, i.e. system
- * bar or button bar. See {@link #getNonDecorDisplayFrame}.
- *
- * @param displayRotation the current display rotation
- * @param fullWidth the width of the display, including all insets
- * @param fullHeight the height of the display, including all insets
- * @param cutout the current display cutout
- * @param outInsets the insets to return
- */
- public void getNonDecorInsetsLw(int displayRotation, int fullWidth, int fullHeight,
- WmDisplayCutout cutout, Rect outInsets) {
- final DisplayFrames displayFrames =
- getSimulatedDisplayFrames(displayRotation, fullWidth, fullHeight, cutout);
- getNonDecorInsetsWithSimulatedFrame(displayFrames, outInsets);
- }
-
- void getNonDecorInsetsWithSimulatedFrame(DisplayFrames displayFrames, Rect outInsets) {
- outInsets.set(getInsetsWithInternalTypes(displayFrames, NON_DECOR_TYPES).toRect());
- }
-
- DisplayFrames getSimulatedDisplayFrames(int displayRotation, int fullWidth,
- int fullHeight, WmDisplayCutout cutout) {
- final DisplayInfo info = new DisplayInfo(mDisplayContent.getDisplayInfo());
- info.rotation = displayRotation;
- info.logicalWidth = fullWidth;
- info.logicalHeight = fullHeight;
- info.displayCutout = cutout.getDisplayCutout();
- final RoundedCorners roundedCorners =
- mDisplayContent.calculateRoundedCornersForRotation(displayRotation);
- final PrivacyIndicatorBounds indicatorBounds =
- mDisplayContent.calculatePrivacyIndicatorBoundsForRotation(displayRotation);
- final DisplayFrames displayFrames = new DisplayFrames(getDisplayId(), new InsetsState(),
- info, cutout, roundedCorners, indicatorBounds);
- simulateLayoutDisplay(displayFrames);
- return displayFrames;
- }
-
- @VisibleForTesting
- Insets getInsets(DisplayFrames displayFrames, @InsetsType int type) {
- final InsetsState state = displayFrames.mInsetsState;
- final Insets insets = state.calculateInsets(state.getDisplayFrame(), type,
- true /* ignoreVisibility */);
- return insets;
- }
-
- Insets getInsetsWithInternalTypes(DisplayFrames displayFrames,
- @InternalInsetsType int[] types) {
- final InsetsState state = displayFrames.mInsetsState;
- final Insets insets = state.calculateInsetsWithInternalTypes(state.getDisplayFrame(), types,
- true /* ignoreVisibility */);
- return insets;
+ DecorInsets.Info getDecorInsetsInfo(int rotation, int w, int h) {
+ return mDecorInsets.get(rotation, w, h);
}
@NavigationBarPosition
@@ -2851,6 +2831,11 @@
pw.print(" mAllowLockscreenWhenOn="); pw.println(mAllowLockscreenWhenOn);
pw.print(prefix); pw.print("mRemoteInsetsControllerControlsSystemBars=");
pw.println(mDisplayContent.getInsetsPolicy().getRemoteInsetsControllerControlsSystemBars());
+ pw.print(prefix); pw.println("mDecorInsetsInfo:");
+ for (int rotation = 0; rotation < mDecorInsets.mInfoForRotation.length; rotation++) {
+ final DecorInsets.Info info = mDecorInsets.mInfoForRotation[rotation];
+ pw.println(prefixInner + Surface.rotationToString(rotation) + "=" + info);
+ }
mSystemGestures.dump(pw, prefix);
pw.print(prefix); pw.println("Looper state:");
diff --git a/services/core/java/com/android/server/wm/DisplayWindowSettings.java b/services/core/java/com/android/server/wm/DisplayWindowSettings.java
index 11bcd8c..c1b6496 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowSettings.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowSettings.java
@@ -150,7 +150,10 @@
final SettingsProvider.SettingsEntry overrideSettings =
mSettingsProvider.getOverrideSettings(displayInfo);
overrideSettings.mWindowingMode = mode;
- dc.setWindowingMode(mode);
+ final TaskDisplayArea defaultTda = dc.getDefaultTaskDisplayArea();
+ if (defaultTda != null) {
+ defaultTda.setWindowingMode(mode);
+ }
mSettingsProvider.updateOverrideSettings(displayInfo, overrideSettings);
}
@@ -253,8 +256,10 @@
// Setting windowing mode first, because it may override overscan values later.
final int windowingMode = getWindowingModeLocked(settings, dc);
- dc.setWindowingMode(windowingMode);
-
+ final TaskDisplayArea defaultTda = dc.getDefaultTaskDisplayArea();
+ if (defaultTda != null) {
+ defaultTda.setWindowingMode(windowingMode);
+ }
final int userRotationMode = settings.mUserRotationMode != null
? settings.mUserRotationMode : WindowManagerPolicy.USER_ROTATION_FREE;
final int userRotation = settings.mUserRotation != null
@@ -311,10 +316,11 @@
* changed.
*/
boolean updateSettingsForDisplay(DisplayContent dc) {
- if (dc.getWindowingMode() != getWindowingModeLocked(dc)) {
+ final TaskDisplayArea defaultTda = dc.getDefaultTaskDisplayArea();
+ if (defaultTda != null && defaultTda.getWindowingMode() != getWindowingModeLocked(dc)) {
// For the time being the only thing that may change is windowing mode, so just update
// that.
- dc.setWindowingMode(getWindowingModeLocked(dc));
+ defaultTda.setWindowingMode(getWindowingModeLocked(dc));
return true;
}
return false;
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index ed771c2..ac1fbc3 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -34,6 +34,7 @@
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.SparseArray;
+import android.view.InsetsSource;
import android.view.InsetsSourceControl;
import android.view.InsetsState;
import android.view.InsetsState.InternalInsetsType;
@@ -44,6 +45,7 @@
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.function.Consumer;
+import java.util.function.Function;
/**
* Manages global window inset state in the system represented by {@link InsetsState}.
@@ -86,8 +88,17 @@
}
};
+ private final Function<Integer, WindowContainerInsetsSourceProvider> mSourceProviderFunc;
+
InsetsStateController(DisplayContent displayContent) {
mDisplayContent = displayContent;
+ mSourceProviderFunc = type -> {
+ final InsetsSource source = mState.getSource(type);
+ if (type == ITYPE_IME) {
+ return new ImeInsetsSourceProvider(source, this, mDisplayContent);
+ }
+ return new WindowContainerInsetsSourceProvider(source, this, mDisplayContent);
+ };
}
InsetsState getRawInsetsState() {
@@ -115,15 +126,7 @@
* @return The provider of a specific type.
*/
WindowContainerInsetsSourceProvider getSourceProvider(@InternalInsetsType int type) {
- if (type == ITYPE_IME) {
- return mProviders.computeIfAbsent(type,
- key -> new ImeInsetsSourceProvider(
- mState.getSource(key), this, mDisplayContent));
- } else {
- return mProviders.computeIfAbsent(type,
- key -> new WindowContainerInsetsSourceProvider(mState.getSource(key), this,
- mDisplayContent));
- }
+ return mProviders.computeIfAbsent(type, mSourceProviderFunc);
}
ImeInsetsSourceProvider getImeSourceProvider() {
diff --git a/services/core/java/com/android/server/wm/SafeActivityOptions.java b/services/core/java/com/android/server/wm/SafeActivityOptions.java
index 2879e33..8bacacd 100644
--- a/services/core/java/com/android/server/wm/SafeActivityOptions.java
+++ b/services/core/java/com/android/server/wm/SafeActivityOptions.java
@@ -116,6 +116,34 @@
}
/**
+ * To ensure that two activities, one using this object, and the other using the
+ * SafeActivityOptions returned from this function, are launched into the same display through
+ * ActivityStartController#startActivities, all display-related information, i.e.
+ * displayAreaToken, launchDisplayId and callerDisplayId, are cloned.
+ */
+ @Nullable SafeActivityOptions selectiveCloneDisplayOptions() {
+ final ActivityOptions options = cloneLaunchingDisplayOptions(mOriginalOptions);
+ final ActivityOptions callerOptions = cloneLaunchingDisplayOptions(mCallerOptions);
+ if (options == null && callerOptions == null) {
+ return null;
+ }
+
+ final SafeActivityOptions safeOptions = new SafeActivityOptions(options,
+ mOriginalCallingPid, mOriginalCallingUid);
+ safeOptions.mCallerOptions = callerOptions;
+ safeOptions.mRealCallingPid = mRealCallingPid;
+ safeOptions.mRealCallingUid = mRealCallingUid;
+ return safeOptions;
+ }
+
+ private ActivityOptions cloneLaunchingDisplayOptions(ActivityOptions options) {
+ return options == null ? null : ActivityOptions.makeBasic()
+ .setLaunchTaskDisplayArea(options.getLaunchTaskDisplayArea())
+ .setLaunchDisplayId(options.getLaunchDisplayId())
+ .setCallerDisplayId((options.getCallerDisplayId()));
+ }
+
+ /**
* Overrides options with options from a caller and records {@link Binder#getCallingPid}/
* {@link Binder#getCallingUid}. Thus, calling identity MUST NOT be cleared when calling this
* method.
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 342ae57..91db278 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -1399,13 +1399,15 @@
/**
* Reorder the history task so that the passed activity is brought to the front.
+ * @return whether it was actually moved (vs already being top).
*/
- final void moveActivityToFrontLocked(ActivityRecord newTop) {
+ final boolean moveActivityToFrontLocked(ActivityRecord newTop) {
ProtoLog.i(WM_DEBUG_ADD_REMOVE, "Removing and adding activity %s to root task at top "
+ "callers=%s", newTop, Debug.getCallers(4));
-
+ int origDist = getDistanceFromTop(newTop);
positionChildAtTop(newTop);
updateEffectiveIntent();
+ return getDistanceFromTop(newTop) != origDist;
}
@Override
@@ -1613,14 +1615,14 @@
}
}
- ActivityRecord performClearTop(ActivityRecord newR, int launchFlags) {
+ ActivityRecord performClearTop(ActivityRecord newR, int launchFlags, int[] finishCount) {
// The task should be preserved for putting new activity in case the last activity is
// finished if it is normal launch mode and not single top ("clear-task-top").
mReuseTask = true;
mTaskSupervisor.beginDeferResume();
final ActivityRecord result;
try {
- result = clearTopActivities(newR, launchFlags);
+ result = clearTopActivities(newR, launchFlags, finishCount);
} finally {
mTaskSupervisor.endDeferResume();
mReuseTask = false;
@@ -1636,14 +1638,19 @@
* activities on top of it and return the instance.
*
* @param newR Description of the new activity being started.
+ * @param finishCount 1-element array that will be populated with the number of activities
+ * that have been finished.
* @return Returns the existing activity in the task that performs the clear-top operation,
* or {@code null} if none was found.
*/
- private ActivityRecord clearTopActivities(ActivityRecord newR, int launchFlags) {
- final ActivityRecord r = findActivityInHistory(newR.mActivityComponent);
+ private ActivityRecord clearTopActivities(ActivityRecord newR, int launchFlags,
+ int[] finishCount) {
+ final ActivityRecord r = findActivityInHistory(newR.mActivityComponent, newR.mUserId);
if (r == null) return null;
- final PooledPredicate f = PooledLambda.obtainPredicate(Task::finishActivityAbove,
+ final PooledPredicate f = PooledLambda.obtainPredicate(
+ (ActivityRecord ar, ActivityRecord boundaryActivity) ->
+ finishActivityAbove(ar, boundaryActivity, finishCount),
PooledLambda.__(ActivityRecord.class), r);
forAllActivities(f);
f.recycle();
@@ -1661,7 +1668,8 @@
return r;
}
- private static boolean finishActivityAbove(ActivityRecord r, ActivityRecord boundaryActivity) {
+ private static boolean finishActivityAbove(ActivityRecord r, ActivityRecord boundaryActivity,
+ @NonNull int[] finishCount) {
// Stop operation once we reach the boundary activity.
if (r == boundaryActivity) return true;
@@ -1672,6 +1680,7 @@
// TODO: Why is this updating the boundary activity vs. the current activity???
boundaryActivity.updateOptionsLocked(opts);
}
+ finishCount[0] += 1;
r.finishIfPossible("clear-task-stack", false /* oomAdj */);
}
@@ -1756,17 +1765,18 @@
* Find the activity in the history task within the given task. Returns
* the index within the history at which it's found, or < 0 if not found.
*/
- ActivityRecord findActivityInHistory(ComponentName component) {
+ ActivityRecord findActivityInHistory(ComponentName component, int userId) {
final PooledPredicate p = PooledLambda.obtainPredicate(Task::matchesActivityInHistory,
- PooledLambda.__(ActivityRecord.class), component);
+ PooledLambda.__(ActivityRecord.class), component, userId);
final ActivityRecord r = getActivity(p);
p.recycle();
return r;
}
private static boolean matchesActivityInHistory(
- ActivityRecord r, ComponentName activityComponent) {
- return !r.finishing && r.mActivityComponent.equals(activityComponent);
+ ActivityRecord r, ComponentName activityComponent, int userId) {
+ return !r.finishing && r.mActivityComponent.equals(activityComponent)
+ && r.mUserId == userId;
}
/** Updates the last task description values. */
@@ -4455,6 +4465,14 @@
// transferring the transform on the leash to the task, reset this state once we're
// moving out of pip
setCanAffectSystemUiFlags(true);
+ // Turn on userLeaveHint so other app can enter PiP mode.
+ mTaskSupervisor.mUserLeaving = true;
+ // Allow entering PiP from current top most activity when we are leaving PiP.
+ final Task topFocused = mRootWindowContainer.getTopDisplayFocusedRootTask();
+ if (topFocused != null) {
+ final ActivityRecord ar = topFocused.getTopResumedActivity();
+ enableEnterPipOnTaskSwitch(ar, null /* toFrontTask */, ar, null /* opts */);
+ }
mRootWindowContainer.notifyActivityPipModeChanged(this, null);
}
if (likelyResolvedMode == WINDOWING_MODE_PINNED) {
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index 0f46c4f..ff09163 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -172,6 +172,8 @@
*/
private final boolean mCanHostHomeTask;
+ private final Configuration mTempConfiguration = new Configuration();
+
TaskDisplayArea(DisplayContent displayContent, WindowManagerService service, String name,
int displayAreaFeature) {
this(displayContent, service, name, displayAreaFeature, false /* createdByOrganizer */,
@@ -1891,6 +1893,15 @@
}
@Override
+ public void setWindowingMode(int windowingMode) {
+ mTempConfiguration.setTo(getRequestedOverrideConfiguration());
+ WindowConfiguration tempRequestWindowConfiguration = mTempConfiguration.windowConfiguration;
+ tempRequestWindowConfiguration.setWindowingMode(windowingMode);
+ tempRequestWindowConfiguration.setDisplayWindowingMode(windowingMode);
+ onRequestedOverrideConfigurationChanged(mTempConfiguration);
+ }
+
+ @Override
TaskDisplayArea getTaskDisplayArea() {
return this;
}
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index da731e8..036a292 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -98,7 +98,6 @@
import com.android.internal.util.function.pooled.PooledPredicate;
import com.android.server.am.HostingRecord;
import com.android.server.pm.parsing.pkg.AndroidPackage;
-import com.android.server.wm.utils.WmDisplayCutout;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -298,10 +297,11 @@
final Point mLastSurfaceSize = new Point();
- private final Rect mTmpInsets = new Rect();
private final Rect mTmpBounds = new Rect();
private final Rect mTmpFullBounds = new Rect();
+ /** For calculating screenWidthDp and screenWidthDp, i.e. the area without the system bars. */
private final Rect mTmpStableBounds = new Rect();
+ /** For calculating app bounds, i.e. the area without the nav bar and display cutout. */
private final Rect mTmpNonDecorBounds = new Rect();
//TODO(b/207481538) Remove once the infrastructure to support per-activity screenshot is
@@ -2202,21 +2202,16 @@
DisplayInfo displayInfo) {
outNonDecorBounds.set(bounds);
outStableBounds.set(bounds);
- final Task rootTask = getRootTaskFragment().asTask();
- if (rootTask == null || rootTask.mDisplayContent == null) {
+ if (mDisplayContent == null) {
return;
}
mTmpBounds.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight);
- final DisplayPolicy policy = rootTask.mDisplayContent.getDisplayPolicy();
- final WmDisplayCutout cutout =
- rootTask.mDisplayContent.calculateDisplayCutoutForRotation(displayInfo.rotation);
- final DisplayFrames displayFrames = policy.getSimulatedDisplayFrames(displayInfo.rotation,
- displayInfo.logicalWidth, displayInfo.logicalHeight, cutout);
- policy.getNonDecorInsetsWithSimulatedFrame(displayFrames, mTmpInsets);
- intersectWithInsetsIfFits(outNonDecorBounds, mTmpBounds, mTmpInsets);
- policy.getStableInsetsWithSimulatedFrame(displayFrames, mTmpInsets);
- intersectWithInsetsIfFits(outStableBounds, mTmpBounds, mTmpInsets);
+ final DisplayPolicy policy = mDisplayContent.getDisplayPolicy();
+ final DisplayPolicy.DecorInsets.Info info = policy.getDecorInsetsInfo(
+ displayInfo.rotation, displayInfo.logicalWidth, displayInfo.logicalHeight);
+ intersectWithInsetsIfFits(outNonDecorBounds, mTmpBounds, info.mNonDecorInsets);
+ intersectWithInsetsIfFits(outStableBounds, mTmpBounds, info.mConfigInsets);
}
/**
@@ -2280,19 +2275,33 @@
super.onConfigurationChanged(newParentConfig);
- if (shouldStartChangeTransition(mTmpPrevBounds)) {
+ final boolean shouldStartChangeTransition = shouldStartChangeTransition(mTmpPrevBounds);
+ if (shouldStartChangeTransition) {
initializeChangeTransition(mTmpPrevBounds);
- } else if (mTaskFragmentOrganizer != null) {
- // Update the surface here instead of in the organizer so that we can make sure
- // it can be synced with the surface freezer.
- final SurfaceControl.Transaction t = getSyncTransaction();
- updateSurfacePosition(t);
- updateOrganizedTaskFragmentSurfaceSize(t, false /* forceUpdate */);
+ }
+ if (mTaskFragmentOrganizer != null) {
+ if (mTransitionController.isShellTransitionsEnabled()
+ && !mTransitionController.isCollecting(this)) {
+ // TaskFragmentOrganizer doesn't have access to the surface for security reasons, so
+ // update the surface here if it is not collected by Shell transition.
+ updateOrganizedTaskFragmentSurface();
+ } else if (!mTransitionController.isShellTransitionsEnabled()
+ && !shouldStartChangeTransition) {
+ // Update the surface here instead of in the organizer so that we can make sure
+ // it can be synced with the surface freezer for legacy app transition.
+ updateOrganizedTaskFragmentSurface();
+ }
}
sendTaskFragmentInfoChanged();
}
+ private void updateOrganizedTaskFragmentSurface() {
+ final SurfaceControl.Transaction t = getSyncTransaction();
+ updateSurfacePosition(t);
+ updateOrganizedTaskFragmentSurfaceSize(t, false /* forceUpdate */);
+ }
+
/** Updates the surface size so that the sub windows cannot be shown out of bounds. */
private void updateOrganizedTaskFragmentSurfaceSize(SurfaceControl.Transaction t,
boolean forceUpdate) {
@@ -2347,33 +2356,16 @@
|| endBounds.height() != startBounds.height();
}
- boolean canHaveEmbeddingActivityTransition(@NonNull ActivityRecord child) {
- if (!isOrganizedTaskFragment() || !mTransitionController.isShellTransitionsEnabled()) {
- return false;
- }
- // The activity should request open transition when it is becoming visible.
- return child.isVisibleRequested();
- }
-
- void collectEmbeddedTaskFragmentIfNeeded() {
- if (!isOrganizedTaskFragment() || mTransitionController.isCollecting(this)) {
- return;
- }
- if (getChildCount() == 0) {
- // The TaskFragment is new created, and just becoming non-empty.
- mTransitionController.collectExistenceChange(this);
- } else {
- mTransitionController.collect(this);
- }
+ @Override
+ boolean isSyncFinished() {
+ return super.isSyncFinished() && isReadyToTransit();
}
@Override
void setSurfaceControl(SurfaceControl sc) {
super.setSurfaceControl(sc);
if (mTaskFragmentOrganizer != null) {
- final SurfaceControl.Transaction t = getSyncTransaction();
- updateSurfacePosition(t);
- updateOrganizedTaskFragmentSurfaceSize(t, false /* forceUpdate */);
+ updateOrganizedTaskFragmentSurface();
// If the TaskFragmentOrganizer was set before we created the SurfaceControl, we need to
// emit the callbacks now.
sendTaskFragmentAppeared();
diff --git a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
index 8f07bb7..8e98cb7 100644
--- a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
+++ b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
@@ -137,7 +137,7 @@
final DisplayContent display = suggestedDisplayArea.mDisplayContent;
if (DEBUG) {
appendLog("display-id=" + display.getDisplayId()
- + " display-windowing-mode=" + display.getWindowingMode()
+ + " task-display-area-windowing-mode=" + suggestedDisplayArea.getWindowingMode()
+ " suggested-display-area=" + suggestedDisplayArea);
}
@@ -156,7 +156,7 @@
// source is a freeform window in a fullscreen display launching an activity on the same
// display.
if (launchMode == WINDOWING_MODE_UNDEFINED
- && canInheritWindowingModeFromSource(display, source)) {
+ && canInheritWindowingModeFromSource(display, suggestedDisplayArea, source)) {
// The source's windowing mode may be different from its task, e.g. activity is set
// to fullscreen and its task is pinned windowing mode when the activity is entering
// pip.
@@ -184,7 +184,8 @@
// is set with the suggestedDisplayArea. If it is set, but the eventual TaskDisplayArea is
// different, we should recalculating the bounds.
boolean hasInitialBoundsForSuggestedDisplayAreaInFreeformWindow = false;
- final boolean canApplyFreeformPolicy = canApplyFreeformWindowPolicy(display, launchMode);
+ final boolean canApplyFreeformPolicy =
+ canApplyFreeformWindowPolicy(suggestedDisplayArea, launchMode);
if (mSupervisor.canUseActivityOptionsLaunchBounds(options)
&& (canApplyFreeformPolicy || canApplyPipWindowPolicy(launchMode))) {
hasInitialBounds = true;
@@ -239,7 +240,8 @@
== display.getDisplayId())) {
// Only set windowing mode if display is in freeform. If the display is in fullscreen
// mode we should only launch a task in fullscreen mode.
- if (currentParams.hasWindowingMode() && display.inFreeformWindowingMode()) {
+ if (currentParams.hasWindowingMode()
+ && suggestedDisplayArea.inFreeformWindowingMode()) {
launchMode = currentParams.mWindowingMode;
fullyResolvedCurrentParam = launchMode != WINDOWING_MODE_FREEFORM;
if (DEBUG) {
@@ -267,11 +269,11 @@
// this step is to define the default policy when there is no initial bounds or a fully
// resolved current params from callers.
- // hasInitialBoundsForSuggestedDisplayAreaInFreeformDisplay is set if the outParams.mBounds
+ // hasInitialBoundsForSuggestedDisplayAreaInFreeformMode is set if the outParams.mBounds
// is set with the suggestedDisplayArea. If it is set, but the eventual TaskDisplayArea is
// different, we should recalcuating the bounds.
- boolean hasInitialBoundsForSuggestedDisplayAreaInFreeformDisplay = false;
- if (display.inFreeformWindowingMode()) {
+ boolean hasInitialBoundsForSuggestedDisplayAreaInFreeformMode = false;
+ if (suggestedDisplayArea.inFreeformWindowingMode()) {
if (launchMode == WINDOWING_MODE_PINNED) {
if (DEBUG) appendLog("picture-in-picture");
} else if (!root.isResizeable()) {
@@ -280,7 +282,7 @@
if (outParams.mBounds.isEmpty()) {
getTaskBounds(root, suggestedDisplayArea, layout, launchMode,
hasInitialBounds, outParams.mBounds);
- hasInitialBoundsForSuggestedDisplayAreaInFreeformDisplay = true;
+ hasInitialBoundsForSuggestedDisplayAreaInFreeformMode = true;
}
if (DEBUG) appendLog("unresizable-freeform");
} else {
@@ -290,10 +292,10 @@
}
}
} else {
- if (DEBUG) appendLog("non-freeform-display");
+ if (DEBUG) appendLog("non-freeform-task-display-area");
}
// If launch mode matches display windowing mode, let it inherit from display.
- outParams.mWindowingMode = launchMode == display.getWindowingMode()
+ outParams.mWindowingMode = launchMode == suggestedDisplayArea.getWindowingMode()
? WINDOWING_MODE_UNDEFINED : launchMode;
if (phase == PHASE_WINDOWING_MODE) {
@@ -303,7 +305,7 @@
// STEP 3: Finalize the display area. Here we allow WM shell route all launches that match
// certain criteria to specific task display areas.
final int resolvedMode = (launchMode != WINDOWING_MODE_UNDEFINED) ? launchMode
- : display.getWindowingMode();
+ : suggestedDisplayArea.getWindowingMode();
TaskDisplayArea taskDisplayArea = suggestedDisplayArea;
// If launch task display area is set in options we should just use it. We assume the
// suggestedDisplayArea has the right one in this case.
@@ -320,14 +322,17 @@
mTmpDisplayArea = displayArea;
return true;
});
- // We may need to recalculate the bounds if the new TaskDisplayArea is different from
- // the suggested one we used to calculate the bounds.
+ // We may need to recalculate the bounds and the windowing mode if the new
+ // TaskDisplayArea is different from the suggested one we used to calculate the two
+ // configurations.
if (mTmpDisplayArea != null && mTmpDisplayArea != suggestedDisplayArea) {
+ outParams.mWindowingMode = (launchMode == mTmpDisplayArea.getWindowingMode())
+ ? WINDOWING_MODE_UNDEFINED : launchMode;
if (hasInitialBoundsForSuggestedDisplayAreaInFreeformWindow) {
outParams.mBounds.setEmpty();
getLayoutBounds(mTmpDisplayArea, root, layout, outParams.mBounds);
hasInitialBounds = !outParams.mBounds.isEmpty();
- } else if (hasInitialBoundsForSuggestedDisplayAreaInFreeformDisplay) {
+ } else if (hasInitialBoundsForSuggestedDisplayAreaInFreeformMode) {
outParams.mBounds.setEmpty();
getTaskBounds(root, mTmpDisplayArea, layout, launchMode,
hasInitialBounds, outParams.mBounds);
@@ -519,7 +524,7 @@
}
private boolean canInheritWindowingModeFromSource(@NonNull DisplayContent display,
- @Nullable ActivityRecord source) {
+ TaskDisplayArea suggestedDisplayArea, @Nullable ActivityRecord source) {
if (source == null) {
return false;
}
@@ -527,7 +532,7 @@
// There is not really any strong reason to tie the launching windowing mode and the source
// on freeform displays. The launching windowing mode is more tied to the content of the new
// activities.
- if (display.inFreeformWindowingMode()) {
+ if (suggestedDisplayArea.inFreeformWindowingMode()) {
return false;
}
@@ -543,9 +548,11 @@
return display.getDisplayId() == source.getDisplayId();
}
- private boolean canApplyFreeformWindowPolicy(@NonNull DisplayContent display, int launchMode) {
+ private boolean canApplyFreeformWindowPolicy(@NonNull TaskDisplayArea suggestedDisplayArea,
+ int launchMode) {
return mSupervisor.mService.mSupportsFreeformWindowManagement
- && (display.inFreeformWindowingMode() || launchMode == WINDOWING_MODE_FREEFORM);
+ && (suggestedDisplayArea.inFreeformWindowingMode()
+ || launchMode == WINDOWING_MODE_FREEFORM);
}
private boolean canApplyPipWindowPolicy(int launchMode) {
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 8e389d3..6650f43 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -80,6 +80,7 @@
import android.util.ArraySet;
import android.util.Slog;
import android.util.SparseArray;
+import android.view.Display;
import android.view.SurfaceControl;
import android.view.WindowManager;
import android.view.animation.Animation;
@@ -92,11 +93,13 @@
import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.inputmethod.InputMethodManagerInternal;
+import com.android.server.wm.utils.RotationAnimationUtils;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
import java.util.function.Predicate;
/**
@@ -288,9 +291,9 @@
if (mContainerFreezer == null) {
mContainerFreezer = new ScreenshotFreezer();
}
- mIsSeamlessRotation = true;
final WindowState top = dc.getDisplayPolicy().getTopFullscreenOpaqueWindow();
if (top != null) {
+ mIsSeamlessRotation = true;
top.mSyncMethodOverride = BLASTSyncEngine.METHOD_BLAST;
ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "Override sync-method for %s "
+ "because seamless rotating", top.getName());
@@ -574,17 +577,16 @@
t.setLayer(targetLeash, target.getLastLayer());
target.getRelativePosition(tmpPos);
t.setPosition(targetLeash, tmpPos.x, tmpPos.y);
- final Rect clipRect;
// No need to clip the display in case seeing the clipped content when during the
// display rotation. No need to clip activities because they rely on clipping on
// task layers.
if (target.asDisplayContent() != null || target.asActivityRecord() != null) {
- clipRect = null;
+ t.setCrop(targetLeash, null /* crop */);
} else {
- clipRect = target.getRequestedOverrideBounds();
- clipRect.offset(-tmpPos.x, -tmpPos.y);
+ // Crop to the requested bounds.
+ final Rect clipRect = target.getRequestedOverrideBounds();
+ t.setWindowCrop(targetLeash, clipRect.width(), clipRect.height());
}
- t.setCrop(targetLeash, clipRect);
t.setCornerRadius(targetLeash, 0);
t.setShadowRadius(targetLeash, 0);
t.setMatrix(targetLeash, 1, 0, 0, 1);
@@ -706,7 +708,11 @@
// remove the surfaces yet. If it is currently visible, but not expected-visible,
// then doing commitVisibility here would actually be out-of-order and leave the
// activity in a bad state.
- if (!visibleAtTransitionEnd && !ar.isVisibleRequested()) {
+ // TODO (b/243755838) Create a screen off transition to correct the visible status
+ // of activities.
+ final boolean isScreenOff = ar.mDisplayContent == null
+ || ar.mDisplayContent.getDisplayInfo().state == Display.STATE_OFF;
+ if ((!visibleAtTransitionEnd || isScreenOff) && !ar.isVisibleRequested()) {
final boolean commitVisibility = !checkEnterPipOnFinish(ar);
// Avoid commit visibility if entering pip or else we will get a sudden
// "flash" / surface going invisible for a split second.
@@ -728,6 +734,10 @@
if (mChanges.get(ar).mVisible != visibleAtTransitionEnd) {
// Legacy dispatch relies on this (for now).
ar.mEnteringAnimation = visibleAtTransitionEnd;
+ } else if (mTransientLaunches != null && mTransientLaunches.containsKey(ar)
+ && ar.isVisible()) {
+ // Transient launch was committed, so report enteringAnimation
+ ar.mEnteringAnimation = true;
}
continue;
}
@@ -1630,6 +1640,9 @@
change.setEndAbsBounds(bounds);
}
change.setRotation(info.mRotation, endRotation);
+ if (info.mSnapshot != null) {
+ change.setSnapshot(info.mSnapshot, info.mSnapshotLuma);
+ }
out.addChange(change);
}
@@ -1785,6 +1798,10 @@
/** These are just extra info. They aren't used for change-detection. */
@Flag int mFlags = FLAG_NONE;
+ /** Snapshot surface and luma, if relevant. */
+ SurfaceControl mSnapshot;
+ float mSnapshotLuma;
+
ChangeInfo(@NonNull WindowContainer origState) {
mVisible = origState.isVisibleRequested();
mWindowingMode = origState.getWindowingMode();
@@ -2093,8 +2110,8 @@
*/
@VisibleForTesting
private class ScreenshotFreezer implements IContainerFreezer {
- /** Values are the screenshot "surfaces" or null if it was frozen via BLAST override. */
- private final ArrayMap<WindowContainer, SurfaceControl> mSnapshots = new ArrayMap<>();
+ /** Keeps track of which windows are frozen. Not all frozen windows have snapshots. */
+ private final ArraySet<WindowContainer> mFrozen = new ArraySet<>();
/** Takes a screenshot and puts it at the top of the container's surface. */
@Override
@@ -2104,7 +2121,7 @@
// Check if any parents have already been "frozen". If so, `wc` is already part of that
// snapshot, so just skip it.
for (WindowContainer p = wc; p != null; p = p.getParent()) {
- if (mSnapshots.containsKey(p)) return false;
+ if (mFrozen.contains(p)) return false;
}
if (mIsSeamlessRotation) {
@@ -2113,7 +2130,7 @@
if (top != null && (top == wc || top.isDescendantOf(wc))) {
// Don't use screenshots for seamless windows: these will use BLAST even if not
// BLAST mode.
- mSnapshots.put(wc, null);
+ mFrozen.add(wc);
return true;
}
}
@@ -2138,15 +2155,26 @@
Slog.w(TAG, "Failed to capture screenshot for " + wc);
return false;
}
+ final boolean isDisplayRotation = wc.asDisplayContent() != null
+ && wc.asDisplayContent().isRotationChanging();
+ // Some tests may check the name "RotationLayer" to detect display rotation.
+ final String name = isDisplayRotation ? "RotationLayer" : "transition snapshot: " + wc;
SurfaceControl snapshotSurface = wc.makeAnimationLeash()
- .setName("transition snapshot: " + wc.toString())
+ .setName(name)
.setOpaque(true)
.setParent(wc.getSurfaceControl())
.setSecure(screenshotBuffer.containsSecureLayers())
.setCallsite("Transition.ScreenshotSync")
.setBLASTLayer()
.build();
- mSnapshots.put(wc, snapshotSurface);
+ mFrozen.add(wc);
+ final ChangeInfo changeInfo = Objects.requireNonNull(mChanges.get(wc));
+ changeInfo.mSnapshot = snapshotSurface;
+ if (isDisplayRotation) {
+ // This isn't cheap, so only do it for display rotations.
+ changeInfo.mSnapshotLuma = RotationAnimationUtils.getMedianBorderLuma(
+ screenshotBuffer.getHardwareBuffer(), screenshotBuffer.getColorSpace());
+ }
SurfaceControl.Transaction t = wc.mWmService.mTransactionFactory.get();
t.setBuffer(snapshotSurface, buffer);
@@ -2167,11 +2195,12 @@
@Override
public void cleanUp(SurfaceControl.Transaction t) {
- for (int i = 0; i < mSnapshots.size(); ++i) {
- SurfaceControl snap = mSnapshots.valueAt(i);
+ for (int i = 0; i < mFrozen.size(); ++i) {
+ SurfaceControl snap =
+ Objects.requireNonNull(mChanges.get(mFrozen.valueAt(i))).mSnapshot;
// May be null if it was frozen via BLAST override.
if (snap == null) continue;
- t.remove(snap);
+ t.reparent(snap, null /* newParent */);
}
}
}
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index 23928ae..0d6532f 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -227,6 +227,14 @@
}
/**
+ * @return the collecting transition. {@code null} if there is no collecting transition.
+ */
+ @Nullable
+ Transition getCollectingTransition() {
+ return mCollectingTransition;
+ }
+
+ /**
* @return the collecting transition sync Id. This should only be called when there is a
* collecting transition.
*/
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 92e52de..979a6e5 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -1834,6 +1834,11 @@
return null;
}
+ int getDistanceFromTop(WindowContainer child) {
+ int idx = mChildren.indexOf(child);
+ return idx < 0 ? -1 : mChildren.size() - 1 - idx;
+ }
+
private ActivityRecord processGetActivityWithBoundary(Predicate<ActivityRecord> callback,
WindowContainer boundary, boolean includeBoundary, boolean traverseTopToBottom,
boolean[] boundaryFound, WindowContainer wc) {
@@ -2827,7 +2832,6 @@
void initializeChangeTransition(Rect startBounds, @Nullable SurfaceControl freezeTarget) {
if (mDisplayContent.mTransitionController.isShellTransitionsEnabled()) {
mDisplayContent.mTransitionController.collectVisibleChange(this);
- // TODO(b/207070762): request shell transition for activityEmbedding change.
return;
}
mDisplayContent.prepareAppTransition(TRANSIT_CHANGE);
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 6819833..66c962d 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -319,7 +319,6 @@
import com.android.server.policy.WindowManagerPolicy.ScreenOffListener;
import com.android.server.power.ShutdownThread;
import com.android.server.utils.PriorityDump;
-import com.android.server.wm.utils.WmDisplayCutout;
import dalvik.annotation.optimization.NeverCompile;
@@ -651,7 +650,7 @@
// Whether the system should use BLAST for ViewRootImpl
final boolean mUseBLAST;
// Whether to enable BLASTSyncEngine Transaction passing.
- final boolean mUseBLASTSync = true;
+ static final boolean USE_BLAST_SYNC = true;
final BLASTSyncEngine mSyncEngine;
@@ -1857,7 +1856,7 @@
+ ": window=%s Callers=%s", client.asBinder(), win, Debug.getCallers(5));
if ((win.isVisibleRequestedOrAdding() && displayContent.updateOrientation())
- || win.providesNonDecorInsets()) {
+ || displayPolicy.updateDecorInsetsInfoIfNeeded(win)) {
displayContent.sendNewConfiguration();
}
@@ -2254,7 +2253,7 @@
Arrays.fill(outActiveControls, null);
}
int result = 0;
- boolean configChanged;
+ boolean configChanged = false;
final int pid = Binder.getCallingPid();
final int uid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
@@ -2321,10 +2320,15 @@
flagChanges = win.mAttrs.flags ^ attrs.flags;
privateFlagChanges = win.mAttrs.privateFlags ^ attrs.privateFlags;
attrChanges = win.mAttrs.copyFrom(attrs);
- if ((attrChanges & (WindowManager.LayoutParams.LAYOUT_CHANGED
- | WindowManager.LayoutParams.SYSTEM_UI_VISIBILITY_CHANGED)) != 0) {
+ final boolean layoutChanged =
+ (attrChanges & WindowManager.LayoutParams.LAYOUT_CHANGED) != 0;
+ if (layoutChanged || (attrChanges
+ & WindowManager.LayoutParams.SYSTEM_UI_VISIBILITY_CHANGED) != 0) {
win.mLayoutNeeded = true;
}
+ if (layoutChanged) {
+ configChanged = displayPolicy.updateDecorInsetsInfoIfNeeded(win);
+ }
if (win.mActivityRecord != null && ((flagChanges & FLAG_SHOW_WHEN_LOCKED) != 0
|| (flagChanges & FLAG_DISMISS_KEYGUARD) != 0)) {
win.mActivityRecord.checkKeyguardFlagsChanged();
@@ -2534,7 +2538,7 @@
}
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "relayoutWindow: updateOrientation");
- configChanged = displayContent.updateOrientation();
+ configChanged |= displayContent.updateOrientation();
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
if (toBeDisplayed && win.mIsWallpaper) {
@@ -2572,7 +2576,7 @@
if (outSyncIdBundle != null) {
final int maybeSyncSeqId;
- if (mUseBLASTSync && win.useBLASTSync() && viewVisibility != View.GONE
+ if (USE_BLAST_SYNC && win.useBLASTSync() && viewVisibility == View.VISIBLE
&& win.mSyncSeqId > lastSyncSeqId) {
maybeSyncSeqId = win.shouldSyncWithBuffers() ? win.mSyncSeqId : -1;
win.markRedrawForSyncReported();
@@ -5655,7 +5659,7 @@
}
public boolean useBLASTSync() {
- return mUseBLASTSync;
+ return USE_BLAST_SYNC;
}
@Override
@@ -7177,9 +7181,8 @@
final DisplayContent dc = mRoot.getDisplayContent(displayId);
if (dc != null) {
final DisplayInfo di = dc.getDisplayInfo();
- final WmDisplayCutout cutout = dc.calculateDisplayCutoutForRotation(di.rotation);
- dc.getDisplayPolicy().getStableInsetsLw(di.rotation, di.logicalWidth, di.logicalHeight,
- cutout, outInsets);
+ outInsets.set(dc.getDisplayPolicy().getDecorInsetsInfo(
+ di.rotation, di.logicalWidth, di.logicalHeight).mConfigInsets);
}
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
index ff43a96..c22091b 100644
--- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
+++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
@@ -34,7 +34,6 @@
import android.graphics.Color;
import android.graphics.Point;
import android.graphics.Rect;
-import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.ShellCommand;
import android.os.UserHandle;
@@ -47,8 +46,6 @@
import com.android.internal.os.ByteTransferPipe;
import com.android.internal.protolog.ProtoLogImpl;
-import com.android.server.LocalServices;
-import com.android.server.statusbar.StatusBarManagerInternal;
import com.android.server.wm.LetterboxConfiguration.LetterboxBackgroundType;
import com.android.server.wm.LetterboxConfiguration.LetterboxHorizontalReachabilityPosition;
import com.android.server.wm.LetterboxConfiguration.LetterboxVerticalReachabilityPosition;
@@ -56,7 +53,6 @@
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
@@ -106,19 +102,11 @@
// trace files can be written.
return mInternal.mWindowTracing.onShellCommand(this);
case "logging":
- String[] args = peekRemainingArgs();
int result = ProtoLogImpl.getSingleInstance().onShellCommand(this);
if (result != 0) {
- // Let the shell try and handle this
- try (ParcelFileDescriptor pfd
- = ParcelFileDescriptor.dup(getOutFileDescriptor())){
- pw.println("Not handled, calling status bar with args: "
- + Arrays.toString(args));
- LocalServices.getService(StatusBarManagerInternal.class)
- .handleWindowManagerLoggingCommand(args, pfd);
- } catch (IOException e) {
- pw.println("Failed to handle logging command: " + e.getMessage());
- }
+ pw.println("Not handled, please use "
+ + "`adb shell dumpsys activity service SystemUIService WMShell` "
+ + "if you are looking for ProtoLog in WMShell");
}
return result;
case "user-rotation":
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index d34ad7d..9456f0f 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -21,7 +21,6 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOW_CONFIG_BOUNDS;
import static android.view.Display.DEFAULT_DISPLAY;
-import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_ADD_RECT_INSETS_PROVIDER;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT;
@@ -416,7 +415,10 @@
if (!shouldApplyIndependently) {
// Although there is an active sync, we want to apply the transaction now.
- if (!mTransitionController.isCollecting()) {
+ // TODO(b/232042367) Redesign the organizer update on activity callback so that we
+ // we will know about the transition explicitly.
+ final Transition transition = mTransitionController.getCollectingTransition();
+ if (transition == null) {
// This should rarely happen, and we should try to avoid using
// {@link #applySyncTransaction} with Shell transition.
// We still want to apply and merge the transaction to the active sync
@@ -426,8 +428,7 @@
+ " because there is an ongoing sync for"
+ " applySyncTransaction().");
}
- // TODO(b/207070762) make sure changes are all collected.
- applyTransaction(wct, -1 /* syncId */, null /* transition */, caller);
+ applyTransaction(wct, -1 /* syncId */, transition, caller);
return;
}
@@ -821,7 +822,8 @@
case HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT: {
final TaskFragmentCreationParams taskFragmentCreationOptions =
hop.getTaskFragmentCreationOptions();
- createTaskFragment(taskFragmentCreationOptions, errorCallbackToken, caller);
+ createTaskFragment(taskFragmentCreationOptions, errorCallbackToken, caller,
+ transition);
break;
}
case HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT: {
@@ -848,7 +850,8 @@
break;
}
}
- effects |= deleteTaskFragment(taskFragment, organizer, errorCallbackToken);
+ effects |= deleteTaskFragment(taskFragment, organizer, errorCallbackToken,
+ transition);
break;
}
case HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT: {
@@ -922,8 +925,15 @@
break;
}
- prepareActivityEmbeddingTransitionForReparentActivityToTaskFragment(parent,
- activity);
+ if (transition != null) {
+ transition.collect(activity);
+ if (activity.getParent() != null) {
+ // Collect the current parent. Its visibility may change as a result of
+ // this reparenting.
+ transition.collect(activity.getParent());
+ }
+ transition.collect(parent);
+ }
activity.reparent(parent, POSITION_TOP);
effects |= TRANSACT_EFFECTS_LIFECYCLE;
break;
@@ -1118,7 +1128,7 @@
break;
}
reparentTaskFragment(oldParent.asTaskFragment(), newParent, organizer,
- errorCallbackToken);
+ errorCallbackToken, transition);
effects |= TRANSACT_EFFECTS_LIFECYCLE;
break;
}
@@ -1162,41 +1172,6 @@
return effects;
}
- private void prepareActivityEmbeddingTransitionForReparentActivityToTaskFragment(
- @NonNull TaskFragment taskFragment, @NonNull ActivityRecord activity) {
- if (!taskFragment.canHaveEmbeddingActivityTransition(activity)) {
- return;
- }
-
- // The reparent can happen in the following cases:
- // 1. Reparent an existing activity to split when app launches new intent.
- // - This happens after app calls to start activity, but before the activity is actually
- // started, so we don't expect any collecting transition, but if it does, we can't
- // queue the WCT because the start activity won't wait.
- // 2. Reparent an existing activity to split to launch placeholder when Task size changed.
- // - We expect to have a collecting transition for the Task resize, so just collect.
- // 3. Reparent a new launching activity to an always-expand container.
- // 4. Reparent a new launching activity to split to launch placeholder together.
- // 5. Reparent a new launching activity to an existing split.
- // - The new launching activity should have start an OPEN transition, so just collect.
- // 6. Reparent PiP activity back to the original Task.
- // - This should be part of the exiting PiP transition, so just collect.
-
- if (!taskFragment.getBounds().equals(activity.getBounds()) && activity.isVisible()
- && !mTransitionController.isCollecting()) {
- // 1. Reparent an existing activity to split when app launches new intent.
- mTransitionController.requestTransitionIfNeeded(TRANSIT_CHANGE, activity);
- }
-
- // We expect the activity to be in the transition already, so just collect the TaskFragment.
- if (mTransitionController.isCollecting(activity)) {
- taskFragment.collectEmbeddedTaskFragmentIfNeeded();
- } else {
- ProtoLog.w(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "Reparenting Activity"
- + " to embedded TaskFragment, but the Activity is not collected");
- }
- }
-
/** A helper method to send minimum dimension violation error to the client. */
private void sendMinimumDimensionViolation(TaskFragment taskFragment, Point minDimensions,
IBinder errorCallbackToken, String reason) {
@@ -1773,8 +1748,9 @@
}
}
- void createTaskFragment(@NonNull TaskFragmentCreationParams creationParams,
- @Nullable IBinder errorCallbackToken, @NonNull CallerInfo caller) {
+ private void createTaskFragment(@NonNull TaskFragmentCreationParams creationParams,
+ @Nullable IBinder errorCallbackToken, @NonNull CallerInfo caller,
+ @Nullable Transition transition) {
final ActivityRecord ownerActivity =
ActivityRecord.forTokenLocked(creationParams.getOwnerToken());
final ITaskFragmentOrganizer organizer = ITaskFragmentOrganizer.Stub.asInterface(
@@ -1829,11 +1805,13 @@
taskFragment.setWindowingMode(creationParams.getWindowingMode());
taskFragment.setBounds(creationParams.getInitialBounds());
mLaunchTaskFragments.put(creationParams.getFragmentToken(), taskFragment);
+
+ if (transition != null) transition.collectExistenceChange(taskFragment);
}
- void reparentTaskFragment(@NonNull TaskFragment oldParent,
+ private void reparentTaskFragment(@NonNull TaskFragment oldParent,
@Nullable WindowContainer<?> newParent, @Nullable ITaskFragmentOrganizer organizer,
- @Nullable IBinder errorCallbackToken) {
+ @Nullable IBinder errorCallbackToken, @Nullable Transition transition) {
final TaskFragment newParentTF;
if (newParent == null) {
// Use the old parent's parent if the caller doesn't specify the new parent.
@@ -1875,13 +1853,24 @@
HIERARCHY_OP_TYPE_REPARENT_CHILDREN, exception);
return;
}
+ if (transition != null) {
+ // Collect the current parent. It's visibility may change as a result of this
+ // reparenting.
+ transition.collect(oldParent);
+ transition.collect(newParentTF);
+ }
while (oldParent.hasChild()) {
- oldParent.getChildAt(0).reparent(newParentTF, POSITION_TOP);
+ final WindowContainer child = oldParent.getChildAt(0);
+ if (transition != null) {
+ transition.collect(child);
+ }
+ child.reparent(newParentTF, POSITION_TOP);
}
}
private int deleteTaskFragment(@NonNull TaskFragment taskFragment,
- @Nullable ITaskFragmentOrganizer organizer, @Nullable IBinder errorCallbackToken) {
+ @Nullable ITaskFragmentOrganizer organizer, @Nullable IBinder errorCallbackToken,
+ @Nullable Transition transition) {
final int index = mLaunchTaskFragments.indexOfValue(taskFragment);
if (index < 0) {
final Throwable exception =
@@ -1901,6 +1890,9 @@
HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT, exception);
return 0;
}
+
+ if (transition != null) transition.collectExistenceChange(taskFragment);
+
mLaunchTaskFragments.removeAt(index);
taskFragment.remove(true /* withTransition */, "deleteTaskFragment");
return TRANSACT_EFFECTS_LIFECYCLE;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index b601cc5..fd18d3d 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2511,6 +2511,7 @@
mWinAnimator.mSurfaceController,
Debug.getCallers(5));
+ final DisplayContent displayContent = getDisplayContent();
final long origId = Binder.clearCallingIdentity();
try {
@@ -2565,7 +2566,7 @@
// Set up a replacement input channel since the app is now dead.
// We need to catch tapping on the dead window to restart the app.
openInputChannel(null);
- getDisplayContent().getInputMonitor().updateInputWindowsLw(true /*force*/);
+ displayContent.getInputMonitor().updateInputWindowsLw(true /*force*/);
return;
}
@@ -2573,7 +2574,7 @@
// usually unnoticeable (e.g. covered by rotation animation) and the animation
// bounds could be inconsistent, such as depending on when the window applies
// its draw transaction with new rotation.
- final boolean allowExitAnimation = !getDisplayContent().inTransition()
+ final boolean allowExitAnimation = !displayContent.inTransition()
// There will be a new window so the exit animation may not be visible or
// look weird if its orientation is changed.
&& !inRelaunchingActivity();
@@ -2623,18 +2624,11 @@
}
removeImmediately();
- boolean sentNewConfig = false;
- if (wasVisible) {
- // Removing a visible window will effect the computed orientation
- // So just update orientation if needed.
- final DisplayContent displayContent = getDisplayContent();
- if (displayContent.updateOrientation()) {
- displayContent.sendNewConfiguration();
- sentNewConfig = true;
- }
- }
- if (!sentNewConfig && providesNonDecorInsets()) {
- getDisplayContent().sendNewConfiguration();
+ // Removing a visible window may affect the display orientation so just update it if
+ // needed. Also recompute configuration if it provides screen decor insets.
+ if ((wasVisible && displayContent.updateOrientation())
+ || displayContent.getDisplayPolicy().updateDecorInsetsInfoIfNeeded(this)) {
+ displayContent.sendNewConfiguration();
}
mWmService.updateFocusedWindowLocked(isFocused()
? UPDATE_FOCUS_REMOVING_FOCUS
@@ -5965,10 +5959,10 @@
@Override
boolean isSyncFinished() {
- if (mSyncState == SYNC_STATE_WAITING_FOR_DRAW && mViewVisibility == View.GONE
+ if (mSyncState == SYNC_STATE_WAITING_FOR_DRAW && mViewVisibility != View.VISIBLE
&& !isVisibleRequested()) {
- // Don't wait for GONE windows. However, we don't alter the state in case the window
- // becomes un-gone while the syncset is still active.
+ // Don't wait for invisible windows. However, we don't alter the state in case the
+ // window becomes visible while the sync group is still active.
return true;
}
return super.isSyncFinished();
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index 72e7e65..8055590 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -16,7 +16,6 @@
package com.android.server.wm;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
@@ -631,12 +630,6 @@
getResolvedOverrideConfiguration().updateFrom(
mFixedRotationTransformState.mRotatedOverrideConfiguration);
}
- if (getTaskDisplayArea() == null) {
- // We only defined behaviors of system windows in fullscreen mode, i.e. windows not
- // contained in a task display area.
- getResolvedOverrideConfiguration().windowConfiguration.setWindowingMode(
- WINDOWING_MODE_FULLSCREEN);
- }
}
@Override
diff --git a/services/core/jni/com_android_server_companion_virtual_InputController.cpp b/services/core/jni/com_android_server_companion_virtual_InputController.cpp
index 8197b67..daca153 100644
--- a/services/core/jni/com_android_server_companion_virtual_InputController.cpp
+++ b/services/core/jni/com_android_server_companion_virtual_InputController.cpp
@@ -21,6 +21,7 @@
#include <android/keycodes.h>
#include <errno.h>
#include <fcntl.h>
+#include <input/Input.h>
#include <linux/uinput.h>
#include <math.h>
#include <nativehelper/JNIHelp.h>
@@ -271,6 +272,14 @@
ALOGE("Error creating touchscreen uinput pressure axis: %s", strerror(errno));
return -errno;
}
+ uinput_abs_setup slotAbsSetup;
+ slotAbsSetup.code = ABS_MT_SLOT;
+ slotAbsSetup.absinfo.maximum = MAX_POINTERS;
+ slotAbsSetup.absinfo.minimum = 0;
+ if (ioctl(fd, UI_ABS_SETUP, &slotAbsSetup) != 0) {
+ ALOGE("Error creating touchscreen uinput slots: %s", strerror(errno));
+ return -errno;
+ }
}
if (ioctl(fd, UI_DEV_SETUP, &setup) != 0) {
ALOGE("Error creating uinput device: %s", strerror(errno));
diff --git a/services/core/xsd/display-device-config/autobrightness.xsd b/services/core/xsd/display-device-config/autobrightness.xsd
deleted file mode 100644
index 477625a..0000000
--- a/services/core/xsd/display-device-config/autobrightness.xsd
+++ /dev/null
@@ -1,33 +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.
--->
-<xs:schema version="2.0"
- elementFormDefault="qualified"
- xmlns:xs="http://www.w3.org/2001/XMLSchema">
- <xs:complexType name="autoBrightness">
- <xs:sequence>
- <!-- Sets the debounce for autoBrightness brightening in millis-->
- <xs:element name="brighteningLightDebounceMillis" type="xs:nonNegativeInteger"
- minOccurs="0" maxOccurs="1">
- <xs:annotation name="final"/>
- </xs:element>
- <!-- Sets the debounce for autoBrightness darkening in millis-->
- <xs:element name="darkeningLightDebounceMillis" type="xs:nonNegativeInteger"
- minOccurs="0" maxOccurs="1">
- <xs:annotation name="final"/>
- </xs:element>
- </xs:sequence>
- </xs:complexType>
-</xs:schema>
\ No newline at end of file
diff --git a/services/core/xsd/display-device-config/display-device-config.xsd b/services/core/xsd/display-device-config/display-device-config.xsd
index bea5e2c..6b05d8f 100644
--- a/services/core/xsd/display-device-config/display-device-config.xsd
+++ b/services/core/xsd/display-device-config/display-device-config.xsd
@@ -23,7 +23,6 @@
<xs:schema version="2.0"
elementFormDefault="qualified"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
- <xs:include schemaLocation="autobrightness.xsd" />
<xs:element name="displayConfiguration">
<xs:complexType>
<xs:sequence>
@@ -343,4 +342,74 @@
<xs:annotation name="final"/>
</xs:element>
</xs:complexType>
+
+ <xs:complexType name="autoBrightness">
+ <xs:sequence>
+ <!-- Sets the debounce for autoBrightness brightening in millis-->
+ <xs:element name="brighteningLightDebounceMillis" type="xs:nonNegativeInteger"
+ minOccurs="0" maxOccurs="1">
+ <xs:annotation name="final"/>
+ </xs:element>
+ <!-- Sets the debounce for autoBrightness darkening in millis-->
+ <xs:element name="darkeningLightDebounceMillis" type="xs:nonNegativeInteger"
+ minOccurs="0" maxOccurs="1">
+ <xs:annotation name="final"/>
+ </xs:element>
+ <!-- Sets the brightness mapping of the desired screen brightness in nits to the
+ corresponding lux for the current display -->
+ <xs:element name="displayBrightnessMapping" type="displayBrightnessMapping"
+ minOccurs="0" maxOccurs="1">
+ <xs:annotation name="final"/>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+
+ <!-- Represents the brightness mapping of the desired screen brightness in nits to the
+ corresponding lux for the current display -->
+ <xs:complexType name="displayBrightnessMapping">
+ <xs:sequence>
+ <!-- Sets the list of display brightness points, each representing the desired screen
+ brightness in nits to the corresponding lux for the current display
+
+ The N entries of this array define N + 1 control points as follows:
+ (1-based arrays)
+
+ Point 1: (0, nits[1]): currentLux <= 0
+ Point 2: (lux[1], nits[2]): 0 < currentLux <= lux[1]
+ Point 3: (lux[2], nits[3]): lux[2] < currentLux <= lux[3]
+ ...
+ Point N+1: (lux[N], nits[N+1]): lux[N] < currentLux
+
+ The control points must be strictly increasing. Each control point
+ corresponds to an entry in the brightness backlight values arrays.
+ For example, if currentLux == lux[1] (first element of the levels array)
+ then the brightness will be determined by nits[2] (second element
+ of the brightness values array).
+ -->
+ <xs:element name="displayBrightnessPoint" type="displayBrightnessPoint"
+ minOccurs="1" maxOccurs="unbounded">
+ <xs:annotation name="final"/>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+
+ <!-- Represents a point in the display brightness mapping, representing the lux level from the
+ light sensor to the desired screen brightness in nits at this level -->
+ <xs:complexType name="displayBrightnessPoint">
+ <xs:sequence>
+ <!-- The lux level from the light sensor. This must be a non-negative integer -->
+ <xs:element name="lux" type="xs:nonNegativeInteger"
+ minOccurs="1" maxOccurs="1">
+ <xs:annotation name="final"/>
+ </xs:element>
+
+ <!-- Desired screen brightness in nits corresponding to the suggested lux values.
+ The display brightness is defined as the measured brightness of an all-white image.
+ This must be a non-negative integer -->
+ <xs:element name="nits" type="nonNegativeDecimal"
+ minOccurs="1" maxOccurs="1">
+ <xs:annotation name="final"/>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
</xs:schema>
diff --git a/services/core/xsd/display-device-config/schema/current.txt b/services/core/xsd/display-device-config/schema/current.txt
index e9a9269..fb7a920 100644
--- a/services/core/xsd/display-device-config/schema/current.txt
+++ b/services/core/xsd/display-device-config/schema/current.txt
@@ -5,8 +5,10 @@
ctor public AutoBrightness();
method public final java.math.BigInteger getBrighteningLightDebounceMillis();
method public final java.math.BigInteger getDarkeningLightDebounceMillis();
+ method public final com.android.server.display.config.DisplayBrightnessMapping getDisplayBrightnessMapping();
method public final void setBrighteningLightDebounceMillis(java.math.BigInteger);
method public final void setDarkeningLightDebounceMillis(java.math.BigInteger);
+ method public final void setDisplayBrightnessMapping(com.android.server.display.config.DisplayBrightnessMapping);
}
public class BrightnessThresholds {
@@ -43,6 +45,19 @@
method public java.util.List<com.android.server.display.config.Density> getDensity();
}
+ public class DisplayBrightnessMapping {
+ ctor public DisplayBrightnessMapping();
+ method public final java.util.List<com.android.server.display.config.DisplayBrightnessPoint> getDisplayBrightnessPoint();
+ }
+
+ public class DisplayBrightnessPoint {
+ ctor public DisplayBrightnessPoint();
+ method public final java.math.BigInteger getLux();
+ method public final java.math.BigDecimal getNits();
+ method public final void setLux(java.math.BigInteger);
+ method public final void setNits(java.math.BigDecimal);
+ }
+
public class DisplayConfiguration {
ctor public DisplayConfiguration();
method @NonNull public final com.android.server.display.config.Thresholds getAmbientBrightnessChangeThresholds();
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 06fb4b0..6aca14f0 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -8178,7 +8178,8 @@
}
final CallerIdentity caller = getCallerIdentity(who);
- Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle));
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle)
+ || isCameraServerUid(caller));
if (parent) {
Preconditions.checkCallAuthorization(
@@ -9689,6 +9690,10 @@
return UserHandle.isSameApp(caller.getUid(), Process.SHELL_UID);
}
+ private boolean isCameraServerUid(CallerIdentity caller) {
+ return UserHandle.isSameApp(caller.getUid(), Process.CAMERASERVER_UID);
+ }
+
private @UserIdInt int getCurrentForegroundUserId() {
try {
UserInfo currentUser = mInjector.getIActivityManager().getCurrentUser();
diff --git a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
index d322290..f05b1d4 100644
--- a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
+++ b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
@@ -205,6 +205,7 @@
.setRequiresDeviceIdle(true)
.setRequiresCharging(true)
.setPeriodic(BG_PROCESS_PERIOD)
+ .setPriority(JobInfo.PRIORITY_MIN)
.build());
}
@@ -217,6 +218,9 @@
BackgroundThread.get().getThreadHandler().post(
() -> {
try {
+ if (sSelfService.mIProfcollect == null) {
+ return;
+ }
sSelfService.mIProfcollect.process();
} catch (RemoteException e) {
Log.e(LOG_TAG, "Failed to process profiles in background: "
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
index 617321b..9c615d1 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
@@ -149,6 +149,12 @@
.thenReturn(mockArray);
when(mMockedResources.obtainTypedArray(R.array.config_roundedCornerBottomRadiusArray))
.thenReturn(mockArray);
+ when(mMockedResources.obtainTypedArray(
+ com.android.internal.R.array.config_autoBrightnessDisplayValuesNits))
+ .thenReturn(mockArray);
+ when(mMockedResources.getIntArray(
+ com.android.internal.R.array.config_autoBrightnessLevels))
+ .thenReturn(new int[]{});
}
@After
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index 0483a60..7ae70eb 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -147,6 +147,19 @@
android:resource="@xml/test_dream_metadata" />
</service>
+ <service
+ android:name="com.android.server.dreams.TestDreamServiceWithInvalidSettings"
+ android:exported="false"
+ android:label="Test Dream" >
+ <intent-filter>
+ <action android:name="android.service.dreams.DreamService" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ <meta-data
+ android:name="android.service.dream"
+ android:resource="@xml/test_dream_metadata_invalid" />
+ </service>
+
<receiver android:name="com.android.server.devicepolicy.ApplicationRestrictionsTest$AdminReceiver"
android:permission="android.permission.BIND_DEVICE_ADMIN"
android:exported="true">
diff --git a/services/tests/servicestests/res/xml/test_dream_metadata.xml b/services/tests/servicestests/res/xml/test_dream_metadata.xml
index aa054f1..9905c69 100644
--- a/services/tests/servicestests/res/xml/test_dream_metadata.xml
+++ b/services/tests/servicestests/res/xml/test_dream_metadata.xml
@@ -15,5 +15,5 @@
-->
<dream xmlns:android="http://schemas.android.com/apk/res/android"
- android:settingsActivity="com.android.server.dreams/.TestDreamSettingsActivity"
+ android:settingsActivity="com.android.frameworks.servicestests/.TestDreamSettingsActivity"
android:showClockAndComplications="false" />
diff --git a/services/tests/servicestests/res/xml/test_dream_metadata_invalid.xml b/services/tests/servicestests/res/xml/test_dream_metadata_invalid.xml
new file mode 100644
index 0000000..47864d9
--- /dev/null
+++ b/services/tests/servicestests/res/xml/test_dream_metadata_invalid.xml
@@ -0,0 +1,20 @@
+<!--
+ ~ 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.
+ -->
+
+<!-- The settings activity is in a different package, which is invalid -->
+<dream xmlns:android="http://schemas.android.com/apk/res/android"
+ android:settingsActivity="com.android.server.dreams/.TestDreamSettingsActivity"
+ android:showClockAndComplications="false"/>
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 db12092..1508055 100644
--- a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
@@ -179,6 +179,11 @@
doNothing().when(mInjector).taskSupervisorRemoveUser(anyInt());
// All UserController params are set to default.
mUserController = new UserController(mInjector);
+
+ // TODO(b/232452368): need to explicitly call setAllowUserUnlocking(), otherwise most
+ // tests would fail. But we might need to disable it for the onBootComplete() test (i.e,
+ // to make sure the users are unlocked at the right time)
+ mUserController.setAllowUserUnlocking(true);
setUpUser(TEST_USER_ID, NO_USERINFO_FLAGS);
setUpUser(TEST_PRE_CREATED_USER_ID, NO_USERINFO_FLAGS, /* preCreated=*/ true, null);
});
@@ -600,6 +605,16 @@
}
@Test
+ public void testUserNotUnlockedBeforeAllowed() throws Exception {
+ mUserController.setAllowUserUnlocking(false);
+
+ mUserController.startUser(TEST_USER_ID, /* foreground= */ false);
+
+ verify(mInjector.mStorageManagerMock, never())
+ .unlockUserKey(eq(TEST_USER_ID), anyInt(), any());
+ }
+
+ @Test
public void testStartProfile_fullUserFails() {
setUpUser(TEST_USER_ID1, 0);
assertThrows(IllegalArgumentException.class,
diff --git a/services/tests/servicestests/src/com/android/server/audio/SpatializerHelperTest.java b/services/tests/servicestests/src/com/android/server/audio/SpatializerHelperTest.java
index b17c3a1..428eaff 100644
--- a/services/tests/servicestests/src/com/android/server/audio/SpatializerHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/audio/SpatializerHelperTest.java
@@ -55,14 +55,20 @@
mMockAudioService = mock(AudioService.class);
mSpyAudioSystem = spy(new NoOpAudioSystemAdapter());
- mSpatHelper = new SpatializerHelper(mMockAudioService, mSpyAudioSystem);
+ mSpatHelper = new SpatializerHelper(mMockAudioService, mSpyAudioSystem,
+ false /*headTrackingEnabledByDefault*/);
}
+ /**
+ * Test that constructing an SADeviceState instance requires a non-null address for a
+ * wireless type, but can take null for a non-wireless type;
+ * @throws Exception
+ */
@Test
public void testSADeviceStateNullAddressCtor() throws Exception {
try {
- SADeviceState devState = new SADeviceState(
- AudioDeviceInfo.TYPE_BUILTIN_SPEAKER, null);
+ SADeviceState devState = new SADeviceState(AudioDeviceInfo.TYPE_BUILTIN_SPEAKER, null);
+ devState = new SADeviceState(AudioDeviceInfo.TYPE_BLUETOOTH_A2DP, null);
Assert.fail();
} catch (NullPointerException e) { }
}
@@ -88,11 +94,12 @@
final AudioDeviceAttributes dev1 =
new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_SPEAKER, "");
final AudioDeviceAttributes dev2 =
- new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, "C3:P0:beep");
+ new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, "C3:PO:beep");
final AudioDeviceAttributes dev3 =
new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, "R2:D2:bloop");
doNothing().when(mMockAudioService).persistSpatialAudioDeviceSettings();
+ mSpatHelper.initForTest(true /*binaural*/, true /*transaural*/);
// test with single device
mSpatHelper.addCompatibleAudioDevice(dev1);
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java
index 92e1f27a..837b553 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java
@@ -16,6 +16,8 @@
package com.android.server.biometrics.sensors.fingerprint.aidl;
+import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_POWER_PRESSED;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -253,6 +255,16 @@
showHideOverlay(c -> c.onEnrollResult(new Fingerprint("", 1, 1), 0));
}
+ @Test
+ public void testPowerPressForwardsAcquireMessage() throws RemoteException {
+ final FingerprintEnrollClient client = createClient();
+ client.start(mCallback);
+ client.onPowerPressed();
+
+ verify(mClientMonitorCallbackConverter).onAcquired(anyInt(),
+ eq(FINGERPRINT_ACQUIRED_POWER_PRESSED), anyInt());
+ }
+
private void showHideOverlay(Consumer<FingerprintEnrollClient> block)
throws RemoteException {
final FingerprintEnrollClient client = createClient();
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java
index 03ea613..66420ad 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java
@@ -19,16 +19,19 @@
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.anyFloat;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.res.Resources;
+import android.content.res.TypedArray;
import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -52,22 +55,16 @@
private Resources mResources;
@Before
- public void setUp() throws IOException {
+ public void setUp() {
MockitoAnnotations.initMocks(this);
when(mContext.getResources()).thenReturn(mResources);
mockDeviceConfigs();
- try {
- Path tempFile = Files.createTempFile("display_config", ".tmp");
- Files.write(tempFile, getContent().getBytes(StandardCharsets.UTF_8));
- mDisplayDeviceConfig = new DisplayDeviceConfig(mContext);
- mDisplayDeviceConfig.initFromFile(tempFile.toFile());
- } catch (IOException e) {
- throw new IOException("Failed to setup the display device config.", e);
- }
}
@Test
- public void testConfigValues() {
+ public void testConfigValuesFromDisplayConfig() throws IOException {
+ setupDisplayDeviceConfigFromDisplayConfigFile();
+
assertEquals(mDisplayDeviceConfig.getAmbientHorizonLong(), 5000);
assertEquals(mDisplayDeviceConfig.getAmbientHorizonShort(), 50);
assertEquals(mDisplayDeviceConfig.getBrightnessRampDecreaseMaxMillis(), 3000);
@@ -88,10 +85,23 @@
assertEquals(mDisplayDeviceConfig.getScreenDarkeningMinThreshold(), 0.002, 0.000001f);
assertEquals(mDisplayDeviceConfig.getAutoBrightnessBrighteningLightDebounce(), 2000);
assertEquals(mDisplayDeviceConfig.getAutoBrightnessDarkeningLightDebounce(), 1000);
-
+ assertArrayEquals(mDisplayDeviceConfig.getAutoBrightnessBrighteningLevelsLux(), new
+ float[]{0.0f, 50.0f, 80.0f}, 0.0f);
+ assertArrayEquals(mDisplayDeviceConfig.getAutoBrightnessBrighteningLevelsNits(), new
+ float[]{45.32f, 75.43f}, 0.0f);
// Todo(brup): Add asserts for BrightnessThrottlingData, DensityMapping,
// HighBrightnessModeData AmbientLightSensor, RefreshRateLimitations and ProximitySensor.
- // Also add test for the case where optional display configs are null
+ }
+
+ @Test
+ public void testConfigValuesFromConfigResource() {
+ setupDisplayDeviceConfigFromConfigResourceFile();
+ assertArrayEquals(mDisplayDeviceConfig.getAutoBrightnessBrighteningLevelsNits(), new
+ float[]{2.0f, 200.0f, 600.0f}, 0.0f);
+ assertArrayEquals(mDisplayDeviceConfig.getAutoBrightnessBrighteningLevelsLux(), new
+ float[]{0.0f, 0.0f, 110.0f, 500.0f}, 0.0f);
+ // Todo(brup): Add asserts for BrightnessThrottlingData, DensityMapping,
+ // HighBrightnessModeData AmbientLightSensor, RefreshRateLimitations and ProximitySensor.
}
private String getContent() {
@@ -114,6 +124,16 @@
+ "<autoBrightness>\n"
+ "<brighteningLightDebounceMillis>2000</brighteningLightDebounceMillis>\n"
+ "<darkeningLightDebounceMillis>1000</darkeningLightDebounceMillis>\n"
+ + "<displayBrightnessMapping>\n"
+ + "<displayBrightnessPoint>\n"
+ + "<lux>50</lux>\n"
+ + "<nits>45.32</nits>\n"
+ + "</displayBrightnessPoint>\n"
+ + "<displayBrightnessPoint>\n"
+ + "<lux>80</lux>\n"
+ + "<nits>75.43</nits>\n"
+ + "</displayBrightnessPoint>\n"
+ + "</displayBrightnessMapping>\n"
+ "</autoBrightness>\n"
+ "<highBrightnessMode enabled=\"true\">\n"
+ "<transitionPoint>0.62</transitionPoint>\n"
@@ -185,4 +205,63 @@
when(mResources.getFloat(com.android.internal.R.dimen
.config_screenBrightnessSettingMaximumFloat)).thenReturn(1.0f);
}
+
+ private void setupDisplayDeviceConfigFromDisplayConfigFile() throws IOException {
+ Path tempFile = Files.createTempFile("display_config", ".tmp");
+ Files.write(tempFile, getContent().getBytes(StandardCharsets.UTF_8));
+ mDisplayDeviceConfig = new DisplayDeviceConfig(mContext);
+ mDisplayDeviceConfig.initFromFile(tempFile.toFile());
+ }
+
+ private void setupDisplayDeviceConfigFromConfigResourceFile() {
+ TypedArray screenBrightnessNits = createFloatTypedArray(new float[]{2.0f, 250.0f, 650.0f});
+ when(mResources.obtainTypedArray(
+ com.android.internal.R.array.config_screenBrightnessNits))
+ .thenReturn(screenBrightnessNits);
+ TypedArray screenBrightnessBacklight = createFloatTypedArray(new
+ float[]{0.0f, 120.0f, 255.0f});
+ when(mResources.obtainTypedArray(
+ com.android.internal.R.array.config_screenBrightnessBacklight))
+ .thenReturn(screenBrightnessBacklight);
+ when(mResources.getIntArray(com.android.internal.R.array
+ .config_screenBrightnessBacklight)).thenReturn(new int[]{0, 120, 255});
+
+ when(mResources.getIntArray(com.android.internal.R.array
+ .config_autoBrightnessLevels)).thenReturn(new int[]{30, 80});
+ when(mResources.getIntArray(com.android.internal.R.array
+ .config_autoBrightnessDisplayValuesNits)).thenReturn(new int[]{25, 55});
+
+ TypedArray screenBrightnessLevelNits = createFloatTypedArray(new
+ float[]{2.0f, 200.0f, 600.0f});
+ when(mResources.obtainTypedArray(
+ com.android.internal.R.array.config_autoBrightnessDisplayValuesNits))
+ .thenReturn(screenBrightnessLevelNits);
+ int[] screenBrightnessLevelLux = new int[]{0, 110, 500};
+ when(mResources.getIntArray(
+ com.android.internal.R.array.config_autoBrightnessLevels))
+ .thenReturn(screenBrightnessLevelLux);
+
+ mDisplayDeviceConfig = DisplayDeviceConfig.create(mContext, true);
+
+ }
+
+ private TypedArray createFloatTypedArray(float[] vals) {
+ TypedArray mockArray = mock(TypedArray.class);
+ when(mockArray.length()).thenAnswer(invocation -> {
+ return vals.length;
+ });
+ when(mockArray.getFloat(anyInt(), anyFloat())).thenAnswer(invocation -> {
+ final float def = (float) invocation.getArguments()[1];
+ if (vals == null) {
+ return def;
+ }
+ int idx = (int) invocation.getArguments()[0];
+ if (idx >= 0 && idx < vals.length) {
+ return vals[idx];
+ } else {
+ return def;
+ }
+ });
+ return mockArray;
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/dreams/DreamServiceTest.java b/services/tests/servicestests/src/com/android/server/dreams/DreamServiceTest.java
index 74d2e0f..0efd296 100644
--- a/services/tests/servicestests/src/com/android/server/dreams/DreamServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/dreams/DreamServiceTest.java
@@ -16,7 +16,8 @@
package com.android.server.dreams;
-import static org.junit.Assert.assertEquals;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.junit.Assert.assertFalse;
import android.content.ComponentName;
@@ -35,21 +36,36 @@
@SmallTest
@RunWith(AndroidJUnit4.class)
public class DreamServiceTest {
+ private static final String TEST_PACKAGE_NAME = "com.android.frameworks.servicestests";
+
@Test
public void testMetadataParsing() throws PackageManager.NameNotFoundException {
- final String testPackageName = "com.android.frameworks.servicestests";
final String testDreamClassName = "com.android.server.dreams.TestDreamService";
- final String testSettingsActivity = "com.android.server.dreams/.TestDreamSettingsActivity";
+ final String testSettingsActivity =
+ "com.android.frameworks.servicestests/.TestDreamSettingsActivity";
+ final DreamService.DreamMetadata metadata = getDreamMetadata(testDreamClassName);
- final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
-
- final ServiceInfo si = context.getPackageManager().getServiceInfo(
- new ComponentName(testPackageName, testDreamClassName),
- PackageManager.ComponentInfoFlags.of(PackageManager.GET_META_DATA));
- final DreamService.DreamMetadata metadata = DreamService.getDreamMetadata(context, si);
-
- assertEquals(0, metadata.settingsActivity.compareTo(
- ComponentName.unflattenFromString(testSettingsActivity)));
+ assertThat(metadata.settingsActivity).isEqualTo(
+ ComponentName.unflattenFromString(testSettingsActivity));
assertFalse(metadata.showComplications);
}
+
+ @Test
+ public void testMetadataParsing_invalidSettingsActivity()
+ throws PackageManager.NameNotFoundException {
+ final String testDreamClassName =
+ "com.android.server.dreams.TestDreamServiceWithInvalidSettings";
+ final DreamService.DreamMetadata metadata = getDreamMetadata(testDreamClassName);
+
+ assertThat(metadata.settingsActivity).isNull();
+ }
+
+ private DreamService.DreamMetadata getDreamMetadata(String dreamClassName)
+ throws PackageManager.NameNotFoundException {
+ final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ final ServiceInfo si = context.getPackageManager().getServiceInfo(
+ new ComponentName(TEST_PACKAGE_NAME, dreamClassName),
+ PackageManager.ComponentInfoFlags.of(PackageManager.GET_META_DATA));
+ return DreamService.getDreamMetadata(context, si);
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeConstants.java b/services/tests/servicestests/src/com/android/server/dreams/TestDreamServiceWithInvalidSettings.java
similarity index 62%
rename from libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeConstants.java
rename to services/tests/servicestests/src/com/android/server/dreams/TestDreamServiceWithInvalidSettings.java
index e62a63a..5c7d02f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeConstants.java
+++ b/services/tests/servicestests/src/com/android/server/dreams/TestDreamServiceWithInvalidSettings.java
@@ -14,18 +14,12 @@
* limitations under the License.
*/
-package com.android.wm.shell.desktopmode;
+package com.android.server.dreams;
-import android.os.SystemProperties;
+import android.service.dreams.DreamService;
/**
- * Constants for desktop mode feature
+ * Dream service implementation for unit testing, where the settings activity is invalid.
*/
-public class DesktopModeConstants {
-
- /**
- * Flag to indicate whether desktop mode is available on the device
- */
- public static final boolean IS_FEATURE_ENABLED = SystemProperties.getBoolean(
- "persist.wm.debug.desktop_mode", false);
+public class TestDreamServiceWithInvalidSettings extends DreamService {
}
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java
index 4ef6530..aafbb11 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java
@@ -66,12 +66,15 @@
import android.os.vibrator.VibrationConfig;
import android.platform.test.annotations.Presubmit;
import android.provider.Settings;
+import android.util.ArraySet;
+import android.view.Display;
import androidx.test.InstrumentationRegistry;
import com.android.internal.util.test.FakeSettingsProvider;
import com.android.internal.util.test.FakeSettingsProviderRule;
import com.android.server.LocalServices;
+import com.android.server.companion.virtual.VirtualDeviceManagerInternal;
import org.junit.After;
import org.junit.Before;
@@ -95,6 +98,7 @@
public class VibrationSettingsTest {
private static final int UID = 1;
+ private static final int VIRTUAL_DISPLAY_ID = 1;
private static final String SYSUI_PACKAGE_NAME = "sysui";
private static final PowerSaveState NORMAL_POWER_STATE = new PowerSaveState.Builder().build();
private static final PowerSaveState LOW_POWER_STATE = new PowerSaveState.Builder()
@@ -117,15 +121,23 @@
@Rule public FakeSettingsProviderRule mSettingsProviderRule = FakeSettingsProvider.rule();
@Mock private VibrationSettings.OnVibratorSettingsChanged mListenerMock;
- @Mock private PowerManagerInternal mPowerManagerInternalMock;
- @Mock private PackageManagerInternal mPackageManagerInternalMock;
- @Mock private VibrationConfig mVibrationConfigMock;
+ @Mock
+ private PowerManagerInternal mPowerManagerInternalMock;
+ @Mock
+ private VirtualDeviceManagerInternal mVirtualDeviceManagerInternalMock;
+ @Mock
+ private PackageManagerInternal mPackageManagerInternalMock;
+ @Mock
+ private VibrationConfig mVibrationConfigMock;
private TestLooper mTestLooper;
private ContextWrapper mContextSpy;
private AudioManager mAudioManager;
private VibrationSettings mVibrationSettings;
private PowerManagerInternal.LowPowerModeListener mRegisteredPowerModeListener;
+ private VirtualDeviceManagerInternal.VirtualDisplayListener mRegisteredVirtualDisplayListener;
+ private VirtualDeviceManagerInternal.AppsOnVirtualDeviceListener
+ mRegisteredAppsOnVirtualDeviceListener;
@Before
public void setUp() throws Exception {
@@ -140,11 +152,17 @@
}).when(mPowerManagerInternalMock).registerLowPowerModeObserver(any());
when(mPackageManagerInternalMock.getSystemUiServiceComponent())
.thenReturn(new ComponentName(SYSUI_PACKAGE_NAME, ""));
+ doAnswer(invocation -> {
+ mRegisteredVirtualDisplayListener = invocation.getArgument(0);
+ return null;
+ }).when(mVirtualDeviceManagerInternalMock).registerVirtualDisplayListener(any());
+ doAnswer(invocation -> {
+ mRegisteredAppsOnVirtualDeviceListener = invocation.getArgument(0);
+ return null;
+ }).when(mVirtualDeviceManagerInternalMock).registerAppsOnVirtualDeviceListener(any());
- LocalServices.removeServiceForTest(PowerManagerInternal.class);
- LocalServices.addService(PowerManagerInternal.class, mPowerManagerInternalMock);
- LocalServices.removeServiceForTest(PackageManagerInternal.class);
- LocalServices.addService(PackageManagerInternal.class, mPackageManagerInternalMock);
+ removeServicesForTest();
+ addServicesForTest();
setDefaultIntensity(VIBRATION_INTENSITY_MEDIUM);
mAudioManager = mContextSpy.getSystemService(AudioManager.class);
@@ -168,6 +186,18 @@
}
@Test
+ public void create_withOnlyRequiredSystemServices() {
+ // The only core services that we depend on are PowerManager and PackageManager
+ removeServicesForTest();
+ LocalServices.addService(PowerManagerInternal.class, mPowerManagerInternalMock);
+ LocalServices.addService(PackageManagerInternal.class, mPackageManagerInternalMock);
+
+ VibrationSettings minimalVibrationSettings = new VibrationSettings(mContextSpy,
+ new Handler(mTestLooper.getLooper()), mVibrationConfigMock);
+ minimalVibrationSettings.onSystemReady();
+ }
+
+ @Test
public void addListener_settingsChangeTriggerListener() {
mVibrationSettings.addListener(mListenerMock);
@@ -447,6 +477,65 @@
}
@Test
+ public void shouldIgnoreVibrationFromVirtualDisplays_displayNonVirtual_neverIgnored() {
+ // Vibrations from the primary display is never ignored regardless of the creation and
+ // removal of virtual displays and of the changes of apps running on virtual displays.
+ mRegisteredVirtualDisplayListener.onVirtualDisplayCreated(VIRTUAL_DISPLAY_ID);
+ mRegisteredAppsOnVirtualDeviceListener.onAppsOnAnyVirtualDeviceChanged(
+ new ArraySet<>(Arrays.asList(UID)));
+ for (int usage : ALL_USAGES) {
+ assertVibrationNotIgnoredForUsageAndDisplay(usage, Display.DEFAULT_DISPLAY);
+ }
+
+ mRegisteredVirtualDisplayListener.onVirtualDisplayRemoved(VIRTUAL_DISPLAY_ID);
+ for (int usage : ALL_USAGES) {
+ assertVibrationNotIgnoredForUsageAndDisplay(usage, Display.DEFAULT_DISPLAY);
+ }
+
+ mRegisteredAppsOnVirtualDeviceListener.onAppsOnAnyVirtualDeviceChanged(new ArraySet<>());
+ for (int usage : ALL_USAGES) {
+ assertVibrationNotIgnoredForUsageAndDisplay(usage, Display.DEFAULT_DISPLAY);
+ }
+ }
+
+ @Test
+ public void shouldIgnoreVibrationFromVirtualDisplays_displayVirtual() {
+ // Ignore the vibration when the coming display id represents a virtual display.
+ mRegisteredVirtualDisplayListener.onVirtualDisplayCreated(VIRTUAL_DISPLAY_ID);
+
+ for (int usage : ALL_USAGES) {
+ assertVibrationIgnoredForUsageAndDisplay(usage, VIRTUAL_DISPLAY_ID,
+ Vibration.Status.IGNORED_FROM_VIRTUAL_DEVICE);
+ }
+
+ // Stop ignoring when the virtual display is removed.
+ mRegisteredVirtualDisplayListener.onVirtualDisplayRemoved(VIRTUAL_DISPLAY_ID);
+ for (int usage : ALL_USAGES) {
+ assertVibrationNotIgnoredForUsageAndDisplay(usage, VIRTUAL_DISPLAY_ID);
+ }
+ }
+
+
+ @Test
+ public void shouldIgnoreVibrationFromVirtualDisplays_appsOnVirtualDisplay() {
+ // Ignore when the passed-in display id is invalid and the calling uid is on a virtual
+ // display.
+ mRegisteredAppsOnVirtualDeviceListener.onAppsOnAnyVirtualDeviceChanged(
+ new ArraySet<>(Arrays.asList(UID)));
+ for (int usage : ALL_USAGES) {
+ assertVibrationIgnoredForUsageAndDisplay(usage, Display.INVALID_DISPLAY,
+ Vibration.Status.IGNORED_FROM_VIRTUAL_DEVICE);
+ }
+
+ // Stop ignoring when the app is no longer on virtual display.
+ mRegisteredAppsOnVirtualDeviceListener.onAppsOnAnyVirtualDeviceChanged(new ArraySet<>());
+ for (int usage : ALL_USAGES) {
+ assertVibrationNotIgnoredForUsageAndDisplay(usage, Display.INVALID_DISPLAY);
+ }
+
+ }
+
+ @Test
public void shouldVibrateInputDevices_returnsSettingsValue() {
setUserSetting(Settings.System.VIBRATE_INPUT_DEVICES, 1);
assertTrue(mVibrationSettings.shouldVibrateInputDevices());
@@ -479,7 +568,7 @@
@Test
public void shouldCancelVibrationOnScreenOff_withSleepReasonInAllowlist_returnsAlwaysFalse() {
long vibrateStartTime = 100;
- int[] allowedSleepReasons = new int[] {
+ int[] allowedSleepReasons = new int[]{
PowerManager.GO_TO_SLEEP_REASON_TIMEOUT,
PowerManager.GO_TO_SLEEP_REASON_INATTENTIVE,
};
@@ -646,11 +735,29 @@
assertNotNull(mVibrationSettings.getFallbackEffect(VibrationEffect.EFFECT_DOUBLE_CLICK));
}
+ private void removeServicesForTest() {
+ LocalServices.removeServiceForTest(PowerManagerInternal.class);
+ LocalServices.removeServiceForTest(PackageManagerInternal.class);
+ LocalServices.removeServiceForTest(VirtualDeviceManagerInternal.class);
+ }
+
+ private void addServicesForTest() {
+ LocalServices.addService(PowerManagerInternal.class, mPowerManagerInternalMock);
+ LocalServices.addService(PackageManagerInternal.class, mPackageManagerInternalMock);
+ LocalServices.addService(VirtualDeviceManagerInternal.class,
+ mVirtualDeviceManagerInternalMock);
+ }
+
private void assertVibrationIgnoredForUsage(@VibrationAttributes.Usage int usage,
Vibration.Status expectedStatus) {
+ assertVibrationIgnoredForUsageAndDisplay(usage, Display.DEFAULT_DISPLAY, expectedStatus);
+ }
+
+ private void assertVibrationIgnoredForUsageAndDisplay(@VibrationAttributes.Usage int usage,
+ int displayId, Vibration.Status expectedStatus) {
assertEquals(errorMessageForUsage(usage),
expectedStatus,
- mVibrationSettings.shouldIgnoreVibration(UID,
+ mVibrationSettings.shouldIgnoreVibration(UID, displayId,
VibrationAttributes.createForUsage(usage)));
}
@@ -660,8 +767,20 @@
private void assertVibrationNotIgnoredForUsageAndFlags(@VibrationAttributes.Usage int usage,
@VibrationAttributes.Flag int flags) {
+ assertVibrationNotIgnoredForUsageAndFlagsAndDidsplay(usage, Display.DEFAULT_DISPLAY, flags);
+ }
+
+ private void assertVibrationNotIgnoredForUsageAndDisplay(@VibrationAttributes.Usage int usage,
+ int displayId) {
+ assertVibrationNotIgnoredForUsageAndFlagsAndDidsplay(usage, displayId, /* flags= */ 0);
+ }
+
+ private void assertVibrationNotIgnoredForUsageAndFlagsAndDidsplay(
+ @VibrationAttributes.Usage int usage, int displayId,
+ @VibrationAttributes.Flag int flags) {
assertNull(errorMessageForUsage(usage),
mVibrationSettings.shouldIgnoreVibration(UID,
+ displayId,
new VibrationAttributes.Builder()
.setUsage(usage)
.setFlags(flags)
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java
index ca162ef..0551bfc 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java
@@ -94,6 +94,7 @@
private static final int TEST_TIMEOUT_MILLIS = 900;
private static final int UID = Process.ROOT_UID;
+ private static final int DISPLAY_ID = 10;
private static final int VIBRATOR_ID = 1;
private static final String PACKAGE_NAME = "package";
private static final VibrationAttributes ATTRS = new VibrationAttributes.Builder().build();
@@ -1584,7 +1585,8 @@
}
private Vibration createVibration(long id, CombinedVibration effect) {
- return new Vibration(mVibrationToken, (int) id, effect, ATTRS, UID, PACKAGE_NAME, "reason");
+ return new Vibration(mVibrationToken, (int) id, effect, ATTRS, UID, DISPLAY_ID,
+ PACKAGE_NAME, "reason");
}
private SparseArray<VibratorController> createVibratorControllers() {
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java
index 36bec75..fe0a79c 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java
@@ -76,7 +76,9 @@
import android.os.vibrator.VibrationEffectSegment;
import android.platform.test.annotations.Presubmit;
import android.provider.Settings;
+import android.util.ArraySet;
import android.util.SparseBooleanArray;
+import android.view.Display;
import android.view.InputDevice;
import androidx.test.InstrumentationRegistry;
@@ -86,6 +88,7 @@
import com.android.internal.util.test.FakeSettingsProvider;
import com.android.internal.util.test.FakeSettingsProviderRule;
import com.android.server.LocalServices;
+import com.android.server.companion.virtual.VirtualDeviceManagerInternal;
import org.junit.After;
import org.junit.Before;
@@ -115,6 +118,7 @@
private static final int TEST_TIMEOUT_MILLIS = 1_000;
private static final int UID = Process.ROOT_UID;
+ private static final int VIRTUAL_DISPLAY_ID = 1;
private static final String PACKAGE_NAME = "package";
private static final PowerSaveState NORMAL_POWER_STATE = new PowerSaveState.Builder().build();
private static final PowerSaveState LOW_POWER_STATE = new PowerSaveState.Builder()
@@ -153,6 +157,8 @@
private IBatteryStats mBatteryStatsMock;
@Mock
private VibratorFrameworkStatsLogger mVibratorFrameworkStatsLoggerMock;
+ @Mock
+ private VirtualDeviceManagerInternal mVirtualDeviceManagerInternalMock;
private final Map<Integer, FakeVibratorControllerProvider> mVibratorProviders = new HashMap<>();
@@ -162,6 +168,9 @@
private PowerManagerInternal.LowPowerModeListener mRegisteredPowerModeListener;
private VibratorManagerService.ExternalVibratorService mExternalVibratorService;
private VibrationConfig mVibrationConfig;
+ private VirtualDeviceManagerInternal.VirtualDisplayListener mRegisteredVirtualDisplayListener;
+ private VirtualDeviceManagerInternal.AppsOnVirtualDeviceListener
+ mRegisteredAppsOnVirtualDeviceListener;
@Before
public void setUp() throws Exception {
@@ -186,6 +195,14 @@
mRegisteredPowerModeListener = invocation.getArgument(0);
return null;
}).when(mPowerManagerInternalMock).registerLowPowerModeObserver(any());
+ doAnswer(invocation -> {
+ mRegisteredVirtualDisplayListener = invocation.getArgument(0);
+ return null;
+ }).when(mVirtualDeviceManagerInternalMock).registerVirtualDisplayListener(any());
+ doAnswer(invocation -> {
+ mRegisteredAppsOnVirtualDeviceListener = invocation.getArgument(0);
+ return null;
+ }).when(mVirtualDeviceManagerInternalMock).registerAppsOnVirtualDeviceListener(any());
setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 1);
setUserSetting(Settings.System.HAPTIC_FEEDBACK_ENABLED, 1);
@@ -202,6 +219,7 @@
addLocalServiceMock(PackageManagerInternal.class, mPackageManagerInternalMock);
addLocalServiceMock(PowerManagerInternal.class, mPowerManagerInternalMock);
+ addLocalServiceMock(VirtualDeviceManagerInternal.class, mVirtualDeviceManagerInternalMock);
mTestLooper.startAutoDispatch();
}
@@ -1167,6 +1185,64 @@
}
@Test
+ public void vibrate_withVitualDisplayChange_ignoreVibrationFromVirtualDisplay()
+ throws Exception {
+ mockVibrators(1);
+ VibratorManagerService service = createSystemReadyService();
+ mRegisteredVirtualDisplayListener.onVirtualDisplayCreated(VIRTUAL_DISPLAY_ID);
+
+ vibrateWithDisplay(service,
+ VIRTUAL_DISPLAY_ID,
+ CombinedVibration.startParallel()
+ .addVibrator(1, VibrationEffect.createOneShot(1000, 100))
+ .combine(),
+ HAPTIC_FEEDBACK_ATTRS);
+
+ // Haptic feedback ignored when it's from a virtual display.
+ assertFalse(waitUntil(s -> s.isVibrating(1), service, /* timeout= */ 50));
+
+ mRegisteredVirtualDisplayListener.onVirtualDisplayRemoved(VIRTUAL_DISPLAY_ID);
+ vibrateWithDisplay(service,
+ VIRTUAL_DISPLAY_ID,
+ CombinedVibration.startParallel()
+ .addVibrator(1, VibrationEffect.createOneShot(1000, 100))
+ .combine(),
+ HAPTIC_FEEDBACK_ATTRS);
+ // Haptic feedback played normally when the virtual display is removed.
+ assertTrue(waitUntil(s -> s.isVibrating(1), service, TEST_TIMEOUT_MILLIS));
+
+ }
+
+ @Test
+ public void vibrate_withAppsOnVitualDisplayChange_ignoreVibrationFromVirtualDisplay()
+ throws Exception {
+ mockVibrators(1);
+ VibratorManagerService service = createSystemReadyService();
+ mRegisteredAppsOnVirtualDeviceListener.onAppsOnAnyVirtualDeviceChanged(
+ new ArraySet<>(Arrays.asList(UID)));
+ vibrateWithDisplay(service,
+ Display.INVALID_DISPLAY,
+ CombinedVibration.startParallel()
+ .addVibrator(1, VibrationEffect.createOneShot(1000, 100))
+ .combine(),
+ HAPTIC_FEEDBACK_ATTRS);
+
+ // Haptic feedback ignored when it's from an app running virtual display.
+ assertFalse(waitUntil(s -> s.isVibrating(1), service, /* timeout= */ 50));
+
+ mRegisteredAppsOnVirtualDeviceListener.onAppsOnAnyVirtualDeviceChanged(new ArraySet<>());
+ vibrateWithDisplay(service,
+ Display.INVALID_DISPLAY,
+ CombinedVibration.startParallel()
+ .addVibrator(1, VibrationEffect.createOneShot(1000, 100))
+ .combine(),
+ HAPTIC_FEEDBACK_ATTRS);
+ // Haptic feedback played normally when the same app no long runs on a virtual display.
+ assertTrue(waitUntil(s -> s.isVibrating(1), service, TEST_TIMEOUT_MILLIS));
+
+ }
+
+ @Test
public void cancelVibrate_withoutUsageFilter_stopsVibrating() throws Exception {
mockVibrators(1);
VibratorManagerService service = createSystemReadyService();
@@ -1240,6 +1316,24 @@
}
@Test
+ public void onExternalVibration_ignoreVibrationFromVirtualDevices() throws Exception {
+ mockVibrators(1);
+ mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_EXTERNAL_CONTROL);
+ createSystemReadyService();
+
+ IBinder binderToken = mock(IBinder.class);
+ ExternalVibration externalVibration = new ExternalVibration(UID, PACKAGE_NAME, AUDIO_ATTRS,
+ mock(IExternalVibrationController.class), binderToken);
+ int scale = mExternalVibratorService.onExternalVibrationStart(externalVibration);
+ assertNotEquals(IExternalVibratorService.SCALE_MUTE, scale);
+
+ mRegisteredAppsOnVirtualDeviceListener.onAppsOnAnyVirtualDeviceChanged(
+ new ArraySet<>(Arrays.asList(UID)));
+ scale = mExternalVibratorService.onExternalVibrationStart(externalVibration);
+ assertEquals(IExternalVibratorService.SCALE_MUTE, scale);
+ }
+
+ @Test
public void onExternalVibration_setsExternalControl() throws Exception {
mockVibrators(1);
mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_EXTERNAL_CONTROL);
@@ -1820,7 +1914,8 @@
private void vibrateAndWaitUntilFinished(VibratorManagerService service,
CombinedVibration effect, VibrationAttributes attrs) throws InterruptedException {
Vibration vib =
- service.vibrateInternal(UID, PACKAGE_NAME, effect, attrs, "some reason", service);
+ service.vibrateInternal(UID, Display.DEFAULT_DISPLAY, PACKAGE_NAME, effect, attrs,
+ "some reason", service);
if (vib != null) {
vib.waitForEnd();
}
@@ -1833,7 +1928,12 @@
private void vibrate(VibratorManagerService service, CombinedVibration effect,
VibrationAttributes attrs) {
- service.vibrate(UID, PACKAGE_NAME, effect, attrs, "some reason", service);
+ vibrateWithDisplay(service, Display.DEFAULT_DISPLAY, effect, attrs);
+ }
+
+ private void vibrateWithDisplay(VibratorManagerService service, int displayId,
+ CombinedVibration effect, VibrationAttributes attrs) {
+ service.vibrate(UID, displayId, PACKAGE_NAME, effect, attrs, "some reason", service);
}
private boolean waitUntil(Predicate<VibratorManagerService> predicate,
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index e85d7db..a545c83 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -7548,6 +7548,43 @@
}
@Test
+ public void testAddAutomaticZenRule_systemCallTakesPackageFromOwner() throws Exception {
+ mService.isSystemUid = true;
+ ZenModeHelper mockZenModeHelper = mock(ZenModeHelper.class);
+ when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
+ .thenReturn(true);
+ mService.setZenHelper(mockZenModeHelper);
+ ComponentName owner = new ComponentName("android", "ProviderName");
+ ZenPolicy zenPolicy = new ZenPolicy.Builder().allowAlarms(true).build();
+ boolean isEnabled = true;
+ AutomaticZenRule rule = new AutomaticZenRule("test", owner, owner, mock(Uri.class),
+ zenPolicy, NotificationManager.INTERRUPTION_FILTER_PRIORITY, isEnabled);
+ mBinderService.addAutomaticZenRule(rule, "com.android.settings");
+
+ // verify that zen mode helper gets passed in a package name of "android"
+ verify(mockZenModeHelper).addAutomaticZenRule(eq("android"), eq(rule), anyString());
+ }
+
+ @Test
+ public void testAddAutomaticZenRule_nonSystemCallTakesPackageFromArg() throws Exception {
+ mService.isSystemUid = false;
+ ZenModeHelper mockZenModeHelper = mock(ZenModeHelper.class);
+ when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
+ .thenReturn(true);
+ mService.setZenHelper(mockZenModeHelper);
+ ComponentName owner = new ComponentName("android", "ProviderName");
+ ZenPolicy zenPolicy = new ZenPolicy.Builder().allowAlarms(true).build();
+ boolean isEnabled = true;
+ AutomaticZenRule rule = new AutomaticZenRule("test", owner, owner, mock(Uri.class),
+ zenPolicy, NotificationManager.INTERRUPTION_FILTER_PRIORITY, isEnabled);
+ mBinderService.addAutomaticZenRule(rule, "another.package");
+
+ // verify that zen mode helper gets passed in the package name from the arg, not the owner
+ verify(mockZenModeHelper).addAutomaticZenRule(
+ eq("another.package"), eq(rule), anyString());
+ }
+
+ @Test
public void testAreNotificationsEnabledForPackage() throws Exception {
mBinderService.areNotificationsEnabledForPackage(mContext.getPackageName(),
mUid);
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 eb61a9c..95e9f20 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -158,7 +158,6 @@
import com.android.internal.R;
import com.android.server.wm.ActivityRecord.State;
-import com.android.server.wm.utils.WmDisplayCutout;
import org.junit.Assert;
import org.junit.Before;
@@ -552,9 +551,9 @@
final Rect insets = new Rect();
final DisplayInfo displayInfo = task.mDisplayContent.getDisplayInfo();
final DisplayPolicy policy = task.mDisplayContent.getDisplayPolicy();
- policy.getNonDecorInsetsLw(displayInfo.rotation, displayInfo.logicalWidth,
- displayInfo.logicalHeight, WmDisplayCutout.NO_CUTOUT, insets);
- policy.convertNonDecorInsetsToStableInsets(insets, displayInfo.rotation);
+
+ insets.set(policy.getDecorInsetsInfo(displayInfo.rotation, displayInfo.logicalWidth,
+ displayInfo.logicalHeight).mConfigInsets);
Task.intersectWithInsetsIfFits(stableRect, stableRect, insets);
final boolean isScreenPortrait = stableRect.width() <= stableRect.height();
@@ -594,9 +593,8 @@
final Rect insets = new Rect();
final DisplayInfo displayInfo = rootTask.mDisplayContent.getDisplayInfo();
final DisplayPolicy policy = rootTask.mDisplayContent.getDisplayPolicy();
- policy.getNonDecorInsetsLw(displayInfo.rotation, displayInfo.logicalWidth,
- displayInfo.logicalHeight, WmDisplayCutout.NO_CUTOUT, insets);
- policy.convertNonDecorInsetsToStableInsets(insets, displayInfo.rotation);
+ insets.set(policy.getDecorInsetsInfo(displayInfo.rotation, displayInfo.logicalWidth,
+ displayInfo.logicalHeight).mConfigInsets);
Task.intersectWithInsetsIfFits(stableRect, stableRect, insets);
final boolean isScreenPortrait = stableRect.width() <= stableRect.height();
@@ -2988,31 +2986,28 @@
}
@Test
- public void testCloseToSquareFixedOrientationPortrait() {
+ public void testCloseToSquareFixedOrientation() {
// create a square display
final DisplayContent squareDisplay = new TestDisplayContent.Builder(mAtm, 2000, 2000)
.setSystemDecorations(true).build();
+ // Add a decor insets provider window.
+ final WindowState navbar = createNavBarWithProvidedInsets(squareDisplay);
+ squareDisplay.getDisplayPolicy().updateDecorInsetsInfoIfNeeded(navbar);
+ squareDisplay.sendNewConfiguration();
final Task task = new TaskBuilder(mSupervisor).setDisplay(squareDisplay).build();
// create a fixed portrait activity
- final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(task)
+ ActivityRecord activity = new ActivityBuilder(mAtm).setTask(task)
.setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT).build();
- // check that both the configuration and app bounds are portrait
+ // The available space could be landscape because of decor insets, but the configuration
+ // should still respect the requested portrait orientation.
assertEquals(ORIENTATION_PORTRAIT, activity.getConfiguration().orientation);
assertTrue(activity.getConfiguration().windowConfiguration.getAppBounds().width()
<= activity.getConfiguration().windowConfiguration.getAppBounds().height());
- }
-
- @Test
- public void testCloseToSquareFixedOrientationLandscape() {
- // create a square display
- final DisplayContent squareDisplay = new TestDisplayContent.Builder(mAtm, 2000, 2000)
- .setSystemDecorations(true).build();
- final Task task = new TaskBuilder(mSupervisor).setDisplay(squareDisplay).build();
// create a fixed landscape activity
- final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(task)
+ activity = new ActivityBuilder(mAtm).setTask(task)
.setScreenOrientation(SCREEN_ORIENTATION_LANDSCAPE).build();
// check that both the configuration and app bounds are landscape
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index c78bc59..00be7ed 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -35,6 +35,7 @@
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
import static android.content.Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+import static android.content.Intent.FLAG_ACTIVITY_REORDER_TO_FRONT;
import static android.content.Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED;
import static android.content.Intent.FLAG_ACTIVITY_SINGLE_TOP;
import static android.content.pm.ActivityInfo.FLAG_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING;
@@ -66,6 +67,7 @@
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.anyBoolean;
@@ -1402,6 +1404,39 @@
canEmbedActivity(taskFragment, starting, task));
}
+ @Test
+ public void testRecordActivityMovementBeforeDeliverToTop() {
+ final Task task = new TaskBuilder(mAtm.mTaskSupervisor).build();
+ final ActivityRecord activityBot = new ActivityBuilder(mAtm).setTask(task).build();
+ final ActivityRecord activityTop = new ActivityBuilder(mAtm).setTask(task).build();
+
+ activityBot.setVisible(false);
+ activityBot.mVisibleRequested = false;
+
+ assertTrue(activityTop.isVisible());
+ assertTrue(activityTop.mVisibleRequested);
+
+ final ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_REORDER_TO_FRONT
+ | FLAG_ACTIVITY_NEW_TASK, false /* mockGetRootTask */);
+ starter.mStartActivity = activityBot;
+ task.inRecents = true;
+ starter.setInTask(task);
+ starter.getIntent().setComponent(activityBot.mActivityComponent);
+ final int result = starter.setReason("testRecordActivityMovement").execute();
+
+ assertEquals(START_DELIVERED_TO_TOP, result);
+ assertNotNull(starter.mMovedToTopActivity);
+
+ final ActivityStarter starter2 = prepareStarter(FLAG_ACTIVITY_REORDER_TO_FRONT
+ | FLAG_ACTIVITY_NEW_TASK, false /* mockGetRootTask */);
+ starter2.setInTask(task);
+ starter2.getIntent().setComponent(activityBot.mActivityComponent);
+ final int result2 = starter2.setReason("testRecordActivityMovement").execute();
+
+ assertEquals(START_DELIVERED_TO_TOP, result2);
+ assertNull(starter2.mMovedToTopActivity);
+ }
+
private static void startActivityInner(ActivityStarter starter, ActivityRecord target,
ActivityRecord source, ActivityOptions options, Task inTask,
TaskFragment inTaskFragment) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
index 20b1120..2fccd64 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
@@ -220,10 +220,7 @@
// Check that changes are reported
Configuration c = new Configuration(newDisp1.getRequestedOverrideConfiguration());
c.windowConfiguration.setBounds(new Rect(0, 0, 1000, 1300));
- newDisp1.onRequestedOverrideConfigurationChanged(c);
- mAtm.mRootWindowContainer.ensureVisibilityAndConfig(null /* starting */,
- newDisp1.mDisplayId, false /* markFrozenIfConfigChanged */,
- false /* deferResume */);
+ newDisp1.performDisplayOverrideConfigUpdate(c);
assertEquals(0, added.size());
assertEquals(1, changed.size());
assertEquals(0, removed.size());
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
index b5764f5..4d71b30 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
@@ -134,9 +134,9 @@
@Test
public void testNoChangeOnOldDisplayWhenMoveDisplay() {
- mDisplayContent.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ mDisplayContent.getDefaultTaskDisplayArea().setWindowingMode(WINDOWING_MODE_FULLSCREEN);
final DisplayContent dc1 = createNewDisplay(Display.STATE_ON);
- dc1.setWindowingMode(WINDOWING_MODE_FREEFORM);
+ dc1.getDefaultTaskDisplayArea().setWindowingMode(WINDOWING_MODE_FREEFORM);
setUpOnDisplay(dc1);
assertEquals(WINDOWING_MODE_FREEFORM, mTask.getWindowingMode());
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index fd97d91..63f4f5f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -1066,6 +1066,7 @@
final DisplayContent dc = createNewDisplay();
dc.getDisplayRotation().setFixedToUserRotation(
IWindowManager.FIXED_TO_USER_ROTATION_DISABLED);
+ dc.getDefaultTaskDisplayArea().setWindowingMode(WINDOWING_MODE_FULLSCREEN);
final int newOrientation = getRotatedOrientation(dc);
final Task task = new TaskBuilder(mSupervisor)
@@ -1125,6 +1126,7 @@
IWindowManager.FIXED_TO_USER_ROTATION_ENABLED);
dc.getDisplayRotation().setUserRotation(
WindowManagerPolicy.USER_ROTATION_LOCKED, ROTATION_0);
+ dc.getDefaultTaskDisplayArea().setWindowingMode(WINDOWING_MODE_FULLSCREEN);
final int newOrientation = getRotatedOrientation(dc);
final Task task = new TaskBuilder(mSupervisor)
@@ -2028,23 +2030,6 @@
}
@Test
- public void testSetWindowingModeAtomicallyUpdatesWindoingModeAndDisplayWindowingMode() {
- final DisplayContent dc = createNewDisplay();
- final Task rootTask = new TaskBuilder(mSupervisor)
- .setDisplay(dc)
- .build();
- doAnswer(invocation -> {
- Object[] args = invocation.getArguments();
- final Configuration config = ((Configuration) args[0]);
- assertEquals(config.windowConfiguration.getWindowingMode(),
- config.windowConfiguration.getDisplayWindowingMode());
- return null;
- }).when(rootTask).onConfigurationChanged(any());
- dc.setWindowingMode(WINDOWING_MODE_FREEFORM);
- dc.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
- }
-
- @Test
public void testForceDesktopMode() {
mWm.mForceDesktopModeOnExternalDisplays = true;
// Not applicable for default display
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyInsetsTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyInsetsTests.java
index a001eda..e298d51 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyInsetsTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyInsetsTests.java
@@ -25,13 +25,10 @@
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
-import android.util.Pair;
import android.view.DisplayInfo;
import androidx.test.filters.SmallTest;
-import com.android.server.wm.utils.WmDisplayCutout;
-
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ErrorCollector;
@@ -49,8 +46,7 @@
@Test
public void portrait() {
- final Pair<DisplayInfo, WmDisplayCutout> di =
- displayInfoForRotation(ROTATION_0, false /* withCutout */);
+ final DisplayInfo di = displayInfoForRotation(ROTATION_0, false /* withCutout */);
verifyStableInsets(di, 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT);
verifyNonDecorInsets(di, 0, 0, 0, NAV_BAR_HEIGHT);
@@ -59,8 +55,7 @@
@Test
public void portrait_withCutout() {
- final Pair<DisplayInfo, WmDisplayCutout> di =
- displayInfoForRotation(ROTATION_0, true /* withCutout */);
+ final DisplayInfo di = displayInfoForRotation(ROTATION_0, true /* withCutout */);
verifyStableInsets(di, 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT);
verifyNonDecorInsets(di, 0, DISPLAY_CUTOUT_HEIGHT, 0, NAV_BAR_HEIGHT);
@@ -69,8 +64,7 @@
@Test
public void landscape() {
- final Pair<DisplayInfo, WmDisplayCutout> di =
- displayInfoForRotation(ROTATION_90, false /* withCutout */);
+ final DisplayInfo di = displayInfoForRotation(ROTATION_90, false /* withCutout */);
if (mDisplayPolicy.navigationBarCanMove()) {
verifyStableInsets(di, 0, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
@@ -85,8 +79,7 @@
@Test
public void landscape_withCutout() {
- final Pair<DisplayInfo, WmDisplayCutout> di =
- displayInfoForRotation(ROTATION_90, true /* withCutout */);
+ final DisplayInfo di = displayInfoForRotation(ROTATION_90, true /* withCutout */);
if (mDisplayPolicy.navigationBarCanMove()) {
verifyStableInsets(di, DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
@@ -101,8 +94,7 @@
@Test
public void seascape() {
- final Pair<DisplayInfo, WmDisplayCutout> di =
- displayInfoForRotation(ROTATION_270, false /* withCutout */);
+ final DisplayInfo di = displayInfoForRotation(ROTATION_270, false /* withCutout */);
if (mDisplayPolicy.navigationBarCanMove()) {
verifyStableInsets(di, NAV_BAR_HEIGHT, STATUS_BAR_HEIGHT, 0, 0);
@@ -117,8 +109,7 @@
@Test
public void seascape_withCutout() {
- final Pair<DisplayInfo, WmDisplayCutout> di =
- displayInfoForRotation(ROTATION_270, true /* withCutout */);
+ final DisplayInfo di = displayInfoForRotation(ROTATION_270, true /* withCutout */);
if (mDisplayPolicy.navigationBarCanMove()) {
verifyStableInsets(di, NAV_BAR_HEIGHT, STATUS_BAR_HEIGHT, DISPLAY_CUTOUT_HEIGHT, 0);
@@ -133,8 +124,7 @@
@Test
public void upsideDown() {
- final Pair<DisplayInfo, WmDisplayCutout> di =
- displayInfoForRotation(ROTATION_180, false /* withCutout */);
+ final DisplayInfo di = displayInfoForRotation(ROTATION_180, false /* withCutout */);
verifyStableInsets(di, 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT);
verifyNonDecorInsets(di, 0, 0, 0, NAV_BAR_HEIGHT);
@@ -143,34 +133,32 @@
@Test
public void upsideDown_withCutout() {
- final Pair<DisplayInfo, WmDisplayCutout> di =
- displayInfoForRotation(ROTATION_180, true /* withCutout */);
+ final DisplayInfo di = displayInfoForRotation(ROTATION_180, true /* withCutout */);
verifyStableInsets(di, 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT + DISPLAY_CUTOUT_HEIGHT);
verifyNonDecorInsets(di, 0, 0, 0, NAV_BAR_HEIGHT + DISPLAY_CUTOUT_HEIGHT);
verifyConsistency(di);
}
- private void verifyStableInsets(Pair<DisplayInfo, WmDisplayCutout> diPair, int left, int top,
+ private void verifyStableInsets(DisplayInfo di, int left, int top,
int right, int bottom) {
- mErrorCollector.checkThat("stableInsets", getStableInsetsLw(diPair.first, diPair.second),
+ mErrorCollector.checkThat("stableInsets", getStableInsets(di),
equalTo(new Rect(left, top, right, bottom)));
}
- private void verifyNonDecorInsets(Pair<DisplayInfo, WmDisplayCutout> diPair, int left, int top,
+ private void verifyNonDecorInsets(DisplayInfo di, int left, int top,
int right, int bottom) {
mErrorCollector.checkThat("nonDecorInsets",
- getNonDecorInsetsLw(diPair.first, diPair.second), equalTo(new Rect(
- left, top, right, bottom)));
+ getNonDecorInsets(di), equalTo(new Rect(left, top, right, bottom)));
}
- private void verifyConsistency(Pair<DisplayInfo, WmDisplayCutout> diPair) {
- final DisplayInfo di = diPair.first;
- final WmDisplayCutout cutout = diPair.second;
- verifyConsistency("configDisplay", di, getStableInsetsLw(di, cutout),
- getConfigDisplayWidth(di, cutout), getConfigDisplayHeight(di, cutout));
- verifyConsistency("nonDecorDisplay", di, getNonDecorInsetsLw(di, cutout),
- getNonDecorDisplayWidth(di, cutout), getNonDecorDisplayHeight(di, cutout));
+ private void verifyConsistency(DisplayInfo di) {
+ final DisplayPolicy.DecorInsets.Info info = mDisplayPolicy.getDecorInsetsInfo(
+ di.rotation, di.logicalWidth, di.logicalHeight);
+ verifyConsistency("configDisplay", di, info.mConfigInsets,
+ info.mConfigFrame.width(), info.mConfigFrame.height());
+ verifyConsistency("nonDecorDisplay", di, info.mNonDecorInsets,
+ info.mNonDecorFrame.width(), info.mNonDecorFrame.height());
}
private void verifyConsistency(String what, DisplayInfo di, Rect insets, int width,
@@ -181,42 +169,18 @@
equalTo(di.logicalHeight - insets.top - insets.bottom));
}
- private Rect getStableInsetsLw(DisplayInfo di, WmDisplayCutout cutout) {
- Rect result = new Rect();
- mDisplayPolicy.getStableInsetsLw(di.rotation, di.logicalWidth, di.logicalHeight,
- cutout, result);
- return result;
+ private Rect getStableInsets(DisplayInfo di) {
+ return mDisplayPolicy.getDecorInsetsInfo(
+ di.rotation, di.logicalWidth, di.logicalHeight).mConfigInsets;
}
- private Rect getNonDecorInsetsLw(DisplayInfo di, WmDisplayCutout cutout) {
- Rect result = new Rect();
- mDisplayPolicy.getNonDecorInsetsLw(di.rotation, di.logicalWidth, di.logicalHeight,
- cutout, result);
- return result;
+ private Rect getNonDecorInsets(DisplayInfo di) {
+ return mDisplayPolicy.getDecorInsetsInfo(
+ di.rotation, di.logicalWidth, di.logicalHeight).mNonDecorInsets;
}
- private int getNonDecorDisplayWidth(DisplayInfo di, WmDisplayCutout cutout) {
- return mDisplayPolicy.getNonDecorDisplayFrame(di.logicalWidth, di.logicalHeight,
- di.rotation, cutout).width();
- }
-
- private int getNonDecorDisplayHeight(DisplayInfo di, WmDisplayCutout cutout) {
- return mDisplayPolicy.getNonDecorDisplayFrame(di.logicalWidth, di.logicalHeight,
- di.rotation, cutout).height();
- }
-
- private int getConfigDisplayWidth(DisplayInfo di, WmDisplayCutout cutout) {
- return mDisplayPolicy.getConfigDisplaySize(di.logicalWidth, di.logicalHeight,
- di.rotation, cutout).x;
- }
-
- private int getConfigDisplayHeight(DisplayInfo di, WmDisplayCutout cutout) {
- return mDisplayPolicy.getConfigDisplaySize(di.logicalWidth, di.logicalHeight,
- di.rotation, cutout).y;
- }
-
- private static Pair<DisplayInfo, WmDisplayCutout> displayInfoForRotation(int rotation,
- boolean withDisplayCutout) {
- return displayInfoAndCutoutForRotation(rotation, withDisplayCutout, false);
+ private DisplayInfo displayInfoForRotation(int rotation, boolean withDisplayCutout) {
+ return displayInfoAndCutoutForRotation(
+ rotation, withDisplayCutout, false /* isLongEdgeCutout */);
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
index 34575ae..6951fef 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
@@ -41,7 +41,6 @@
import android.graphics.Insets;
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
-import android.util.Pair;
import android.view.DisplayInfo;
import android.view.InsetsFrameProvider;
import android.view.InsetsState;
@@ -50,8 +49,6 @@
import androidx.test.filters.SmallTest;
-import com.android.server.wm.utils.WmDisplayCutout;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -123,7 +120,7 @@
private void updateDisplayFrames() {
mFrames = createDisplayFrames(
mDisplayContent.getInsetsStateController().getRawInsetsState());
- mDisplayBounds.set(0, 0, mFrames.mDisplayWidth, mFrames.mDisplayHeight);
+ mDisplayBounds.set(0, 0, mFrames.mWidth, mFrames.mHeight);
mDisplayContent.mDisplayFrames = mFrames;
mDisplayContent.setBounds(mDisplayBounds);
mDisplayPolicy.layoutWindowLw(mNavBarWindow, null, mFrames);
@@ -131,13 +128,13 @@
}
private DisplayFrames createDisplayFrames(InsetsState insetsState) {
- final Pair<DisplayInfo, WmDisplayCutout> info = displayInfoAndCutoutForRotation(mRotation,
+ final DisplayInfo info = displayInfoAndCutoutForRotation(mRotation,
mHasDisplayCutout, mIsLongEdgeDisplayCutout);
final RoundedCorners roundedCorners = mHasRoundedCorners
? mDisplayContent.calculateRoundedCornersForRotation(mRotation)
: RoundedCorners.NO_ROUNDED_CORNERS;
- return new DisplayFrames(mDisplayContent.getDisplayId(),
- insetsState, info.first, info.second, roundedCorners, new PrivacyIndicatorBounds());
+ return new DisplayFrames(insetsState, info,
+ info.displayCutout, roundedCorners, new PrivacyIndicatorBounds());
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
index 8f2e9b4..e00296f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static android.view.DisplayCutout.NO_CUTOUT;
import static android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR;
import static android.view.InsetsState.ITYPE_IME;
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
@@ -35,13 +36,12 @@
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
-import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_BOTTOM;
-import static com.android.server.wm.utils.WmDisplayCutout.NO_CUTOUT;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
@@ -286,10 +286,18 @@
DisplayPolicy.isOverlappingWithNavBar(targetWin));
}
- private WindowState createNavigationBarWindow() {
- final WindowState win = createWindow(null, TYPE_NAVIGATION_BAR, "NavigationBar");
- win.mHasSurface = true;
- return win;
+ @Test
+ public void testUpdateDisplayConfigurationByDecor() {
+ final WindowState navbar = createNavBarWithProvidedInsets(mDisplayContent);
+ final DisplayPolicy displayPolicy = mDisplayContent.getDisplayPolicy();
+ final DisplayInfo di = mDisplayContent.getDisplayInfo();
+ final int prevScreenHeightDp = mDisplayContent.getConfiguration().screenHeightDp;
+ assertTrue(displayPolicy.updateDecorInsetsInfoIfNeeded(navbar));
+ assertEquals(NAV_BAR_HEIGHT, displayPolicy.getDecorInsetsInfo(di.rotation,
+ di.logicalWidth, di.logicalHeight).mConfigInsets.bottom);
+ mDisplayContent.sendNewConfiguration();
+ assertNotEquals(prevScreenHeightDp, mDisplayContent.getConfiguration().screenHeightDp);
+ assertFalse(displayPolicy.updateDecorInsetsInfoIfNeeded(navbar));
}
@UseTestDisplay(addWindows = { W_NAVIGATION_BAR, W_INPUT_METHOD })
@@ -307,7 +315,7 @@
mNavBarWindow.getControllableInsetProvider().setServerVisible(true);
final InsetsState state = mDisplayContent.getInsetsStateController().getRawInsetsState();
mImeWindow.mAboveInsetsState.set(state);
- mDisplayContent.mDisplayFrames = new DisplayFrames(mDisplayContent.getDisplayId(),
+ mDisplayContent.mDisplayFrames = new DisplayFrames(
state, displayInfo, NO_CUTOUT, NO_ROUNDED_CORNERS, new PrivacyIndicatorBounds());
mDisplayContent.setInputMethodWindowLocked(mImeWindow);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java
index 97b1c91..fe890d5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java
@@ -30,25 +30,14 @@
import static com.android.server.wm.utils.CoordinateTransforms.transformPhysicalToLogicalCoordinates;
import static org.junit.Assert.assertEquals;
-import static org.mockito.ArgumentMatchers.anyInt;
-import android.content.Context;
-import android.content.ContextWrapper;
-import android.content.pm.PackageManager;
-import android.content.res.Resources;
import android.graphics.Matrix;
import android.graphics.RectF;
import android.os.Binder;
-import android.os.IBinder;
-import android.testing.TestableResources;
-import android.util.Pair;
import android.view.DisplayCutout;
import android.view.DisplayInfo;
import android.view.WindowManagerGlobal;
-import com.android.internal.R;
-import com.android.server.wm.utils.WmDisplayCutout;
-
import org.junit.Before;
public class DisplayPolicyTestsBase extends WindowTestsBase {
@@ -69,23 +58,8 @@
mDisplayPolicy = mDisplayContent.getDisplayPolicy();
spyOn(mDisplayPolicy);
-
- final TestContextWrapper context = new TestContextWrapper(
- mDisplayPolicy.getContext(), mDisplayPolicy.getCurrentUserResources());
- final TestableResources resources = context.getResourceMocker();
- resources.addOverride(R.dimen.navigation_bar_height, NAV_BAR_HEIGHT);
- resources.addOverride(R.dimen.navigation_bar_height_landscape, NAV_BAR_HEIGHT);
- resources.addOverride(R.dimen.navigation_bar_width, NAV_BAR_HEIGHT);
- resources.addOverride(R.dimen.navigation_bar_frame_height_landscape, NAV_BAR_HEIGHT);
- resources.addOverride(R.dimen.navigation_bar_frame_height, NAV_BAR_HEIGHT);
- doReturn(STATUS_BAR_HEIGHT).when(mDisplayPolicy).getStatusBarHeightForRotation(anyInt());
- doReturn(resources.getResources()).when(mDisplayPolicy).getCurrentUserResources();
doReturn(true).when(mDisplayPolicy).hasNavigationBar();
doReturn(true).when(mDisplayPolicy).hasStatusBar();
-
- mDisplayContent.getDisplayRotation().configure(DISPLAY_WIDTH, DISPLAY_HEIGHT);
- mDisplayPolicy.onConfigurationChanged();
-
addWindow(mStatusBarWindow);
addWindow(mNavBarWindow);
@@ -101,24 +75,20 @@
win.mHasSurface = true;
}
- static Pair<DisplayInfo, WmDisplayCutout> displayInfoAndCutoutForRotation(int rotation,
- boolean withDisplayCutout, boolean isLongEdgeCutout) {
- final DisplayInfo info = new DisplayInfo();
- WmDisplayCutout cutout = WmDisplayCutout.NO_CUTOUT;
-
+ DisplayInfo displayInfoAndCutoutForRotation(int rotation, boolean withDisplayCutout,
+ boolean isLongEdgeCutout) {
+ final DisplayInfo info = mDisplayContent.getDisplayInfo();
final boolean flippedDimensions = rotation == ROTATION_90 || rotation == ROTATION_270;
info.logicalWidth = flippedDimensions ? DISPLAY_HEIGHT : DISPLAY_WIDTH;
info.logicalHeight = flippedDimensions ? DISPLAY_WIDTH : DISPLAY_HEIGHT;
info.rotation = rotation;
- if (withDisplayCutout) {
- cutout = WmDisplayCutout.computeSafeInsets(
- displayCutoutForRotation(rotation, isLongEdgeCutout), info.logicalWidth,
- info.logicalHeight);
- info.displayCutout = cutout.getDisplayCutout();
- } else {
- info.displayCutout = null;
- }
- return Pair.create(info, cutout);
+ mDisplayContent.mInitialDisplayCutout = withDisplayCutout
+ ? displayCutoutForRotation(ROTATION_0, isLongEdgeCutout)
+ : DisplayCutout.NO_CUTOUT;
+ info.displayCutout = mDisplayContent.calculateDisplayCutoutForRotation(rotation);
+ mDisplayContent.updateBaseDisplayMetrics(DISPLAY_WIDTH, DISPLAY_HEIGHT,
+ info.logicalDensityDpi, info.physicalXDpi, info.physicalYDpi);
+ return info;
}
private static DisplayCutout displayCutoutForRotation(int rotation, boolean isLongEdgeCutout) {
@@ -152,33 +122,4 @@
return DisplayCutout.fromBoundingRect((int) rectF.left, (int) rectF.top,
(int) rectF.right, (int) rectF.bottom, pos);
}
-
- static class TestContextWrapper extends ContextWrapper {
- private final TestableResources mResourceMocker;
-
- TestContextWrapper(Context targetContext, Resources targetResources) {
- super(targetContext);
- mResourceMocker = new TestableResources(targetResources);
- }
-
- @Override
- public int checkPermission(String permission, int pid, int uid) {
- return PackageManager.PERMISSION_GRANTED;
- }
-
- @Override
- public int checkPermission(String permission, int pid, int uid, IBinder callerToken) {
- return PackageManager.PERMISSION_GRANTED;
- }
-
- @Override
- public Resources getResources() {
- return mResourceMocker.getResources();
- }
-
- TestableResources getResourceMocker() {
- return mResourceMocker;
- }
- }
-
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
index 892b5f9..89f7111 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
@@ -20,6 +20,7 @@
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_SENSOR;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.view.DisplayCutout.NO_CUTOUT;
import static android.view.IWindowManager.FIXED_TO_USER_ROTATION_DEFAULT;
import static android.view.IWindowManager.FIXED_TO_USER_ROTATION_DISABLED;
import static android.view.IWindowManager.FIXED_TO_USER_ROTATION_ENABLED;
@@ -68,7 +69,6 @@
import com.android.server.UiThread;
import com.android.server.policy.WindowManagerPolicy;
import com.android.server.statusbar.StatusBarManagerInternal;
-import com.android.server.wm.utils.WmDisplayCutout;
import org.junit.After;
import org.junit.AfterClass;
@@ -1008,7 +1008,7 @@
mMockDisplayContent = mock(DisplayContent.class);
mMockDisplayContent.isDefaultDisplay = mIsDefaultDisplay;
when(mMockDisplayContent.calculateDisplayCutoutForRotation(anyInt()))
- .thenReturn(WmDisplayCutout.NO_CUTOUT);
+ .thenReturn(NO_CUTOUT);
when(mMockDisplayContent.getDefaultTaskDisplayArea())
.thenReturn(mock(TaskDisplayArea.class));
when(mMockDisplayContent.getWindowConfiguration())
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
index 093be82..c398a0a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
@@ -110,7 +110,7 @@
mDisplayWindowSettings.applySettingsToDisplayLocked(mPrimaryDisplay);
assertEquals(WindowConfiguration.WINDOWING_MODE_FULLSCREEN,
- mPrimaryDisplay.getWindowingMode());
+ mPrimaryDisplay.getDefaultTaskDisplayArea().getWindowingMode());
}
@Test
@@ -120,7 +120,7 @@
mDisplayWindowSettings.applySettingsToDisplayLocked(mPrimaryDisplay);
assertEquals(WindowConfiguration.WINDOWING_MODE_FULLSCREEN,
- mPrimaryDisplay.getWindowingMode());
+ mPrimaryDisplay.getDefaultTaskDisplayArea().getWindowingMode());
}
@Test
@@ -131,7 +131,7 @@
mDisplayWindowSettings.applySettingsToDisplayLocked(mPrimaryDisplay);
assertEquals(WindowConfiguration.WINDOWING_MODE_FULLSCREEN,
- mPrimaryDisplay.getWindowingMode());
+ mPrimaryDisplay.getDefaultTaskDisplayArea().getWindowingMode());
}
@Test
@@ -141,7 +141,8 @@
mDisplayWindowSettings.applySettingsToDisplayLocked(mPrimaryDisplay);
- assertEquals(WINDOWING_MODE_FREEFORM, mPrimaryDisplay.getWindowingMode());
+ assertEquals(WINDOWING_MODE_FREEFORM,
+ mPrimaryDisplay.getDefaultTaskDisplayArea().getWindowingMode());
}
@Test
@@ -154,7 +155,7 @@
mDisplayWindowSettings.updateSettingsForDisplay(mPrimaryDisplay);
assertEquals(WindowConfiguration.WINDOWING_MODE_FREEFORM,
- mPrimaryDisplay.getWindowingMode());
+ mPrimaryDisplay.getDefaultTaskDisplayArea().getWindowingMode());
}
@Test
@@ -162,7 +163,7 @@
mDisplayWindowSettings.applySettingsToDisplayLocked(mSecondaryDisplay);
assertEquals(WindowConfiguration.WINDOWING_MODE_FULLSCREEN,
- mSecondaryDisplay.getWindowingMode());
+ mSecondaryDisplay.getDefaultTaskDisplayArea().getWindowingMode());
}
@Test
@@ -172,7 +173,7 @@
mDisplayWindowSettings.applySettingsToDisplayLocked(mSecondaryDisplay);
assertEquals(WindowConfiguration.WINDOWING_MODE_FULLSCREEN,
- mSecondaryDisplay.getWindowingMode());
+ mSecondaryDisplay.getDefaultTaskDisplayArea().getWindowingMode());
}
@Test
@@ -183,7 +184,7 @@
mDisplayWindowSettings.applySettingsToDisplayLocked(mSecondaryDisplay);
assertEquals(WINDOWING_MODE_FREEFORM,
- mSecondaryDisplay.getWindowingMode());
+ mSecondaryDisplay.getDefaultTaskDisplayArea().getWindowingMode());
}
@Test
@@ -194,7 +195,7 @@
mDisplayWindowSettings.applySettingsToDisplayLocked(mSecondaryDisplay);
assertEquals(WINDOWING_MODE_FREEFORM,
- mSecondaryDisplay.getWindowingMode());
+ mSecondaryDisplay.getDefaultTaskDisplayArea().getWindowingMode());
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
index 68079f4..601cf15 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
@@ -107,9 +107,10 @@
}
@Test
- public void testUpdateDefaultDisplayWindowingModeOnSettingsRetrieved() {
+ public void testUpdateDefaultTaskDisplayAreaWindowingModeOnSettingsRetrieved() {
assertEquals(WindowConfiguration.WINDOWING_MODE_FULLSCREEN,
- mWm.getDefaultDisplayContentLocked().getWindowingMode());
+ mWm.getDefaultDisplayContentLocked().getDefaultTaskDisplayArea()
+ .getWindowingMode());
mWm.mIsPc = true;
mWm.mAtmService.mSupportsFreeformWindowManagement = true;
@@ -117,7 +118,8 @@
mWm.mRoot.onSettingsRetrieved();
assertEquals(WindowConfiguration.WINDOWING_MODE_FREEFORM,
- mWm.getDefaultDisplayContentLocked().getWindowingMode());
+ mWm.getDefaultDisplayContentLocked().getDefaultTaskDisplayArea()
+ .getWindowingMode());
}
/**
diff --git a/services/tests/wmtests/src/com/android/server/wm/SafeActivityOptionsTest.java b/services/tests/wmtests/src/com/android/server/wm/SafeActivityOptionsTest.java
index 7111852..e57ad5d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SafeActivityOptionsTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SafeActivityOptionsTest.java
@@ -17,9 +17,12 @@
package com.android.server.wm;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+import static org.mockito.Mockito.mock;
import android.app.ActivityOptions;
import android.platform.test.annotations.Presubmit;
+import android.window.WindowContainerToken;
import androidx.test.filters.MediumTest;
@@ -43,4 +46,21 @@
final ActivityOptions result = options.mergeActivityOptions(opts1, opts2);
assertEquals(6, result.getLaunchDisplayId());
}
+
+ @Test
+ public void test_selectiveCloneDisplayOptions() {
+ final WindowContainerToken token = mock(WindowContainerToken.class);
+ final int launchDisplayId = 5;
+ final int callerDisplayId = 6;
+
+ final SafeActivityOptions clone = new SafeActivityOptions(ActivityOptions.makeBasic()
+ .setLaunchTaskDisplayArea(token)
+ .setLaunchDisplayId(launchDisplayId)
+ .setCallerDisplayId(callerDisplayId))
+ .selectiveCloneDisplayOptions();
+
+ assertSame(clone.getOriginalOptions().getLaunchTaskDisplayArea(), token);
+ assertEquals(clone.getOriginalOptions().getLaunchDisplayId(), launchDisplayId);
+ assertEquals(clone.getOriginalOptions().getCallerDisplayId(), callerDisplayId);
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index 85f85f1..60d3f10 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -676,7 +676,8 @@
// The non-resizable activity should not be size compat because the display support
// changing windowing mode from fullscreen to freeform.
- mTask.mDisplayContent.setDisplayWindowingMode(WindowConfiguration.WINDOWING_MODE_FREEFORM);
+ mTask.mDisplayContent.getDefaultTaskDisplayArea()
+ .setWindowingMode(WindowConfiguration.WINDOWING_MODE_FREEFORM);
mTask.setWindowingMode(WindowConfiguration.WINDOWING_MODE_FULLSCREEN);
assertFalse(activity.shouldCreateCompatDisplayInsets());
// Activity should not be sandboxed.
@@ -1640,6 +1641,75 @@
}
@Test
+ @EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO,
+ ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_LARGE,
+ ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_EXCLUDE_PORTRAIT_FULLSCREEN})
+ public void testOverrideMinAspectRatioExcludePortraitFullscreen() {
+ setUpDisplaySizeWithApp(2600, 1600);
+ mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+ mActivity.mWmService.mLetterboxConfiguration.setFixedOrientationLetterboxAspectRatio(1.33f);
+
+ // Create a size compat activity on the same task.
+ final ActivityRecord activity = new ActivityBuilder(mAtm)
+ .setTask(mTask)
+ .setComponent(ComponentName.createRelative(mContext,
+ SizeCompatTests.class.getName()))
+ .setUid(android.os.Process.myUid())
+ .build();
+
+ // Non-resizable portrait activity
+ prepareUnresizable(activity, 0f, ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
+
+ // At first, OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_FULLSCREEN does not apply, because the
+ // display is in landscape
+ assertEquals(1600, activity.getBounds().height());
+ assertEquals(1600 / ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_LARGE_VALUE,
+ activity.getBounds().width(), 0.5);
+
+ rotateDisplay(activity.mDisplayContent, ROTATION_90);
+ prepareUnresizable(activity, /* maxAspect */ 0, SCREEN_ORIENTATION_PORTRAIT);
+
+ // Now the display is in portrait fullscreen, so the override is applied making the content
+ // fullscreen
+ assertEquals(activity.getBounds(), activity.mDisplayContent.getBounds());
+ }
+
+ @Test
+ @EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO,
+ ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_LARGE,
+ ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_EXCLUDE_PORTRAIT_FULLSCREEN})
+ public void testOverrideMinAspectRatioExcludePortraitFullscreenNotApplied() {
+ // In this test, the activity is not in fullscreen, so the override is not applied
+ setUpDisplaySizeWithApp(2600, 1600);
+ mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+ mActivity.mWmService.mLetterboxConfiguration.setFixedOrientationLetterboxAspectRatio(1.33f);
+
+ // Create a size compat activity on the same task.
+ final ActivityRecord activity = new ActivityBuilder(mAtm)
+ .setTask(mTask)
+ .setComponent(ComponentName.createRelative(mContext,
+ SizeCompatTests.class.getName()))
+ .setUid(android.os.Process.myUid())
+ .build();
+
+ final TestSplitOrganizer organizer =
+ new TestSplitOrganizer(mAtm, activity.getDisplayContent());
+
+ // Move first activity to split screen which takes half of the screen.
+ organizer.mPrimary.setBounds(0, 0, 1300, 1600);
+ organizer.putTaskToPrimary(mTask, true);
+
+ // Non-resizable portrait activity
+ prepareUnresizable(activity, /* maxAspect */ 0, SCREEN_ORIENTATION_PORTRAIT);
+
+ // OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_FULLSCREEN does not apply here because the
+ // display is not in fullscreen, so OVERRIDE_MIN_ASPECT_RATIO_LARGE applies instead
+ assertEquals(1600, activity.getBounds().height());
+ assertEquals(1600 / ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_LARGE_VALUE,
+ activity.getBounds().width(), 0.5);
+ }
+
+ @Test
public void testSplitAspectRatioForUnresizableLandscapeApps() {
// Set up a display in portrait and ignoring orientation request.
int screenWidth = 1400;
@@ -3064,8 +3134,8 @@
}
private static void resizeDisplay(DisplayContent displayContent, int width, int height) {
- displayContent.mBaseDisplayWidth = width;
- displayContent.mBaseDisplayHeight = height;
+ displayContent.updateBaseDisplayMetrics(width, height, displayContent.mBaseDisplayDensity,
+ displayContent.mBaseDisplayPhysicalXDpi, displayContent.mBaseDisplayPhysicalYDpi);
final Configuration c = new Configuration();
displayContent.computeScreenConfiguration(c);
displayContent.onRequestedOverrideConfigurationChanged(c);
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
index 6d514b2..ca817ab 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -345,7 +345,7 @@
// Set default display to be in fullscreen mode. Devices with PC feature may start their
// default display in freeform mode but some of tests in WmTests have implicit assumption on
// that the default display is in fullscreen mode.
- display.setDisplayWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ display.getDefaultTaskDisplayArea().setWindowingMode(WINDOWING_MODE_FULLSCREEN);
spyOn(display);
final TaskDisplayArea taskDisplayArea = display.getDefaultTaskDisplayArea();
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
index c0759c1..a6c5fd8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
@@ -1775,7 +1775,7 @@
private TestDisplayContent createNewDisplayContent(int windowingMode) {
final TestDisplayContent display = addNewDisplayContentAt(DisplayContent.POSITION_TOP);
- display.setWindowingMode(windowingMode);
+ display.getDefaultTaskDisplayArea().setWindowingMode(windowingMode);
display.setBounds(DISPLAY_BOUNDS);
display.getConfiguration().densityDpi = DENSITY_DEFAULT;
display.getConfiguration().orientation = ORIENTATION_LANDSCAPE;
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
index f4323db..76cd19b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
@@ -36,7 +36,6 @@
import static android.view.Surface.ROTATION_90;
import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_FIRST;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
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.times;
@@ -264,7 +263,8 @@
// Detach from process so the activities can be removed from hierarchy when finishing.
activity1.detachFromProcess();
activity2.detachFromProcess();
- assertTrue(task.performClearTop(activity1, 0 /* launchFlags */).finishing);
+ int[] finishCount = new int[1];
+ assertTrue(task.performClearTop(activity1, 0 /* launchFlags */, finishCount).finishing);
assertFalse(task.hasChild());
// In real case, the task should be preserved for adding new activity.
assertTrue(task.isAttached());
@@ -278,7 +278,7 @@
doReturn(true).when(activityB).shouldBeVisibleUnchecked();
doReturn(true).when(activityC).shouldBeVisibleUnchecked();
activityA.getConfiguration().densityDpi += 100;
- assertTrue(task.performClearTop(activityA, 0 /* launchFlags */).finishing);
+ assertTrue(task.performClearTop(activityA, 0 /* launchFlags */, finishCount).finishing);
// The bottom activity should destroy directly without relaunch for config change.
assertEquals(ActivityRecord.State.DESTROYING, activityA.getState());
verify(activityA, never()).startRelaunching();
@@ -692,12 +692,9 @@
// Setup the display with a top stable inset. The later assertion will ensure the inset is
// excluded from screenHeightDp.
final int statusBarHeight = 100;
- final DisplayPolicy policy = display.getDisplayPolicy();
- doAnswer(invocationOnMock -> {
- final Rect insets = invocationOnMock.<Rect>getArgument(0);
- insets.top = statusBarHeight;
- return null;
- }).when(policy).convertNonDecorInsetsToStableInsets(any(), eq(ROTATION_0));
+ final DisplayInfo di = display.getDisplayInfo();
+ display.getDisplayPolicy().getDecorInsetsInfo(di.rotation,
+ di.logicalWidth, di.logicalHeight).mConfigInsets.top = statusBarHeight;
// Without limiting to be inside the parent bounds, the out screen size should keep relative
// to the input bounds.
@@ -1259,7 +1256,8 @@
final Task task = getTestTask();
task.setHasBeenVisible(false);
- task.getDisplayContent().setDisplayWindowingMode(WINDOWING_MODE_FREEFORM);
+ task.getDisplayContent().getDefaultTaskDisplayArea()
+ .setWindowingMode(WINDOWING_MODE_FREEFORM);
task.getRootTask().setWindowingMode(WINDOWING_MODE_FULLSCREEN);
task.setHasBeenVisible(true);
@@ -1275,7 +1273,9 @@
final Task task = getTestTask();
task.setHasBeenVisible(false);
- task.getDisplayContent().setWindowingMode(WindowConfiguration.WINDOWING_MODE_FREEFORM);
+ task.getDisplayContent()
+ .getDefaultTaskDisplayArea()
+ .setWindowingMode(WindowConfiguration.WINDOWING_MODE_FREEFORM);
task.getRootTask().setWindowingMode(WINDOWING_MODE_FULLSCREEN);
final DisplayContent oldDisplay = task.getDisplayContent();
@@ -1315,7 +1315,8 @@
final Task task = getTestTask();
task.setHasBeenVisible(false);
- task.getDisplayContent().setDisplayWindowingMode(WINDOWING_MODE_FREEFORM);
+ task.getDisplayContent().getDefaultTaskDisplayArea()
+ .setWindowingMode(WINDOWING_MODE_FREEFORM);
task.getRootTask().setWindowingMode(WINDOWING_MODE_PINNED);
task.setHasBeenVisible(true);
@@ -1332,7 +1333,8 @@
final Task task = new TaskBuilder(mSupervisor).setCreateActivity(true)
.setCreateParentTask(true).build().getRootTask();
task.setHasBeenVisible(false);
- task.getDisplayContent().setDisplayWindowingMode(WINDOWING_MODE_FREEFORM);
+ task.getDisplayContent().getDefaultTaskDisplayArea()
+ .setWindowingMode(WINDOWING_MODE_FREEFORM);
task.getRootTask().setWindowingMode(WINDOWING_MODE_FULLSCREEN);
final Task leafTask = createTaskInRootTask(task, 0 /* userId */);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java b/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java
index f5304d0..aa3ca18 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java
@@ -18,13 +18,6 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS;
-import static android.view.InsetsState.ITYPE_BOTTOM_DISPLAY_CUTOUT;
-import static android.view.InsetsState.ITYPE_CLIMATE_BAR;
-import static android.view.InsetsState.ITYPE_LEFT_DISPLAY_CUTOUT;
-import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
-import static android.view.InsetsState.ITYPE_RIGHT_DISPLAY_CUTOUT;
-import static android.view.InsetsState.ITYPE_STATUS_BAR;
-import static android.view.InsetsState.ITYPE_TOP_DISPLAY_CUTOUT;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_BOTTOM;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
@@ -33,7 +26,6 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import android.annotation.Nullable;
@@ -47,7 +39,6 @@
import android.view.Display;
import android.view.DisplayCutout;
import android.view.DisplayInfo;
-import android.view.WindowInsets;
import com.android.server.wm.DisplayWindowSettings.SettingsProvider.SettingsEntry;
@@ -209,26 +200,6 @@
doReturn(true).when(newDisplay).supportsSystemDecorations();
doReturn(true).when(displayPolicy).hasNavigationBar();
doReturn(NAV_BAR_BOTTOM).when(displayPolicy).navigationBarPosition(anyInt());
- doReturn(Insets.of(0, 0, 0, 20)).when(displayPolicy).getInsets(any(),
- eq(WindowInsets.Type.displayCutout() | WindowInsets.Type.navigationBars()));
- doReturn(Insets.of(0, 20, 0, 20)).when(displayPolicy).getInsets(any(),
- eq(WindowInsets.Type.displayCutout() | WindowInsets.Type.navigationBars()
- | WindowInsets.Type.statusBars()));
- final int[] nonDecorTypes = new int[]{
- ITYPE_TOP_DISPLAY_CUTOUT, ITYPE_RIGHT_DISPLAY_CUTOUT,
- ITYPE_BOTTOM_DISPLAY_CUTOUT, ITYPE_LEFT_DISPLAY_CUTOUT, ITYPE_NAVIGATION_BAR
- };
- doReturn(Insets.of(0, 0, 0, 20)).when(displayPolicy).getInsetsWithInternalTypes(
- any(),
- eq(nonDecorTypes));
- final int[] stableTypes = new int[]{
- ITYPE_TOP_DISPLAY_CUTOUT, ITYPE_RIGHT_DISPLAY_CUTOUT,
- ITYPE_BOTTOM_DISPLAY_CUTOUT, ITYPE_LEFT_DISPLAY_CUTOUT,
- ITYPE_NAVIGATION_BAR, ITYPE_STATUS_BAR, ITYPE_CLIMATE_BAR
- };
- doReturn(Insets.of(0, 20, 0, 20)).when(displayPolicy).getInsetsWithInternalTypes(
- any(),
- eq(stableTypes));
} else {
doReturn(false).when(displayPolicy).hasNavigationBar();
doReturn(false).when(displayPolicy).hasStatusBar();
@@ -241,11 +212,6 @@
displayPolicy.finishScreenTurningOn();
if (mStatusBarHeight > 0) {
doReturn(true).when(displayPolicy).hasStatusBar();
- doAnswer(invocation -> {
- Rect inOutInsets = (Rect) invocation.getArgument(0);
- inOutInsets.top = mStatusBarHeight;
- return null;
- }).when(displayPolicy).convertNonDecorInsetsToStableInsets(any(), anyInt());
}
Configuration c = new Configuration();
newDisplay.computeScreenConfiguration(c);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
index 4f68e98..8f186e4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
@@ -27,6 +27,7 @@
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
+import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_BACK;
@@ -82,6 +83,7 @@
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Objects;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
@@ -962,8 +964,17 @@
@Test
public void testTransientLaunch() {
final TaskSnapshotController snapshotController = mock(TaskSnapshotController.class);
+ final ArrayList<ActivityRecord> enteringAnimReports = new ArrayList<>();
final TransitionController controller = new TransitionController(mAtm, snapshotController,
- mock(TransitionTracer.class));
+ mock(TransitionTracer.class)) {
+ @Override
+ protected void dispatchLegacyAppTransitionFinished(ActivityRecord ar) {
+ if (ar.mEnteringAnimation) {
+ enteringAnimReports.add(ar);
+ }
+ super.dispatchLegacyAppTransitionFinished(ar);
+ }
+ };
final ITransitionPlayer player = new ITransitionPlayer.Default();
controller.registerTransitionPlayer(player, null /* playerProc */);
final Transition openTransition = controller.createTransition(TRANSIT_OPEN);
@@ -1008,6 +1019,7 @@
activity1.mVisibleRequested = false;
activity2.mVisibleRequested = true;
+ activity2.setVisible(true);
// Using abort to force-finish the sync (since we obviously can't wait for drawing).
// We didn't call abort on the actual transition, so it will still run onTransactionReady
@@ -1018,9 +1030,11 @@
// called until finish).
verify(snapshotController, times(0)).recordTaskSnapshot(eq(task1), eq(false));
+ enteringAnimReports.clear();
closeTransition.finishTransition();
verify(snapshotController, times(1)).recordTaskSnapshot(eq(task1), eq(false));
+ assertTrue(enteringAnimReports.contains(activity2));
}
@Test
@@ -1167,6 +1181,42 @@
assertTrue(mSyncEngine.isReady(transition.getSyncId()));
}
+ @Test
+ public void testVisibleChange_snapshot() {
+ registerTestTransitionPlayer();
+ final ActivityRecord app = createActivityRecord(mDisplayContent);
+ final Transition transition = new Transition(TRANSIT_CHANGE, 0 /* flags */,
+ app.mTransitionController, mWm.mSyncEngine);
+ app.mTransitionController.moveToCollecting(transition, BLASTSyncEngine.METHOD_NONE);
+ final SurfaceControl mockSnapshot = mock(SurfaceControl.class);
+ transition.setContainerFreezer(new Transition.IContainerFreezer() {
+ @Override
+ public boolean freeze(@NonNull WindowContainer wc, @NonNull Rect bounds) {
+ Objects.requireNonNull(transition.mChanges.get(wc)).mSnapshot = mockSnapshot;
+ return true;
+ }
+
+ @Override
+ public void cleanUp(SurfaceControl.Transaction t) {
+ }
+ });
+ final Task task = app.getTask();
+ transition.collect(task);
+ final Rect bounds = new Rect(task.getBounds());
+ Configuration c = new Configuration(task.getRequestedOverrideConfiguration());
+ bounds.inset(10, 10);
+ c.windowConfiguration.setBounds(bounds);
+ task.onRequestedOverrideConfigurationChanged(c);
+
+ ArrayList<WindowContainer> targets = Transition.calculateTargets(
+ transition.mParticipants, transition.mChanges);
+ TransitionInfo info = Transition.calculateTransitionInfo(
+ TRANSIT_CHANGE, 0, targets, transition.mChanges, mMockT);
+ assertEquals(mockSnapshot,
+ info.getChange(task.mRemoteToken.toWindowContainerToken()).getSnapshot());
+ transition.abort();
+ }
+
private static void makeTaskOrganized(Task... tasks) {
final ITaskOrganizer organizer = mock(ITaskOrganizer.class);
for (Task t : tasks) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
index 8288713..6333508 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
@@ -52,6 +52,7 @@
import android.os.IBinder;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
+import android.view.DisplayCutout;
import android.view.DisplayInfo;
import android.view.Gravity;
import android.view.InsetsState;
@@ -63,8 +64,6 @@
import androidx.test.filters.SmallTest;
-import com.android.server.wm.utils.WmDisplayCutout;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -164,8 +163,8 @@
// Apply the fixed transform
Configuration config = new Configuration();
final DisplayInfo info = dc.computeScreenConfiguration(config, Surface.ROTATION_0);
- final WmDisplayCutout cutout = dc.calculateDisplayCutoutForRotation(Surface.ROTATION_0);
- final DisplayFrames displayFrames = new DisplayFrames(dc.getDisplayId(), new InsetsState(),
+ final DisplayCutout cutout = dc.calculateDisplayCutoutForRotation(Surface.ROTATION_0);
+ final DisplayFrames displayFrames = new DisplayFrames(new InsetsState(),
info, cutout, RoundedCorners.NO_ROUNDED_CORNERS, new PrivacyIndicatorBounds());
wallpaperWindow.mToken.applyFixedRotationTransform(info, displayFrames, config);
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 77e12f4..b6373b4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -26,6 +26,7 @@
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.os.Process.SYSTEM_UID;
+import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
import static android.view.View.VISIBLE;
import static android.view.WindowManager.DISPLAY_IME_POLICY_FALLBACK_DISPLAY;
import static android.view.WindowManager.DISPLAY_IME_POLICY_LOCAL;
@@ -69,6 +70,7 @@
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
+import android.graphics.Insets;
import android.graphics.Rect;
import android.hardware.HardwareBuffer;
import android.hardware.display.DisplayManager;
@@ -84,6 +86,7 @@
import android.view.Gravity;
import android.view.IDisplayWindowInsetsController;
import android.view.IWindow;
+import android.view.InsetsFrameProvider;
import android.view.InsetsSourceControl;
import android.view.InsetsState;
import android.view.InsetsVisibilities;
@@ -417,6 +420,15 @@
true /* ownerCanManageAppTokens */);
}
+ WindowState createNavBarWithProvidedInsets(DisplayContent dc) {
+ final WindowState navbar = createWindow(null, TYPE_NAVIGATION_BAR, dc, "navbar");
+ navbar.mAttrs.providedInsets = new InsetsFrameProvider[] {
+ new InsetsFrameProvider(ITYPE_NAVIGATION_BAR, Insets.of(0, 0, 0, NAV_BAR_HEIGHT))
+ };
+ dc.getDisplayPolicy().addWindowLw(navbar, navbar.mAttrs);
+ return navbar;
+ }
+
WindowState createAppWindow(Task task, int type, String name) {
final ActivityRecord activity = createNonAttachedActivityRecord(task.getDisplayContent());
task.addChild(activity, 0);
diff --git a/telephony/java/android/telephony/DataFailCause.java b/telephony/java/android/telephony/DataFailCause.java
index e882b25..418f518 100644
--- a/telephony/java/android/telephony/DataFailCause.java
+++ b/telephony/java/android/telephony/DataFailCause.java
@@ -987,8 +987,17 @@
/** The ePDG does not support un-authenticated IMSI based emergency PDN bringup **/
public static final int IWLAN_UNAUTHENTICATED_EMERGENCY_NOT_SUPPORTED = 0x2B2F;
- // Device is unable to establish an IPSec tunnel with the ePDG for any reason
- // e.g authentication fail or certificate validation or DNS Resolution and timeout failure.
+ // The below error causes are relevant when the device is unable to establish an IPSec tunnel
+ // with the ePDG for any reason, e.g. authentication fail or certificate validation or DNS
+ // Resolution and timeout failure.
+
+ /**
+ * The requested service was rejected because of congestion in the network while accessing the
+ * IWLAN ePDG. Defined in 3GPP TS 24.502, Section 9.2.4.2.
+ *
+ * @hide
+ */
+ public static final int IWLAN_CONGESTION = 0x3C8C;
/** IKE configuration error resulting in failure */
public static final int IWLAN_IKEV2_CONFIG_FAILURE = 0x4000;
diff --git a/tests/FlickerTests/test-apps/flickerapp/Android.bp b/tests/FlickerTests/test-apps/flickerapp/Android.bp
index 78660c0..fffe33a 100644
--- a/tests/FlickerTests/test-apps/flickerapp/Android.bp
+++ b/tests/FlickerTests/test-apps/flickerapp/Android.bp
@@ -24,6 +24,20 @@
android_test {
name: "FlickerTestApp",
srcs: ["**/*.java"],
+ static_libs: [
+ "androidx.annotation_annotation",
+ "androidx.appcompat_appcompat",
+ "androidx-constraintlayout_constraintlayout",
+ "androidx.core_core",
+ "androidx.fragment_fragment",
+ "androidx.recyclerview_recyclerview",
+ "androidx.navigation_navigation-common-ktx",
+ "androidx.navigation_navigation-fragment-ktx",
+ "androidx.navigation_navigation-runtime-ktx",
+ "androidx.navigation_navigation-ui-ktx",
+ "kotlin-stdlib",
+ "kotlinx-coroutines-android",
+ ],
sdk_version: "current",
test_suites: ["device-tests"],
}
diff --git a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
index 3e2130d..66ad6f1 100644
--- a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
@@ -163,5 +163,27 @@
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
+ <activity android:name=".MailActivity"
+ android:exported="true"
+ android:label="MailApp"
+ android:taskAffinity="com.android.server.wm.flicker.testapp.MailActivity"
+ android:theme="@style/Theme.AppCompat.Light">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity>
+ <activity android:name=".GameActivity"
+ android:taskAffinity="com.android.server.wm.flicker.testapp.GameActivity"
+ android:immersive="true"
+ android:theme="@android:style/Theme.NoTitleBar"
+ android:configChanges="screenSize"
+ android:label="GameApp"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity>
</application>
</manifest>
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/anim/slide_in_from_bottom.xml b/tests/FlickerTests/test-apps/flickerapp/res/anim/slide_in_from_bottom.xml
new file mode 100644
index 0000000..c0165e5
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/res/anim/slide_in_from_bottom.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:interpolator="@android:anim/linear_interpolator"
+ android:shareInterpolator="false">
+ <translate
+ android:duration="500"
+ android:fromYDelta="100%p"
+ android:toYDelta="0%p" />
+</set>
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_mail.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_mail.xml
new file mode 100644
index 0000000..8a97433
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_mail.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+
+<androidx.constraintlayout.widget.ConstraintLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <fragment
+ android:id="@+id/main_fragment"
+ android:name="androidx.navigation.fragment.NavHostFragment"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ app:defaultNavHost="true"
+ app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintRight_toRightOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ app:navGraph="@navigation/mail_navigation"></fragment>
+</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_surfaceview.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_surfaceview.xml
new file mode 100644
index 0000000..0b4693d
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_surfaceview.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@android:color/holo_orange_light">
+
+ <SurfaceView
+ android:id="@+id/surface_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"/>
+</LinearLayout>
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/fragment_mail_content.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/fragment_mail_content.xml
new file mode 100644
index 0000000..fbbdc5b
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/fragment_mail_content.xml
@@ -0,0 +1,21 @@
+<!--
+ ~ 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.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+</LinearLayout>
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/fragment_mail_list.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/fragment_mail_list.xml
new file mode 100644
index 0000000..0e30745
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/fragment_mail_list.xml
@@ -0,0 +1,25 @@
+<!--
+ ~ 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.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+ <androidx.recyclerview.widget.RecyclerView
+ android:id="@+id/mail_recycle_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/mail_row_item.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/mail_row_item.xml
new file mode 100644
index 0000000..c39bfb3
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/mail_row_item.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/list_item_height"
+ android:layout_marginLeft="@dimen/margin_medium"
+ android:layout_marginRight="@dimen/margin_medium">
+ <ImageView
+ android:id="@+id/mail_row_item_icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingBottom="@dimen/padding_small"
+ android:paddingEnd="@dimen/padding_small"
+ android:paddingStart="@dimen/padding_small"
+ android:paddingTop="@dimen/padding_small"/>
+ <TextView
+ android:id="@+id/mail_row_item_text"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:paddingEnd="@dimen/padding_small"
+ android:textSize="@dimen/list_item_text_size" />
+</LinearLayout>
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/navigation/mail_navigation.xml b/tests/FlickerTests/test-apps/flickerapp/res/navigation/mail_navigation.xml
new file mode 100644
index 0000000..d12707a
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/res/navigation/mail_navigation.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+
+<navigation xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/mail_navigation"
+ app:startDestination="@id/fragment_mail_list">
+ <fragment
+ android:id="@+id/fragment_mail_list"
+ android:name=".MailListFragment"
+ android:label="Mail List">
+ <action
+ android:id="@+id/action_mail_list_to_mail_content"
+ app:destination="@id/fragment_mail_content"
+ app:enterAnim="@anim/slide_in_from_bottom" />
+ </fragment>
+ <fragment
+ android:id="@+id/fragment_mail_content"
+ android:name=".MailContentFragment"
+ android:label="Mail Content">
+ </fragment>
+</navigation>
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/values/dimens.xml b/tests/FlickerTests/test-apps/flickerapp/res/values/dimens.xml
new file mode 100644
index 0000000..0b0763d
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/res/values/dimens.xml
@@ -0,0 +1,24 @@
+<!--
+ ~ 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.
+ -->
+
+<resources>
+ <dimen name="padding_small">8dp</dimen>
+ <dimen name="margin_medium">16dp</dimen>
+ <dimen name="list_item_height">72dp</dimen>
+ <dimen name="list_item_text_size">24dp</dimen>
+ <dimen name="icon_size">64dp</dimen>
+ <dimen name="icon_text_size">36dp</dimen>
+</resources>
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
index 6cda482..42a37df 100644
--- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
@@ -87,4 +87,9 @@
public static final ComponentName NOTIFICATION_ACTIVITY_COMPONENT_NAME =
new ComponentName(FLICKER_APP_PACKAGE,
FLICKER_APP_PACKAGE + ".NotificationActivity");
+
+ public static final String GAME_ACTIVITY_LAUNCHER_NAME = "GameApp";
+ public static final ComponentName GAME_ACTIVITY_COMPONENT_NAME =
+ new ComponentName(FLICKER_APP_PACKAGE,
+ FLICKER_APP_PACKAGE + ".GameActivity");
}
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/GameActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/GameActivity.java
new file mode 100644
index 0000000..ef75d4d
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/GameActivity.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.testapp;
+
+import android.app.Activity;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.PixelFormat;
+import android.os.Bundle;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+
+import androidx.core.view.ViewCompat;
+import androidx.core.view.WindowInsetsCompat;
+import androidx.core.view.WindowInsetsControllerCompat;
+
+public class GameActivity extends Activity implements SurfaceHolder.Callback {
+ private SurfaceHolder mSurfaceHolder;
+ private SurfaceView mSurfaceView;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setContentView(R.layout.activity_surfaceview);
+
+ mSurfaceView = (SurfaceView) findViewById(R.id.surface_view);
+ mSurfaceView.setZOrderOnTop(true);
+ mSurfaceHolder = mSurfaceView.getHolder();
+ mSurfaceHolder.setFormat(PixelFormat.TRANSPARENT);
+ mSurfaceHolder.addCallback(this);
+ }
+
+ @Override
+ public void surfaceCreated(SurfaceHolder holder) {
+ hideSystemBars();
+ }
+
+ @Override
+ public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+ Canvas canvas = holder.lockCanvas();
+ canvas.drawColor(Color.BLUE);
+ holder.unlockCanvasAndPost(canvas);
+ }
+
+ @Override
+ public void surfaceDestroyed(SurfaceHolder holder) {
+ }
+
+ private void hideSystemBars() {
+ WindowInsetsControllerCompat windowInsetsController =
+ ViewCompat.getWindowInsetsController(getWindow().getDecorView());
+ if (windowInsetsController == null) {
+ return;
+ }
+ // Configure the behavior of the hidden system bars.
+ windowInsetsController.setSystemBarsBehavior(
+ WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
+ );
+ // Hide both the status bar and the navigation bar.
+ windowInsetsController.hide(WindowInsetsCompat.Type.systemBars());
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeConstants.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/MailActivity.java
similarity index 60%
copy from libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeConstants.java
copy to tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/MailActivity.java
index e62a63a..419d438 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeConstants.java
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/MailActivity.java
@@ -14,18 +14,18 @@
* limitations under the License.
*/
-package com.android.wm.shell.desktopmode;
+package com.android.server.wm.flicker.testapp;
-import android.os.SystemProperties;
+import android.os.Bundle;
-/**
- * Constants for desktop mode feature
- */
-public class DesktopModeConstants {
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AppCompatActivity;
- /**
- * Flag to indicate whether desktop mode is available on the device
- */
- public static final boolean IS_FEATURE_ENABLED = SystemProperties.getBoolean(
- "persist.wm.debug.desktop_mode", false);
+public class MailActivity extends AppCompatActivity {
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_mail);
+ }
}
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/MailAdapter.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/MailAdapter.java
new file mode 100644
index 0000000..984263a
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/MailAdapter.java
@@ -0,0 +1,134 @@
+/*
+ * 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.wm.flicker.testapp;
+
+import static androidx.navigation.fragment.NavHostFragment.findNavController;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Typeface;
+import android.graphics.drawable.ShapeDrawable;
+import android.graphics.drawable.shapes.OvalShape;
+import android.graphics.drawable.shapes.Shape;
+import android.util.DisplayMetrics;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.fragment.app.Fragment;
+import androidx.navigation.NavController;
+import androidx.recyclerview.widget.RecyclerView;
+
+public class MailAdapter extends RecyclerView.Adapter<MailAdapter.ViewHolder> {
+
+ private final Fragment mFragment;
+ private final int mSize;
+
+ static class BadgeShape extends OvalShape {
+ Context mContext;
+ String mLabel;
+
+ BadgeShape(Context context, String label) {
+ mContext = context;
+ mLabel = label;
+ }
+
+ @Override
+ public void draw(Canvas canvas, Paint paint) {
+ final Resources resources = mContext.getResources();
+ int textSize = resources.getDimensionPixelSize(R.dimen.icon_text_size);
+ paint.setColor(Color.BLACK);
+ super.draw(canvas, paint);
+ paint.setColor(Color.WHITE);
+ paint.setTextSize(textSize);
+ paint.setTypeface(Typeface.DEFAULT_BOLD);
+ paint.setTextAlign(Paint.Align.CENTER);
+ Paint.FontMetrics fontMetrics = paint.getFontMetrics();
+ float distance = (fontMetrics.bottom - fontMetrics.top) / 2 - fontMetrics.bottom;
+ canvas.drawText(
+ mLabel,
+ rect().centerX(),
+ rect().centerY() + distance,
+ paint);
+ }
+ }
+
+ static class ViewHolder extends RecyclerView.ViewHolder {
+
+ NavController mNavController;
+ ImageView mImageView;
+ TextView mTextView;
+ DisplayMetrics mDisplayMetrics;
+
+ ViewHolder(@NonNull View itemView, NavController navController) {
+ super(itemView);
+ mNavController = navController;
+ itemView.setOnClickListener(this::onClick);
+ mImageView = itemView.findViewById(R.id.mail_row_item_icon);
+ mTextView = itemView.findViewById(R.id.mail_row_item_text);
+ mDisplayMetrics = itemView.getContext().getResources().getDisplayMetrics();
+ }
+
+ void onClick(View v) {
+ mNavController.navigate(R.id.action_mail_list_to_mail_content);
+ }
+
+ public void setContent(int i) {
+ final Resources resources = mImageView.getContext().getResources();
+ final int badgeSize = resources.getDimensionPixelSize(R.dimen.icon_size);
+ final char c = (char) ('A' + i % 26);
+ final Shape badge = new BadgeShape(mImageView.getContext(), String.valueOf(c));
+ ShapeDrawable drawable = new ShapeDrawable();
+ drawable.setIntrinsicHeight(badgeSize);
+ drawable.setIntrinsicWidth(badgeSize);
+ drawable.setShape(badge);
+ mImageView.setImageDrawable(drawable);
+ mTextView.setText(String.format("%s-%04d", c, i));
+ }
+ }
+
+ public MailAdapter(Fragment fragment, int size) {
+ super();
+ mFragment = fragment;
+ mSize = size;
+ }
+
+ @NonNull
+ @Override
+ public ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
+ View v = LayoutInflater
+ .from(viewGroup.getContext())
+ .inflate(R.layout.mail_row_item, viewGroup, false);
+ return new ViewHolder(v, findNavController(mFragment));
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull ViewHolder viewHolder, int i) {
+ viewHolder.setContent(i);
+ }
+
+ @Override
+ public int getItemCount() {
+ return mSize;
+ }
+}
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/MailContentFragment.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/MailContentFragment.java
new file mode 100644
index 0000000..278b92e
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/MailContentFragment.java
@@ -0,0 +1,36 @@
+/*
+ * 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.wm.flicker.testapp;
+
+import android.graphics.Color;
+import android.os.Bundle;
+import android.view.View;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
+
+public class MailContentFragment extends Fragment {
+ public MailContentFragment() {
+ super(R.layout.fragment_mail_content);
+ }
+
+ @Override
+ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+ view.setBackgroundColor(Color.LTGRAY);
+ }
+}
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/MailListFragment.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/MailListFragment.java
new file mode 100644
index 0000000..551820c
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/MailListFragment.java
@@ -0,0 +1,49 @@
+/*
+ * 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.wm.flicker.testapp;
+
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.fragment.app.Fragment;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+public class MailListFragment extends Fragment {
+
+ protected RecyclerView mRecyclerView;
+ protected RecyclerView.LayoutManager mLayoutManager;
+ protected MailAdapter mAdapter;
+
+ public MailListFragment() {
+ super(R.layout.fragment_mail_list);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ View rootView = inflater.inflate(R.layout.fragment_mail_list, container, false);
+ mRecyclerView = rootView.findViewById(R.id.mail_recycle_view);
+ mAdapter = new MailAdapter(this, 1000);
+ mRecyclerView.setAdapter(mAdapter);
+ mLayoutManager = new LinearLayoutManager(getActivity());
+ mRecyclerView.setLayoutManager(mLayoutManager);
+ return rootView;
+ }
+}
diff --git a/tests/permission/src/com/android/framework/permission/tests/VibratorManagerServicePermissionTest.java b/tests/permission/src/com/android/framework/permission/tests/VibratorManagerServicePermissionTest.java
index e0f3f03..421ceb7 100644
--- a/tests/permission/src/com/android/framework/permission/tests/VibratorManagerServicePermissionTest.java
+++ b/tests/permission/src/com/android/framework/permission/tests/VibratorManagerServicePermissionTest.java
@@ -50,6 +50,7 @@
public class VibratorManagerServicePermissionTest {
private static final String PACKAGE_NAME = "com.android.framework.permission.tests";
+ private static final int DISPLAY_ID = 1;
private static final CombinedVibration EFFECT =
CombinedVibration.createParallel(
VibrationEffect.createOneShot(100, VibrationEffect.DEFAULT_AMPLITUDE));
@@ -106,7 +107,8 @@
@Test
public void testVibrateWithoutPermissionFails() throws RemoteException {
expectSecurityException("VIBRATE");
- mVibratorService.vibrate(Process.myUid(), PACKAGE_NAME, EFFECT, ATTRS, "testVibrate",
+ mVibratorService.vibrate(Process.myUid(), DISPLAY_ID, PACKAGE_NAME, EFFECT, ATTRS,
+ "testVibrate",
new Binder());
}
@@ -115,7 +117,8 @@
throws RemoteException {
getInstrumentation().getUiAutomation().adoptShellPermissionIdentity(
Manifest.permission.VIBRATE);
- mVibratorService.vibrate(Process.myUid(), PACKAGE_NAME, EFFECT, ATTRS, "testVibrate",
+ mVibratorService.vibrate(Process.myUid(), DISPLAY_ID, PACKAGE_NAME, EFFECT, ATTRS,
+ "testVibrate",
new Binder());
}
@@ -124,7 +127,8 @@
expectSecurityException("UPDATE_APP_OPS_STATS");
getInstrumentation().getUiAutomation().adoptShellPermissionIdentity(
Manifest.permission.VIBRATE);
- mVibratorService.vibrate(Process.SYSTEM_UID, "android", EFFECT, ATTRS, "testVibrate",
+ mVibratorService.vibrate(Process.SYSTEM_UID, DISPLAY_ID, "android", EFFECT, ATTRS,
+ "testVibrate",
new Binder());
}
@@ -133,7 +137,8 @@
getInstrumentation().getUiAutomation().adoptShellPermissionIdentity(
Manifest.permission.VIBRATE,
Manifest.permission.UPDATE_APP_OPS_STATS);
- mVibratorService.vibrate(Process.SYSTEM_UID, "android", EFFECT, ATTRS, "testVibrate",
+ mVibratorService.vibrate(Process.SYSTEM_UID, DISPLAY_ID, "android", EFFECT, ATTRS,
+ "testVibrate",
new Binder());
}