Merge "Add secondaryId comparison for ProgramInfo"
diff --git a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShimPriv_apk.asciipb b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShimPriv_apk.asciipb
index 0ccd951..6b3278f 100644
--- a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShimPriv_apk.asciipb
+++ b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShimPriv_apk.asciipb
@@ -1,6 +1,6 @@
drops {
android_build_drop {
- build_id: "7552332"
+ build_id: "8572644"
target: "CtsShim"
source_file: "aosp_arm64/CtsShimPriv.apk"
}
@@ -8,7 +8,7 @@
version: ""
version_group: ""
git_project: "platform/frameworks/base"
- git_branch: "sc-dev"
+ git_branch: "tm-dev"
transform: TRANSFORM_NONE
transform_options {
}
diff --git a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShim_apk.asciipb b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShim_apk.asciipb
index 7e85c8f..34c9c4d 100644
--- a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShim_apk.asciipb
+++ b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShim_apk.asciipb
@@ -1,6 +1,6 @@
drops {
android_build_drop {
- build_id: "7552332"
+ build_id: "8572644"
target: "CtsShim"
source_file: "aosp_arm64/CtsShim.apk"
}
@@ -8,7 +8,7 @@
version: ""
version_group: ""
git_project: "platform/frameworks/base"
- git_branch: "sc-dev"
+ git_branch: "tm-dev"
transform: TRANSFORM_NONE
transform_options {
}
diff --git a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShimPriv_apk.asciipb b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShimPriv_apk.asciipb
index 20c2785..6897a02 100644
--- a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShimPriv_apk.asciipb
+++ b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShimPriv_apk.asciipb
@@ -1,6 +1,6 @@
drops {
android_build_drop {
- build_id: "7552332"
+ build_id: "8572644"
target: "CtsShim"
source_file: "aosp_x86_64/CtsShimPriv.apk"
}
@@ -8,7 +8,7 @@
version: ""
version_group: ""
git_project: "platform/frameworks/base"
- git_branch: "sc-dev"
+ git_branch: "tm-dev"
transform: TRANSFORM_NONE
transform_options {
}
diff --git a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShim_apk.asciipb b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShim_apk.asciipb
index 13e3ae5..6dfa7810 100644
--- a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShim_apk.asciipb
+++ b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShim_apk.asciipb
@@ -1,6 +1,6 @@
drops {
android_build_drop {
- build_id: "7552332"
+ build_id: "8572644"
target: "CtsShim"
source_file: "aosp_x86_64/CtsShim.apk"
}
@@ -8,7 +8,7 @@
version: ""
version_group: ""
git_project: "platform/frameworks/base"
- git_branch: "sc-dev"
+ git_branch: "tm-dev"
transform: TRANSFORM_NONE
transform_options {
}
diff --git a/ApiDocs.bp b/ApiDocs.bp
index 5ec107da..e6525c9 100644
--- a/ApiDocs.bp
+++ b/ApiDocs.bp
@@ -139,11 +139,7 @@
defaults: ["android-non-updatable-doc-stubs-defaults"],
srcs: [":all-modules-public-stubs-source"],
args: metalava_framework_docs_args,
- api_levels_annotations_enabled: true,
- api_levels_annotations_dirs: [
- "sdk-dir",
- "api-versions-jars-dir",
- ],
+ api_levels_module: "api_versions_public",
aidl: {
include_dirs: [
"packages/modules/Connectivity/framework/aidl-export",
diff --git a/apct-tests/perftests/core/src/android/libcore/ZipFilePerfTest.java b/apct-tests/perftests/core/src/android/libcore/ZipFilePerfTest.java
index 517e3ce..31c92ba 100644
--- a/apct-tests/perftests/core/src/android/libcore/ZipFilePerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/ZipFilePerfTest.java
@@ -70,6 +70,9 @@
BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
ZipFile zf = new ZipFile(mFile);
+ state.pauseTiming();
+ zf.close();
+ state.resumeTiming();
}
}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/ExpensiveObjectsPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/ExpensiveObjectsPerfTest.java
index 32117dc..03c9d43 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/ExpensiveObjectsPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/ExpensiveObjectsPerfTest.java
@@ -141,15 +141,6 @@
}
@Test
- public void timeNumberFormatTrivialFormatLong() {
- NumberFormat nf = NumberFormat.getInstance(Locale.US);
- BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
- while (state.keepRunning()) {
- nf.format(1024L);
- }
- }
-
- @Test
public void timeLongToString() {
BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/HostnameVerifierPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/HostnameVerifierPerfTest.java
deleted file mode 100644
index f2b7fdf..0000000
--- a/apct-tests/perftests/core/src/android/libcore/regression/HostnameVerifierPerfTest.java
+++ /dev/null
@@ -1,192 +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 android.libcore.regression;
-
-import android.perftests.utils.BenchmarkState;
-import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameters;
-
-import java.io.ByteArrayInputStream;
-import java.net.URL;
-import java.security.Principal;
-import java.security.cert.Certificate;
-import java.security.cert.CertificateFactory;
-import java.util.Arrays;
-import java.util.Collection;
-
-import javax.net.ssl.HostnameVerifier;
-import javax.net.ssl.HttpsURLConnection;
-import javax.net.ssl.SSLSession;
-import javax.net.ssl.SSLSessionContext;
-
-/**
- * This benchmark makes a real HTTP connection to a handful of hosts and
- * captures the served certificates as a byte array. It then verifies each
- * certificate in the benchmark loop, being careful to convert from the
- * byte[] to the certificate each time. Otherwise the certificate class
- * caches previous results which skews the results of the benchmark: In practice
- * each certificate instance is verified once and then released.
- */
-@RunWith(Parameterized.class)
-@LargeTest
-public final class HostnameVerifierPerfTest {
- @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
-
- @Parameters(name = "mHost({0})")
- public static Collection<Object[]> data() {
- return Arrays.asList(
- new Object[][] {
- {"m.google.com"},
- {"www.google.com"},
- {"www.amazon.com"},
- {"www.ubs.com"}
- });
- }
-
- @Parameterized.Parameter(0)
- public String mHost;
-
-
- private String mHostname;
- private HostnameVerifier mHostnameVerifier;
- private byte[][] mEncodedCertificates;
-
- @Before
- public void setUp() throws Exception {
- URL url = new URL("https", mHost, "/");
- mHostnameVerifier = HttpsURLConnection.getDefaultHostnameVerifier();
- HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
- connection.setHostnameVerifier(new HostnameVerifier() {
- public boolean verify(String mHostname, SSLSession sslSession) {
- try {
- mEncodedCertificates = certificatesToBytes(sslSession.getPeerCertificates());
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- HostnameVerifierPerfTest.this.mHostname = mHostname;
- return true;
- }
- });
- connection.getInputStream();
- connection.disconnect();
- }
-
- @Test
- public void timeVerify() throws Exception {
- BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
- while (state.keepRunning()) {
- final Certificate[] certificates = bytesToCertificates(mEncodedCertificates);
- FakeSSLSession sslSession = new FakeSSLSession() {
- @Override public Certificate[] getPeerCertificates() {
- return certificates;
- }
- };
- mHostnameVerifier.verify(mHostname, sslSession);
- }
- }
-
- private byte[][] certificatesToBytes(Certificate[] certificates) throws Exception {
- byte[][] result = new byte[certificates.length][];
- for (int i = 0, certificatesLength = certificates.length; i < certificatesLength; i++) {
- result[i] = certificates[i].getEncoded();
- }
- return result;
- }
-
- private Certificate[] bytesToCertificates(byte[][] encodedCertificates) throws Exception {
- CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
- Certificate[] result = new Certificate[encodedCertificates.length];
- for (int i = 0; i < encodedCertificates.length; i++) {
- result[i] = certificateFactory.generateCertificate(
- new ByteArrayInputStream(encodedCertificates[i]));
- }
- return result;
- }
-
- private static class FakeSSLSession implements SSLSession {
- public int getApplicationBufferSize() {
- throw new UnsupportedOperationException();
- }
- public String getCipherSuite() {
- throw new UnsupportedOperationException();
- }
- public long getCreationTime() {
- throw new UnsupportedOperationException();
- }
- public byte[] getId() {
- throw new UnsupportedOperationException();
- }
- public long getLastAccessedTime() {
- throw new UnsupportedOperationException();
- }
- public Certificate[] getLocalCertificates() {
- throw new UnsupportedOperationException();
- }
- public Principal getLocalPrincipal() {
- throw new UnsupportedOperationException();
- }
- public int getPacketBufferSize() {
- throw new UnsupportedOperationException();
- }
- public javax.security.cert.X509Certificate[] getPeerCertificateChain() {
- throw new UnsupportedOperationException();
- }
- public Certificate[] getPeerCertificates() {
- throw new UnsupportedOperationException();
- }
- public String getPeerHost() {
- throw new UnsupportedOperationException();
- }
- public int getPeerPort() {
- throw new UnsupportedOperationException();
- }
- public Principal getPeerPrincipal() {
- throw new UnsupportedOperationException();
- }
- public String getProtocol() {
- throw new UnsupportedOperationException();
- }
- public SSLSessionContext getSessionContext() {
- throw new UnsupportedOperationException();
- }
- public Object getValue(String name) {
- throw new UnsupportedOperationException();
- }
- public String[] getValueNames() {
- throw new UnsupportedOperationException();
- }
- public void invalidate() {
- throw new UnsupportedOperationException();
- }
- public boolean isValid() {
- throw new UnsupportedOperationException();
- }
- public void putValue(String name, Object value) {
- throw new UnsupportedOperationException();
- }
- public void removeValue(String name) {
- throw new UnsupportedOperationException();
- }
- }
-}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/NumberFormatTrivialFormatLongPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/NumberFormatTrivialFormatLongPerfTest.java
new file mode 100644
index 0000000..5ff2b22
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/NumberFormatTrivialFormatLongPerfTest.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 android.libcore.regression;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.text.NumberFormat;
+import java.util.Locale;
+
+/**
+ * Benchmarks creation and cloning various expensive objects.
+ */
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class NumberFormatTrivialFormatLongPerfTest {
+ @Rule
+ public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ @Test
+ public void timeNumberFormatTrivialFormatLong() {
+ NumberFormat nf = NumberFormat.getInstance(Locale.US);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ nf.format(1024L);
+ }
+ }
+}
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobAccessMode.java b/apex/blobstore/service/java/com/android/server/blob/BlobAccessMode.java
index 83ef21e..b0c295c 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobAccessMode.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobAccessMode.java
@@ -24,6 +24,7 @@
import android.annotation.NonNull;
import android.content.Context;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
import android.os.Binder;
import android.os.UserHandle;
import android.util.ArraySet;
@@ -32,6 +33,7 @@
import android.util.IndentingPrintWriter;
import com.android.internal.util.XmlUtils;
+import com.android.server.LocalServices;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -108,7 +110,7 @@
}
if ((mAccessType & ACCESS_TYPE_SAME_SIGNATURE) != 0) {
- if (checkSignatures(context, callingUid, committerUid)) {
+ if (checkSignatures(callingUid, committerUid)) {
return true;
}
}
@@ -133,11 +135,11 @@
/**
* Compare signatures for two packages of different users.
*/
- private boolean checkSignatures(Context context, int uid1, int uid2) {
+ private boolean checkSignatures(int uid1, int uid2) {
final long token = Binder.clearCallingIdentity();
try {
- return context.getPackageManager().checkSignatures(uid1, uid2)
- == PackageManager.SIGNATURE_MATCH;
+ return LocalServices.getService(PackageManagerInternal.class)
+ .checkUidSignaturesForAllUsers(uid1, uid2) == PackageManager.SIGNATURE_MATCH;
} finally {
Binder.restoreCallingIdentity(token);
}
diff --git a/apex/jobscheduler/framework/java/android/app/AlarmManager.java b/apex/jobscheduler/framework/java/android/app/AlarmManager.java
index 1b9cf26..7393bcd 100644
--- a/apex/jobscheduler/framework/java/android/app/AlarmManager.java
+++ b/apex/jobscheduler/framework/java/android/app/AlarmManager.java
@@ -27,7 +27,7 @@
import android.annotation.SystemService;
import android.annotation.TestApi;
import android.compat.annotation.ChangeId;
-import android.compat.annotation.EnabledAfter;
+import android.compat.annotation.Disabled;
import android.compat.annotation.EnabledSince;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
@@ -282,15 +282,14 @@
public static final long ENABLE_USE_EXACT_ALARM = 218533173L;
/**
- * For apps targeting {@link Build.VERSION_CODES#TIRAMISU} or above, the permission
- * {@link Manifest.permission#SCHEDULE_EXACT_ALARM} will be denied, unless the user explicitly
- * allows it from Settings.
+ * The permission {@link Manifest.permission#SCHEDULE_EXACT_ALARM} will be denied, unless the
+ * user explicitly allows it from Settings.
*
- * TODO (b/226439802): change to EnabledSince(T) after SDK finalization.
+ * TODO (b/226439802): Either enable it in the next SDK or replace it with a better alternative.
* @hide
*/
@ChangeId
- @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.S_V2)
+ @Disabled
public static final long SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT = 226439802L;
@UnsupportedAppUsage
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
index 2ea8592..4aa9e84 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
@@ -30,6 +30,8 @@
import static android.app.AlarmManager.RTC;
import static android.app.AlarmManager.RTC_WAKEUP;
import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
+import static android.os.PowerExemptionManager.REASON_ALARM_MANAGER_ALARM_CLOCK;
+import static android.os.PowerExemptionManager.REASON_DENIED;
import static android.os.PowerExemptionManager.REASON_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED;
import static android.os.PowerExemptionManager.TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
import static android.os.PowerWhitelistManager.REASON_ALARM_MANAGER_WHILE_IDLE;
@@ -329,6 +331,7 @@
});
BroadcastOptions mOptsWithFgs = BroadcastOptions.makeBasic();
+ BroadcastOptions mOptsWithFgsForAlarmClock = BroadcastOptions.makeBasic();
BroadcastOptions mOptsWithoutFgs = BroadcastOptions.makeBasic();
BroadcastOptions mOptsTimeBroadcast = BroadcastOptions.makeBasic();
ActivityOptions mActivityOptsRestrictBal = ActivityOptions.makeBasic();
@@ -565,9 +568,6 @@
@VisibleForTesting
static final String KEY_KILL_ON_SCHEDULE_EXACT_ALARM_REVOKED =
"kill_on_schedule_exact_alarm_revoked";
- @VisibleForTesting
- static final String KEY_SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT =
- "schedule_exact_alarm_denied_by_default";
private static final long DEFAULT_MIN_FUTURITY = 5 * 1000;
private static final long DEFAULT_MIN_INTERVAL = 60 * 1000;
@@ -612,8 +612,6 @@
private static final boolean DEFAULT_KILL_ON_SCHEDULE_EXACT_ALARM_REVOKED = true;
- private static final boolean DEFAULT_SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT = true;
-
// Minimum futurity of a new alarm
public long MIN_FUTURITY = DEFAULT_MIN_FUTURITY;
@@ -701,14 +699,6 @@
public boolean KILL_ON_SCHEDULE_EXACT_ALARM_REVOKED =
DEFAULT_KILL_ON_SCHEDULE_EXACT_ALARM_REVOKED;
- /**
- * When this is {@code true}, apps with the change
- * {@link AlarmManager#SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT} enabled will not get
- * {@link Manifest.permission#SCHEDULE_EXACT_ALARM} unless the user grants it to them.
- */
- public volatile boolean SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT =
- DEFAULT_SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT;
-
public boolean USE_TARE_POLICY = Settings.Global.DEFAULT_ENABLE_TARE == 1;
private long mLastAllowWhileIdleWhitelistDuration = -1;
@@ -743,9 +733,12 @@
mOptsWithFgs.setTemporaryAppAllowlist(ALLOW_WHILE_IDLE_WHITELIST_DURATION,
TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
REASON_ALARM_MANAGER_WHILE_IDLE, "");
+ mOptsWithFgsForAlarmClock.setTemporaryAppAllowlist(
+ ALLOW_WHILE_IDLE_WHITELIST_DURATION,
+ TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
+ REASON_ALARM_MANAGER_ALARM_CLOCK, "");
mOptsWithoutFgs.setTemporaryAppAllowlist(ALLOW_WHILE_IDLE_WHITELIST_DURATION,
- TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED,
- REASON_ALARM_MANAGER_WHILE_IDLE, "");
+ TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED, REASON_DENIED, "");
}
}
@@ -892,15 +885,6 @@
KEY_KILL_ON_SCHEDULE_EXACT_ALARM_REVOKED,
DEFAULT_KILL_ON_SCHEDULE_EXACT_ALARM_REVOKED);
break;
- case KEY_SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT:
- final boolean oldValue = SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT;
-
- SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT = properties.getBoolean(
- KEY_SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT,
- DEFAULT_SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT);
- handleScheduleExactAlarmDeniedByDefaultChange(oldValue,
- SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT);
- break;
default:
if (name.startsWith(KEY_PREFIX_STANDBY_QUOTA) && !standbyQuotaUpdated) {
// The quotas need to be updated in order, so we can't just rely
@@ -971,15 +955,6 @@
}
}
- private void handleScheduleExactAlarmDeniedByDefaultChange(boolean oldValue,
- boolean newValue) {
- if (oldValue == newValue) {
- return;
- }
- mHandler.obtainMessage(AlarmHandler.CHECK_EXACT_ALARM_PERMISSION_ON_FEATURE_TOGGLE,
- newValue).sendToTarget();
- }
-
private void migrateAlarmsToNewStoreLocked() {
final AlarmStore newStore = LAZY_BATCHING ? new LazyAlarmStore()
: new BatchingAlarmStore();
@@ -1156,9 +1131,6 @@
pw.print(KEY_KILL_ON_SCHEDULE_EXACT_ALARM_REVOKED,
KILL_ON_SCHEDULE_EXACT_ALARM_REVOKED);
pw.println();
- pw.print(KEY_SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT,
- SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT);
- pw.println();
pw.print(Settings.Global.ENABLE_TARE, USE_TARE_POLICY);
pw.println();
@@ -1744,6 +1716,7 @@
public void onStart() {
mInjector.init();
mOptsWithFgs.setPendingIntentBackgroundActivityLaunchAllowed(false);
+ mOptsWithFgsForAlarmClock.setPendingIntentBackgroundActivityLaunchAllowed(false);
mOptsWithoutFgs.setPendingIntentBackgroundActivityLaunchAllowed(false);
mOptsTimeBroadcast.setPendingIntentBackgroundActivityLaunchAllowed(false);
mActivityOptsRestrictBal.setPendingIntentBackgroundActivityLaunchAllowed(false);
@@ -2741,7 +2714,12 @@
if (isExactAlarmChangeEnabled(callingPackage, callingUserId)) {
needsPermission = exact;
lowerQuota = !exact;
- idleOptions = exact ? mOptsWithFgs.toBundle() : mOptsWithoutFgs.toBundle();
+ if (exact) {
+ idleOptions = (alarmClock != null) ? mOptsWithFgsForAlarmClock.toBundle()
+ : mOptsWithFgs.toBundle();
+ } else {
+ idleOptions = mOptsWithoutFgs.toBundle();
+ }
} else {
changeDisabled = true;
needsPermission = false;
@@ -2928,10 +2906,8 @@
}
private boolean isScheduleExactAlarmDeniedByDefault(String packageName, int userId) {
- return mConstants.SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT
- && CompatChanges.isChangeEnabled(
- AlarmManager.SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT, packageName,
- UserHandle.of(userId));
+ return CompatChanges.isChangeEnabled(AlarmManager.SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT,
+ packageName, UserHandle.of(userId));
}
@NeverCompile // Avoid size overhead of debugging code.
@@ -4707,7 +4683,6 @@
public static final int REFRESH_EXACT_ALARM_CANDIDATES = 11;
public static final int TARE_AFFORDABILITY_CHANGED = 12;
public static final int CHECK_EXACT_ALARM_PERMISSION_ON_UPDATE = 13;
- public static final int CHECK_EXACT_ALARM_PERMISSION_ON_FEATURE_TOGGLE = 14;
AlarmHandler() {
super(Looper.myLooper());
@@ -4827,32 +4802,6 @@
removeExactAlarmsOnPermissionRevoked(uid, packageName, /*killUid = */false);
}
break;
- case CHECK_EXACT_ALARM_PERMISSION_ON_FEATURE_TOGGLE:
- final boolean defaultDenied = (Boolean) msg.obj;
-
- final int[] startedUserIds = mActivityManagerInternal.getStartedUserIds();
- for (int appId : mExactAlarmCandidates) {
- for (int userId : startedUserIds) {
- uid = UserHandle.getUid(userId, appId);
-
- final AndroidPackage packageForUid =
- mPackageManagerInternal.getPackage(uid);
- if (packageForUid == null) {
- continue;
- }
- final String pkg = packageForUid.getPackageName();
- if (defaultDenied) {
- if (!hasScheduleExactAlarmInternal(pkg, uid)
- && !hasUseExactAlarmInternal(pkg, uid)) {
- removeExactAlarmsOnPermissionRevoked(uid, pkg, true);
- }
- } else if (hasScheduleExactAlarmInternal(pkg, uid)) {
- sendScheduleExactAlarmPermissionStateChangedBroadcast(pkg,
- UserHandle.getUserId(uid));
- }
- }
- }
- break;
default:
// nope, just ignore it
break;
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
index afe36b5..d5a7f28 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
@@ -959,7 +959,7 @@
for (int i = 0; i < mActiveServices.size(); i++) {
JobServiceContext jsc = mActiveServices.get(i);
final JobStatus executing = jsc.getRunningJobLocked();
- if (executing != null && executing.matches(job.getUid(), job.getJobId())) {
+ if (executing == job) {
jsc.cancelExecutingJobLocked(reason, internalReasonCode, debugReason);
return true;
}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/PrefetchController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/PrefetchController.java
index 428f2cb..0f385ef 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/PrefetchController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/PrefetchController.java
@@ -17,6 +17,7 @@
package com.android.server.job.controllers;
import static android.text.format.DateUtils.HOUR_IN_MILLIS;
+import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
import static com.android.server.job.JobSchedulerService.sSystemClock;
@@ -90,6 +91,14 @@
@CurrentTimeMillisLong
private long mLaunchTimeThresholdMs = PcConstants.DEFAULT_LAUNCH_TIME_THRESHOLD_MS;
+ /**
+ * The additional time we'll add to a launch time estimate before considering it obsolete and
+ * try to get a new estimate. This will help make prefetch jobs more viable in case an estimate
+ * is a few minutes early.
+ */
+ @GuardedBy("mLock")
+ private long mLaunchTimeAllowanceMs = PcConstants.DEFAULT_LAUNCH_TIME_ALLOWANCE_MS;
+
@SuppressWarnings("FieldCanBeLocal")
private final EstimatedLaunchTimeChangedListener mEstimatedLaunchTimeChangedListener =
new EstimatedLaunchTimeChangedListener() {
@@ -204,7 +213,8 @@
private long getNextEstimatedLaunchTimeLocked(int userId, @NonNull String pkgName,
@CurrentTimeMillisLong long now) {
final Long nextEstimatedLaunchTime = mEstimatedLaunchTimes.get(userId, pkgName);
- if (nextEstimatedLaunchTime == null || nextEstimatedLaunchTime < now) {
+ if (nextEstimatedLaunchTime == null
+ || nextEstimatedLaunchTime < now - mLaunchTimeAllowanceMs) {
// Don't query usage stats here because it may have to read from disk.
mHandler.obtainMessage(MSG_RETRIEVE_ESTIMATED_LAUNCH_TIME, userId, 0, pkgName)
.sendToTarget();
@@ -335,7 +345,9 @@
}
final long nextEstimatedLaunchTime = getNextEstimatedLaunchTimeLocked(userId, pkgName, now);
- if (nextEstimatedLaunchTime - now > mLaunchTimeThresholdMs) {
+ // Avoid setting an alarm for the end of time.
+ if (nextEstimatedLaunchTime != Long.MAX_VALUE
+ && nextEstimatedLaunchTime - now > mLaunchTimeThresholdMs) {
// Set alarm to be notified when this crosses the threshold.
final long timeToCrossThresholdMs =
nextEstimatedLaunchTime - (now + mLaunchTimeThresholdMs);
@@ -354,7 +366,7 @@
private boolean willBeLaunchedSoonLocked(int userId, @NonNull String pkgName,
@CurrentTimeMillisLong long now) {
return getNextEstimatedLaunchTimeLocked(userId, pkgName, now)
- <= now + mLaunchTimeThresholdMs;
+ <= now + mLaunchTimeThresholdMs - mLaunchTimeAllowanceMs;
}
@Override
@@ -494,16 +506,37 @@
@VisibleForTesting
static final String KEY_LAUNCH_TIME_THRESHOLD_MS =
PC_CONSTANT_PREFIX + "launch_time_threshold_ms";
+ @VisibleForTesting
+ static final String KEY_LAUNCH_TIME_ALLOWANCE_MS =
+ PC_CONSTANT_PREFIX + "launch_time_allowance_ms";
private static final long DEFAULT_LAUNCH_TIME_THRESHOLD_MS = 7 * HOUR_IN_MILLIS;
+ private static final long DEFAULT_LAUNCH_TIME_ALLOWANCE_MS = 20 * MINUTE_IN_MILLIS;
/** How much time each app will have to run jobs within their standby bucket window. */
public long LAUNCH_TIME_THRESHOLD_MS = DEFAULT_LAUNCH_TIME_THRESHOLD_MS;
+ /**
+ * How much additional time to add to an estimated launch time before considering it
+ * unusable.
+ */
+ public long LAUNCH_TIME_ALLOWANCE_MS = DEFAULT_LAUNCH_TIME_ALLOWANCE_MS;
+
@GuardedBy("mLock")
public void processConstantLocked(@NonNull DeviceConfig.Properties properties,
@NonNull String key) {
switch (key) {
+ case KEY_LAUNCH_TIME_ALLOWANCE_MS:
+ LAUNCH_TIME_ALLOWANCE_MS =
+ properties.getLong(key, DEFAULT_LAUNCH_TIME_ALLOWANCE_MS);
+ // Limit the allowance to the range [0 minutes, 2 hours].
+ long newLaunchTimeAllowanceMs = Math.min(2 * HOUR_IN_MILLIS,
+ Math.max(0, LAUNCH_TIME_ALLOWANCE_MS));
+ if (mLaunchTimeAllowanceMs != newLaunchTimeAllowanceMs) {
+ mLaunchTimeAllowanceMs = newLaunchTimeAllowanceMs;
+ mShouldReevaluateConstraints = true;
+ }
+ break;
case KEY_LAUNCH_TIME_THRESHOLD_MS:
LAUNCH_TIME_THRESHOLD_MS =
properties.getLong(key, DEFAULT_LAUNCH_TIME_THRESHOLD_MS);
@@ -528,6 +561,7 @@
pw.increaseIndent();
pw.print(KEY_LAUNCH_TIME_THRESHOLD_MS, LAUNCH_TIME_THRESHOLD_MS).println();
+ pw.print(KEY_LAUNCH_TIME_ALLOWANCE_MS, LAUNCH_TIME_ALLOWANCE_MS).println();
pw.decreaseIndent();
}
@@ -536,6 +570,11 @@
//////////////////////// TESTING HELPERS /////////////////////////////
@VisibleForTesting
+ long getLaunchTimeAllowanceMs() {
+ return mLaunchTimeAllowanceMs;
+ }
+
+ @VisibleForTesting
long getLaunchTimeThresholdMs() {
return mLaunchTimeThresholdMs;
}
diff --git a/api/api.go b/api/api.go
index ce8cd14..ca0fc28 100644
--- a/api/api.go
+++ b/api/api.go
@@ -179,7 +179,7 @@
// Note: order matters: first parameter is the full api-versions.xml
// after that the stubs files in any order
// stubs files are all modules that export API surfaces EXCEPT ART
- props.Srcs = append([]string{":framework-doc-stubs{.api_versions.xml}"}, createSrcs(modules, ".stubs{.jar}")...)
+ props.Srcs = append([]string{":api_versions_public{.api_versions.xml}"}, createSrcs(modules, ".stubs{.jar}")...)
props.Dists = []android.Dist{{Targets: []string{"sdk"}}}
ctx.CreateModule(genrule.GenRuleFactory, &props)
}
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index 3f6adef..dae4570 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -508,7 +508,8 @@
resolution = limitSurfaceSize(resolution.width, resolution.height);
// create the native surface
sp<SurfaceControl> control = session()->createSurface(String8("BootAnimation"),
- resolution.getWidth(), resolution.getHeight(), PIXEL_FORMAT_RGB_565);
+ resolution.getWidth(), resolution.getHeight(), PIXEL_FORMAT_RGB_565,
+ ISurfaceComposerClient::eOpaque);
SurfaceComposerClient::Transaction t;
diff --git a/core/api/current.txt b/core/api/current.txt
index 30dbbdb..6433776 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -19533,6 +19533,8 @@
method @Nullable public android.os.Bundle getExtras();
method @FloatRange(from=-90.0, to=90.0) public double getLatitude();
method @FloatRange(from=-180.0, to=180.0) public double getLongitude();
+ method @FloatRange(from=0.0) public float getMslAltitudeAccuracyMeters();
+ method @FloatRange public double getMslAltitudeMeters();
method @Nullable public String getProvider();
method @FloatRange(from=0.0) public float getSpeed();
method @FloatRange(from=0.0) public float getSpeedAccuracyMetersPerSecond();
@@ -19543,6 +19545,8 @@
method public boolean hasBearing();
method public boolean hasBearingAccuracy();
method public boolean hasElapsedRealtimeUncertaintyNanos();
+ method public boolean hasMslAltitude();
+ method public boolean hasMslAltitudeAccuracy();
method public boolean hasSpeed();
method public boolean hasSpeedAccuracy();
method public boolean hasVerticalAccuracy();
@@ -19554,6 +19558,8 @@
method public void removeBearing();
method public void removeBearingAccuracy();
method public void removeElapsedRealtimeUncertaintyNanos();
+ method public void removeMslAltitude();
+ method public void removeMslAltitudeAccuracy();
method public void removeSpeed();
method public void removeSpeedAccuracy();
method public void removeVerticalAccuracy();
@@ -19569,6 +19575,8 @@
method public void setLatitude(@FloatRange(from=-90.0, to=90.0) double);
method public void setLongitude(@FloatRange(from=-180.0, to=180.0) double);
method public void setMock(boolean);
+ method public void setMslAltitudeAccuracyMeters(@FloatRange(from=0.0) float);
+ method public void setMslAltitudeMeters(@FloatRange double);
method public void setProvider(@Nullable String);
method public void setSpeed(@FloatRange(from=0.0) float);
method public void setSpeedAccuracyMetersPerSecond(@FloatRange(from=0.0) float);
@@ -22305,6 +22313,7 @@
field public static final String KEY_VIDEO_QP_P_MAX = "video-qp-p-max";
field public static final String KEY_VIDEO_QP_P_MIN = "video-qp-p-min";
field public static final String KEY_WIDTH = "width";
+ field public static final String LOG_SESSION_ID = "log-session-id";
field public static final String MIMETYPE_AUDIO_AAC = "audio/mp4a-latm";
field public static final String MIMETYPE_AUDIO_AAC_ELD = "audio/mp4a.40.39";
field public static final String MIMETYPE_AUDIO_AAC_HE_V1 = "audio/mp4a.40.05";
@@ -31441,6 +31450,7 @@
public static interface IBinder.DeathRecipient {
method public void binderDied();
+ method public default void binderDied(@NonNull android.os.IBinder);
}
public interface IInterface {
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 4e81491..5c532a0 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -96,6 +96,11 @@
package android.animation {
+ public abstract class Animator implements java.lang.Cloneable {
+ method public static long getBackgroundPauseDelay();
+ method public static void setBackgroundPauseDelay(long);
+ }
+
public class ValueAnimator extends android.animation.Animator {
method @MainThread public static void setDurationScale(@FloatRange(from=0) float);
}
@@ -320,7 +325,6 @@
method public void setDemoted(boolean);
method public void setFgServiceShown(boolean);
method public void setImportanceLockedByCriticalDeviceFunction(boolean);
- method public void setImportanceLockedByOEM(boolean);
method public void setImportantConversation(boolean);
method public void setOriginalImportance(int);
}
@@ -483,8 +487,6 @@
field public static final int WINDOWING_MODE_FULLSCREEN = 1; // 0x1
field public static final int WINDOWING_MODE_MULTI_WINDOW = 6; // 0x6
field public static final int WINDOWING_MODE_PINNED = 2; // 0x2
- field public static final int WINDOWING_MODE_SPLIT_SCREEN_PRIMARY = 3; // 0x3
- field public static final int WINDOWING_MODE_SPLIT_SCREEN_SECONDARY = 4; // 0x4
field public static final int WINDOWING_MODE_UNDEFINED = 0; // 0x0
}
diff --git a/core/java/android/animation/AnimationHandler.java b/core/java/android/animation/AnimationHandler.java
index 260323f..b3be42a 100644
--- a/core/java/android/animation/AnimationHandler.java
+++ b/core/java/android/animation/AnimationHandler.java
@@ -18,6 +18,8 @@
import android.os.SystemClock;
import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Log;
import android.view.Choreographer;
import java.util.ArrayList;
@@ -35,10 +37,13 @@
* @hide
*/
public class AnimationHandler {
+
+ private static final String TAG = "AnimationHandler";
+ private static final boolean LOCAL_LOGV = false;
+
/**
* Internal per-thread collections used to avoid set collisions as animations start and end
* while being processed.
- * @hide
*/
private final ArrayMap<AnimationFrameCallback, Long> mDelayedCallbackStartTime =
new ArrayMap<>();
@@ -48,6 +53,26 @@
new ArrayList<>();
private AnimationFrameCallbackProvider mProvider;
+ /**
+ * This paused list is used to store animators forcibly paused when the activity
+ * went into the background (to avoid unnecessary background processing work).
+ * These animators should be resume()'d when the activity returns to the foreground.
+ */
+ private final ArrayList<Animator> mPausedAnimators = new ArrayList<>();
+
+ /**
+ * This structure is used to store the currently active objects (ViewRootImpls or
+ * WallpaperService.Engines) in the process. Each of these objects sends a request to
+ * AnimationHandler when it goes into the background (request to pause) or foreground
+ * (request to resume). Because all animators are managed by AnimationHandler on the same
+ * thread, it should only ever pause animators when *all* requestors are in the background.
+ * This list tracks the background/foreground state of all requestors and only ever
+ * pauses animators when all items are in the background (false). To simplify, we only ever
+ * store visible (foreground) requestors; if the set size reaches zero, there are no
+ * objects in the foreground and it is time to pause animators.
+ */
+ private final ArraySet<Object> mAnimatorRequestors = new ArraySet<>();
+
private final Choreographer.FrameCallback mFrameCallback = new Choreographer.FrameCallback() {
@Override
public void doFrame(long frameTimeNanos) {
@@ -68,6 +93,89 @@
return sAnimatorHandler.get();
}
+
+ /**
+ * This is called when a window goes away. We should remove
+ * it from the requestors list to ensure that we are counting requests correctly and not
+ * tracking obsolete+enabled requestors.
+ */
+ public static void removeRequestor(Object requestor) {
+ getInstance().removeRequestorImpl(requestor);
+ }
+
+ private void removeRequestorImpl(Object requestor) {
+ // Also request disablement, in case that requestor was the sole object keeping
+ // animators un-paused
+ requestAnimatorsEnabled(false, requestor);
+ mAnimatorRequestors.remove(requestor);
+ if (LOCAL_LOGV) {
+ Log.v(TAG, "removeRequestorImpl for " + requestor);
+ for (int i = 0; i < mAnimatorRequestors.size(); ++i) {
+ Log.v(TAG, "animatorRequesters " + i + " = " + mAnimatorRequestors.valueAt(i));
+ }
+ }
+ }
+
+ /**
+ * This method is called from ViewRootImpl or WallpaperService when either a window is no
+ * longer visible (enable == false) or when a window becomes visible (enable == true).
+ * If animators are not properly disabled when activities are backgrounded, it can lead to
+ * unnecessary processing, particularly for infinite animators, as the system will continue
+ * to pulse timing events even though the results are not visible. As a workaround, we
+ * pause all un-paused infinite animators, and resume them when any window in the process
+ * becomes visible.
+ */
+ public static void requestAnimatorsEnabled(boolean enable, Object requestor) {
+ getInstance().requestAnimatorsEnabledImpl(enable, requestor);
+ }
+
+ private void requestAnimatorsEnabledImpl(boolean enable, Object requestor) {
+ boolean wasEmpty = mAnimatorRequestors.isEmpty();
+ if (enable) {
+ mAnimatorRequestors.add(requestor);
+ } else {
+ mAnimatorRequestors.remove(requestor);
+ }
+ boolean isEmpty = mAnimatorRequestors.isEmpty();
+ if (wasEmpty != isEmpty) {
+ // only paused/resume animators if there was a visibility change
+ if (!isEmpty) {
+ // If any requestors are enabled, resume currently paused animators
+ Choreographer.getInstance().removeFrameCallback(mPauser);
+ for (int i = mPausedAnimators.size() - 1; i >= 0; --i) {
+ mPausedAnimators.get(i).resume();
+ }
+ mPausedAnimators.clear();
+ } else {
+ // Wait before pausing to avoid thrashing animator state for temporary backgrounding
+ Choreographer.getInstance().postFrameCallbackDelayed(mPauser,
+ Animator.getBackgroundPauseDelay());
+ }
+ }
+ if (LOCAL_LOGV) {
+ Log.v(TAG, enable ? "enable" : "disable" + " animators for " + requestor);
+ for (int i = 0; i < mAnimatorRequestors.size(); ++i) {
+ Log.v(TAG, "animatorRequesters " + i + " = " + mAnimatorRequestors.valueAt(i));
+ }
+ }
+ }
+
+ private Choreographer.FrameCallback mPauser = frameTimeNanos -> {
+ if (mAnimatorRequestors.size() > 0) {
+ // something enabled animators since this callback was scheduled - bail
+ return;
+ }
+ for (int i = 0; i < mAnimationCallbacks.size(); ++i) {
+ Animator animator = ((Animator) mAnimationCallbacks.get(i));
+ if (animator != null
+ && animator.getTotalDuration() == Animator.DURATION_INFINITE
+ && !animator.isPaused()) {
+ mPausedAnimators.add(animator);
+ animator.pause();
+ }
+ }
+ };
+
/**
* By default, the Choreographer is used to provide timing for frame callbacks. A custom
* provider can be used here to provide different timing pulse.
diff --git a/core/java/android/animation/Animator.java b/core/java/android/animation/Animator.java
index a8ff36a..9e55d35 100644
--- a/core/java/android/animation/Animator.java
+++ b/core/java/android/animation/Animator.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.pm.ActivityInfo.Config;
import android.content.res.ConstantState;
@@ -64,6 +65,34 @@
private AnimatorConstantState mConstantState;
/**
+ * backing field for backgroundPauseDelay property. This could be simply a hardcoded
+ * value in AnimationHandler, but it is useful to be able to change the value in tests.
+ */
+ private static long sBackgroundPauseDelay = 10000;
+
+ /**
+ * Sets the duration for delaying pausing animators when apps go into the background.
+ * Used by AnimationHandler when requested to pause animators.
+ *
+ * @hide
+ */
+ @TestApi
+ public static void setBackgroundPauseDelay(long value) {
+ sBackgroundPauseDelay = value;
+ }
+
+ /**
+ * Gets the duration for delaying pausing animators when apps go into the background.
+ * Used by AnimationHandler when requested to pause animators.
+ *
+ * @hide
+ */
+ @TestApi
+ public static long getBackgroundPauseDelay() {
+ return sBackgroundPauseDelay;
+ }
+
+ /**
* Starts this animation. If the animation has a nonzero startDelay, the animation will start
* running after that delay elapses. A non-delayed animation will have its initial
* value(s) set immediately, followed by calls to
diff --git a/core/java/android/app/ActivityClient.java b/core/java/android/app/ActivityClient.java
index 668dc6b..73678d9 100644
--- a/core/java/android/app/ActivityClient.java
+++ b/core/java/android/app/ActivityClient.java
@@ -98,6 +98,15 @@
}
}
+ /** Reports the activity starts local relaunch. */
+ public void activityLocalRelaunch(IBinder token) {
+ try {
+ getActivityClientController().activityLocalRelaunch(token);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
/** Reports the activity has completed relaunched. */
public void activityRelaunched(IBinder token) {
try {
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index abd6017..e25e374 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -2210,7 +2210,6 @@
pw.print(((baseIntent.getFlags() & FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) != 0));
pw.print(" activityType="); pw.print(activityTypeToString(getActivityType()));
pw.print(" windowingMode="); pw.print(windowingModeToString(getWindowingMode()));
- pw.print(" supportsSplitScreenMultiWindow="); pw.print(supportsSplitScreenMultiWindow);
pw.print(" supportsMultiWindow=");
pw.println(supportsMultiWindow);
if (taskDescription != null) {
@@ -4617,8 +4616,8 @@
try {
getService().broadcastIntentWithFeature(
null, null, intent, null, null, Activity.RESULT_OK, null, null,
- null /*requiredPermissions*/, null /*excludedPermissions*/, appOp, null, false,
- true, userId);
+ null /*requiredPermissions*/, null /*excludedPermissions*/,
+ null /*excludedPackages*/, appOp, null, false, true, userId);
} catch (RemoteException ex) {
}
}
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 2eebc01..d6441a2 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -16,6 +16,7 @@
package android.app;
+import static android.Manifest.permission.CONTROL_KEYGUARD;
import static android.Manifest.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS;
import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
@@ -362,9 +363,8 @@
private static final String KEY_LAUNCH_INTO_PIP_PARAMS =
"android.activity.launchIntoPipParams";
- /** See {@link #setDismissKeyguardIfInsecure()}. */
- private static final String KEY_DISMISS_KEYGUARD_IF_INSECURE =
- "android.activity.dismissKeyguardIfInsecure";
+ /** See {@link #setDismissKeyguard()}. */
+ private static final String KEY_DISMISS_KEYGUARD = "android.activity.dismissKeyguard";
private static final String KEY_IGNORE_PENDING_INTENT_CREATOR_FOREGROUND_STATE =
"android.activity.ignorePendingIntentCreatorForegroundState";
@@ -465,7 +465,7 @@
private boolean mLaunchedFromBubble;
private boolean mTransientLaunch;
private PictureInPictureParams mLaunchIntoPipParams;
- private boolean mDismissKeyguardIfInsecure;
+ private boolean mDismissKeyguard;
private boolean mIgnorePendingIntentCreatorForegroundState;
/**
@@ -1270,7 +1270,7 @@
mLaunchIntoPipParams = opts.getParcelable(KEY_LAUNCH_INTO_PIP_PARAMS);
mIsEligibleForLegacyPermissionPrompt =
opts.getBoolean(KEY_LEGACY_PERMISSION_PROMPT_ELIGIBLE);
- mDismissKeyguardIfInsecure = opts.getBoolean(KEY_DISMISS_KEYGUARD_IF_INSECURE);
+ mDismissKeyguard = opts.getBoolean(KEY_DISMISS_KEYGUARD);
mIgnorePendingIntentCreatorForegroundState = opts.getBoolean(
KEY_IGNORE_PENDING_INTENT_CREATOR_FOREGROUND_STATE);
}
@@ -1869,24 +1869,24 @@
}
/**
- * Sets whether the insecure keyguard should go away when this activity launches. In case the
- * keyguard is secure, this option will be ignored.
+ * Sets whether the keyguard should go away when this activity launches.
*
* @see Activity#setShowWhenLocked(boolean)
* @see android.R.attr#showWhenLocked
* @hide
*/
- public void setDismissKeyguardIfInsecure() {
- mDismissKeyguardIfInsecure = true;
+ @RequiresPermission(CONTROL_KEYGUARD)
+ public void setDismissKeyguard() {
+ mDismissKeyguard = true;
}
/**
- * @see #setDismissKeyguardIfInsecure()
+ * @see #setDismissKeyguard()
* @return whether the insecure keyguard should go away when the activity launches.
* @hide
*/
- public boolean getDismissKeyguardIfInsecure() {
- return mDismissKeyguardIfInsecure;
+ public boolean getDismissKeyguard() {
+ return mDismissKeyguard;
}
/**
@@ -2167,8 +2167,8 @@
b.putBoolean(KEY_LEGACY_PERMISSION_PROMPT_ELIGIBLE,
mIsEligibleForLegacyPermissionPrompt);
}
- if (mDismissKeyguardIfInsecure) {
- b.putBoolean(KEY_DISMISS_KEYGUARD_IF_INSECURE, mDismissKeyguardIfInsecure);
+ if (mDismissKeyguard) {
+ b.putBoolean(KEY_DISMISS_KEYGUARD, mDismissKeyguard);
}
if (mIgnorePendingIntentCreatorForegroundState) {
b.putBoolean(KEY_IGNORE_PENDING_INTENT_CREATOR_FOREGROUND_STATE,
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index b4cabad..69868ab 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -177,7 +177,6 @@
import android.view.SurfaceControl;
import android.view.ThreadedRenderer;
import android.view.View;
-import android.view.ViewDebug;
import android.view.ViewManager;
import android.view.ViewRootImpl;
import android.view.ViewTreeObserver;
@@ -873,6 +872,7 @@
String processName;
@UnsupportedAppUsage
ApplicationInfo appInfo;
+ String sdkSandboxClientAppVolumeUuid;
String sdkSandboxClientAppPackage;
@UnsupportedAppUsage
List<ProviderInfo> providers;
@@ -1119,9 +1119,10 @@
@Override
public final void bindApplication(String processName, ApplicationInfo appInfo,
- String sdkSandboxClientAppPackage, ProviderInfoList providerList,
- ComponentName instrumentationName, ProfilerInfo profilerInfo,
- Bundle instrumentationArgs, IInstrumentationWatcher instrumentationWatcher,
+ String sdkSandboxClientAppVolumeUuid, String sdkSandboxClientAppPackage,
+ ProviderInfoList providerList, ComponentName instrumentationName,
+ ProfilerInfo profilerInfo, Bundle instrumentationArgs,
+ IInstrumentationWatcher instrumentationWatcher,
IUiAutomationConnection instrumentationUiConnection, int debugMode,
boolean enableBinderTracking, boolean trackAllocation,
boolean isRestrictedBackupMode, boolean persistent, Configuration config,
@@ -1161,6 +1162,7 @@
AppBindData data = new AppBindData();
data.processName = processName;
data.appInfo = appInfo;
+ data.sdkSandboxClientAppVolumeUuid = sdkSandboxClientAppVolumeUuid;
data.sdkSandboxClientAppPackage = sdkSandboxClientAppPackage;
data.providers = providerList.getList();
data.instrumentationName = instrumentationName;
@@ -1402,16 +1404,18 @@
ContextImpl.class,
Activity.class,
WebView.class,
- OpenSSLSocketImpl.class
+ OpenSSLSocketImpl.class,
+ View.class,
+ ViewRootImpl.class
};
long[] instanceCounts = VMDebug.countInstancesOfClasses(classesToCount, true);
long appContextInstanceCount = instanceCounts[0];
long activityInstanceCount = instanceCounts[1];
long webviewInstanceCount = instanceCounts[2];
long openSslSocketCount = instanceCounts[3];
+ long viewInstanceCount = instanceCounts[4];
+ long viewRootInstanceCount = instanceCounts[5];
- long viewInstanceCount = ViewDebug.getViewInstanceCount();
- long viewRootInstanceCount = ViewDebug.getViewRootImplCount();
int globalAssetCount = AssetManager.getGlobalAssetCount();
int globalAssetManagerCount = AssetManager.getGlobalAssetManagerCount();
int binderLocalObjectCount = Debug.getBinderLocalObjectCount();
@@ -1554,16 +1558,18 @@
ContextImpl.class,
Activity.class,
WebView.class,
- OpenSSLSocketImpl.class
+ OpenSSLSocketImpl.class,
+ View.class,
+ ViewRootImpl.class
};
long[] instanceCounts = VMDebug.countInstancesOfClasses(classesToCount, true);
long appContextInstanceCount = instanceCounts[0];
long activityInstanceCount = instanceCounts[1];
long webviewInstanceCount = instanceCounts[2];
long openSslSocketCount = instanceCounts[3];
+ long viewInstanceCount = instanceCounts[4];
+ long viewRootInstanceCount = instanceCounts[5];
- long viewInstanceCount = ViewDebug.getViewInstanceCount();
- long viewRootInstanceCount = ViewDebug.getViewRootImplCount();
int globalAssetCount = AssetManager.getGlobalAssetCount();
int globalAssetManagerCount = AssetManager.getGlobalAssetManagerCount();
int binderLocalObjectCount = Debug.getBinderLocalObjectCount();
@@ -2561,6 +2567,11 @@
return getPackageInfo(ai, compatInfo, null, false, true, false);
}
+ private LoadedApk getPackageInfoNoCheck(ApplicationInfo ai, CompatibilityInfo compatInfo,
+ boolean isSdkSandbox) {
+ return getPackageInfo(ai, compatInfo, null, false, true, false, isSdkSandbox);
+ }
+
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public final LoadedApk peekPackageInfo(String packageName, boolean includeCode) {
synchronized (mResourcesManager) {
@@ -2577,11 +2588,18 @@
private LoadedApk getPackageInfo(ApplicationInfo aInfo, CompatibilityInfo compatInfo,
ClassLoader baseLoader, boolean securityViolation, boolean includeCode,
boolean registerPackage) {
+ return getPackageInfo(aInfo, compatInfo, baseLoader, securityViolation, includeCode,
+ registerPackage, /*isSdkSandbox=*/false);
+ }
+
+ private LoadedApk getPackageInfo(ApplicationInfo aInfo, CompatibilityInfo compatInfo,
+ ClassLoader baseLoader, boolean securityViolation, boolean includeCode,
+ boolean registerPackage, boolean isSdkSandbox) {
final boolean differentUser = (UserHandle.myUserId() != UserHandle.getUserId(aInfo.uid));
synchronized (mResourcesManager) {
WeakReference<LoadedApk> ref;
- if (differentUser) {
- // Caching not supported across users
+ if (differentUser || isSdkSandbox) {
+ // Caching not supported across users and for sdk sandboxes
ref = null;
} else if (includeCode) {
ref = mPackages.get(aInfo.packageName);
@@ -2628,8 +2646,8 @@
getSystemContext().mPackageInfo.getClassLoader());
}
- if (differentUser) {
- // Caching not supported across users
+ if (differentUser || isSdkSandbox) {
+ // Caching not supported across users and for sdk sandboxes
} else if (includeCode) {
mPackages.put(aInfo.packageName,
new WeakReference<LoadedApk>(packageInfo));
@@ -3410,26 +3428,12 @@
}
}
- /**
- * Returns {@code true} if the {@link android.app.ActivityManager.ProcessState} of the current
- * process is cached.
- */
- @Override
- @VisibleForTesting
- public boolean isCachedProcessState() {
- synchronized (mAppThread) {
- return mLastProcessState >= ActivityManager.PROCESS_STATE_CACHED_ACTIVITY;
- }
- }
-
@Override
public void updateProcessState(int processState, boolean fromIpc) {
- final boolean wasCached;
synchronized (mAppThread) {
if (mLastProcessState == processState) {
return;
}
- wasCached = isCachedProcessState();
mLastProcessState = processState;
// Defer the top state for VM to avoid aggressive JIT compilation affecting activity
// launch time.
@@ -3446,22 +3450,6 @@
+ (fromIpc ? " (from ipc" : ""));
}
}
-
- // Handle the pending configuration if the process state is changed from cached to
- // non-cached. Except the case where there is a launching activity because the
- // LaunchActivityItem will handle it.
- if (wasCached && !isCachedProcessState() && mNumLaunchingActivities.get() == 0) {
- final Configuration pendingConfig =
- mConfigurationController.getPendingConfiguration(false /* clearPending */);
- if (pendingConfig == null) {
- return;
- }
- if (Looper.myLooper() == mH.getLooper()) {
- handleConfigurationChanged(pendingConfig);
- } else {
- sendMessage(H.CONFIGURATION_CHANGED, pendingConfig);
- }
- }
}
/** Update VM state based on ActivityManager.PROCESS_STATE_* constants. */
@@ -5728,6 +5716,7 @@
return;
}
+ ActivityClient.getInstance().activityLocalRelaunch(r.token);
// Initialize a relaunch request.
final MergedConfiguration mergedConfiguration = new MergedConfiguration(
r.createdConfig != null
@@ -6574,9 +6563,11 @@
mConfigurationController.applyCompatConfiguration();
}
- data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo);
- if (data.sdkSandboxClientAppPackage != null) {
- data.info.setSdkSandboxStorage(data.sdkSandboxClientAppPackage);
+ final boolean isSdkSandbox = data.sdkSandboxClientAppPackage != null;
+ data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo, isSdkSandbox);
+ if (isSdkSandbox) {
+ data.info.setSdkSandboxStorage(data.sdkSandboxClientAppVolumeUuid,
+ data.sdkSandboxClientAppPackage);
}
if (agent != null) {
diff --git a/core/java/android/app/ActivityThreadInternal.java b/core/java/android/app/ActivityThreadInternal.java
index b9ad5c3..72506b9 100644
--- a/core/java/android/app/ActivityThreadInternal.java
+++ b/core/java/android/app/ActivityThreadInternal.java
@@ -32,8 +32,6 @@
boolean isInDensityCompatMode();
- boolean isCachedProcessState();
-
Application getApplication();
ArrayList<ComponentCallbacks2> collectComponentCallbacks(boolean includeUiContexts);
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 3b1943b..cb64173 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -1335,9 +1335,17 @@
public static final int OP_ACCESS_RESTRICTED_SETTINGS =
AppProtoEnums.APP_OP_ACCESS_RESTRICTED_SETTINGS;
+ /**
+ * Receive microphone audio from an ambient sound detection event
+ *
+ * @hide
+ */
+ public static final int OP_RECEIVE_AMBIENT_TRIGGER_AUDIO =
+ AppProtoEnums.APP_OP_RECEIVE_AMBIENT_TRIGGER_AUDIO;
+
/** @hide */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public static final int _NUM_OP = 120;
+ public static final int _NUM_OP = 121;
/** Access to coarse location information. */
public static final String OPSTR_COARSE_LOCATION = "android:coarse_location";
@@ -1800,6 +1808,14 @@
public static final String OPSTR_ACCESS_RESTRICTED_SETTINGS =
"android:access_restricted_settings";
+ /**
+ * Receive microphone audio from an ambient sound detection event
+ *
+ * @hide
+ */
+ public static final String OPSTR_RECEIVE_AMBIENT_TRIGGER_AUDIO =
+ "android:receive_ambient_trigger_audio";
+
/** {@link #sAppOpsToNote} not initialized yet for this op */
private static final byte SHOULD_COLLECT_NOTE_OP_NOT_INITIALIZED = 0;
/** Should not collect noting of this app-op in {@link #sAppOpsToNote} */
@@ -2021,6 +2037,7 @@
OP_ESTABLISH_VPN_SERVICE, // OP_ESTABLISH_VPN_SERVICE
OP_ESTABLISH_VPN_MANAGER, // OP_ESTABLISH_VPN_MANAGER
OP_ACCESS_RESTRICTED_SETTINGS, // OP_ACCESS_RESTRICTED_SETTINGS
+ OP_RECEIVE_AMBIENT_TRIGGER_AUDIO, // RECEIVE_SOUNDTRIGGER_AUDIO
};
/**
@@ -2147,6 +2164,7 @@
OPSTR_ESTABLISH_VPN_SERVICE,
OPSTR_ESTABLISH_VPN_MANAGER,
OPSTR_ACCESS_RESTRICTED_SETTINGS,
+ OPSTR_RECEIVE_AMBIENT_TRIGGER_AUDIO,
};
/**
@@ -2274,6 +2292,7 @@
"ESTABLISH_VPN_SERVICE",
"ESTABLISH_VPN_MANAGER",
"ACCESS_RESTRICTED_SETTINGS",
+ "RECEIVE_SOUNDTRIGGER_AUDIO",
};
/**
@@ -2402,6 +2421,7 @@
null, // no permission for OP_ESTABLISH_VPN_SERVICE
null, // no permission for OP_ESTABLISH_VPN_MANAGER
null, // no permission for OP_ACCESS_RESTRICTED_SETTINGS,
+ null, // no permission for OP_RECEIVE_SOUNDTRIGGER_AUDIO
};
/**
@@ -2529,7 +2549,8 @@
null, // NEARBY_WIFI_DEVICES
null, // ESTABLISH_VPN_SERVICE
null, // ESTABLISH_VPN_MANAGER
- null, // ACCESS_RESTRICTED_SETTINGS,
+ null, // ACCESS_RESTRICTED_SETTINGS
+ null, // RECEIVE_SOUNDTRIGGER_AUDIO
};
/**
@@ -2656,7 +2677,8 @@
null, // NEARBY_WIFI_DEVICES
null, // ESTABLISH_VPN_SERVICE
null, // ESTABLISH_VPN_MANAGER
- null, // ACCESS_RESTRICTED_SETTINGS,
+ null, // ACCESS_RESTRICTED_SETTINGS
+ null, // RECEIVE_SOUNDTRIGGER_AUDIO
};
/**
@@ -2687,7 +2709,7 @@
AppOpsManager.MODE_ALLOWED, // READ_ICC_SMS
AppOpsManager.MODE_ALLOWED, // WRITE_ICC_SMS
AppOpsManager.MODE_DEFAULT, // WRITE_SETTINGS
- AppOpsManager.MODE_DEFAULT, // SYSTEM_ALERT_WINDOW /*Overridden in opToDefaultMode()*/
+ getSystemAlertWindowDefault(), // SYSTEM_ALERT_WINDOW
AppOpsManager.MODE_ALLOWED, // ACCESS_NOTIFICATIONS
AppOpsManager.MODE_ALLOWED, // CAMERA
AppOpsManager.MODE_ALLOWED, // RECORD_AUDIO
@@ -2765,7 +2787,7 @@
AppOpsManager.MODE_ERRORED, // OP_NO_ISOLATED_STORAGE
AppOpsManager.MODE_ALLOWED, // PHONE_CALL_MICROPHONE
AppOpsManager.MODE_ALLOWED, // PHONE_CALL_CAMERA
- AppOpsManager.MODE_ALLOWED, // OP_RECORD_AUDIO_HOTWORD
+ AppOpsManager.MODE_ALLOWED, // RECORD_AUDIO_HOTWORD
AppOpsManager.MODE_DEFAULT, // MANAGE_ONGOING_CALLS
AppOpsManager.MODE_DEFAULT, // MANAGE_CREDENTIALS
AppOpsManager.MODE_DEFAULT, // USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER
@@ -2783,6 +2805,7 @@
AppOpsManager.MODE_ALLOWED, // ESTABLISH_VPN_SERVICE
AppOpsManager.MODE_ALLOWED, // ESTABLISH_VPN_MANAGER
AppOpsManager.MODE_ALLOWED, // ACCESS_RESTRICTED_SETTINGS,
+ AppOpsManager.MODE_ALLOWED, // RECEIVE_SOUNDTRIGGER_AUDIO
};
/**
@@ -2913,6 +2936,7 @@
false, // OP_ESTABLISH_VPN_SERVICE
false, // OP_ESTABLISH_VPN_MANAGER
true, // ACCESS_RESTRICTED_SETTINGS
+ false, // RECEIVE_SOUNDTRIGGER_AUDIO
};
/**
@@ -3040,6 +3064,7 @@
false, // OP_ESTABLISH_VPN_SERVICE
false, // OP_ESTABLISH_VPN_MANAGER
true, // ACCESS_RESTRICTED_SETTINGS
+ false, // RECEIVE_SOUNDTRIGGER_AUDIO
};
/**
@@ -3138,8 +3163,6 @@
private static final String DEBUG_LOGGING_OPS_PROP = "appops.logging_ops";
private static final String DEBUG_LOGGING_TAG = "AppOpsManager";
- private static volatile Integer sOpSystemAlertWindowDefaultMode;
-
/**
* Retrieve the op switch that controls the given operation.
* @hide
@@ -3238,9 +3261,6 @@
* @hide
*/
public static @Mode int opToDefaultMode(int op) {
- if (op == OP_SYSTEM_ALERT_WINDOW) {
- return getSystemAlertWindowDefault();
- }
return sOpDefaultMode[op];
}
@@ -10258,11 +10278,6 @@
}
private static int getSystemAlertWindowDefault() {
- // This is indeed racy but we aren't expecting the result to change so it's not worth
- // the synchronization.
- if (sOpSystemAlertWindowDefaultMode != null) {
- return sOpSystemAlertWindowDefaultMode;
- }
final Context context = ActivityThread.currentApplication();
if (context == null) {
return AppOpsManager.MODE_DEFAULT;
@@ -10273,11 +10288,10 @@
// TVs are constantly plugged in and has less concern for memory/power
if (ActivityManager.isLowRamDeviceStatic()
&& !pm.hasSystemFeature(PackageManager.FEATURE_LEANBACK, 0)) {
- sOpSystemAlertWindowDefaultMode = AppOpsManager.MODE_IGNORED;
- } else {
- sOpSystemAlertWindowDefaultMode = AppOpsManager.MODE_DEFAULT;
+ return AppOpsManager.MODE_IGNORED;
}
- return sOpSystemAlertWindowDefaultMode;
+
+ return AppOpsManager.MODE_DEFAULT;
}
/**
diff --git a/core/java/android/app/ConfigurationController.java b/core/java/android/app/ConfigurationController.java
index 1a77b65..18dc1ce 100644
--- a/core/java/android/app/ConfigurationController.java
+++ b/core/java/android/app/ConfigurationController.java
@@ -124,12 +124,6 @@
* @param config The new configuration.
*/
void handleConfigurationChanged(@NonNull Configuration config) {
- if (mActivityThread.isCachedProcessState()) {
- updatePendingConfiguration(config);
- // If the process is in a cached state, delay the handling until the process is no
- // longer cached.
- return;
- }
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "configChanged");
handleConfigurationChanged(config, null /* compat */);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index ac46066..4c7bc6d 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1193,7 +1193,7 @@
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
null, Activity.RESULT_OK, null, null, null, null /*excludedPermissions=*/,
- AppOpsManager.OP_NONE, null, false, false, getUserId());
+ null, AppOpsManager.OP_NONE, null, false, false, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1210,7 +1210,7 @@
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
null, Activity.RESULT_OK, null, null, receiverPermissions,
- null /*excludedPermissions=*/, AppOpsManager.OP_NONE, null, false, false,
+ null /*excludedPermissions=*/, null, AppOpsManager.OP_NONE, null, false, false,
getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -1226,7 +1226,7 @@
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
null, Activity.RESULT_OK, null, null, receiverPermissions,
- null /*excludedPermissions=*/, AppOpsManager.OP_NONE, null, false, false,
+ null /*excludedPermissions=*/, null, AppOpsManager.OP_NONE, null, false, false,
getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -1243,8 +1243,8 @@
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
null, Activity.RESULT_OK, null, null, receiverPermissions,
- null /*excludedPermissions=*/, AppOpsManager.OP_NONE, options, false, false,
- getUserId());
+ null /*excludedPermissions=*/, null /*excludedPackages*/,
+ AppOpsManager.OP_NONE, options, false, false, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1259,7 +1259,7 @@
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
null, Activity.RESULT_OK, null, null, receiverPermissions,
- null /*excludedPermissions=*/, AppOpsManager.OP_NONE, null, false, false,
+ null /*excludedPermissions=*/, null, AppOpsManager.OP_NONE, null, false, false,
user.getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -1268,7 +1268,7 @@
@Override
public void sendBroadcastMultiplePermissions(Intent intent, String[] receiverPermissions,
- String[] excludedPermissions) {
+ String[] excludedPermissions, String[] excludedPackages) {
warnIfCallingFromSystemProcess();
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
@@ -1276,7 +1276,7 @@
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
null, Activity.RESULT_OK, null, null, receiverPermissions, excludedPermissions,
- AppOpsManager.OP_NONE, null, false, false, getUserId());
+ excludedPackages, AppOpsManager.OP_NONE, null, false, false, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1303,7 +1303,7 @@
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
null, Activity.RESULT_OK, null, null, receiverPermissions,
- excludedPermissions, AppOpsManager.OP_NONE, options, false, false,
+ excludedPermissions, null, AppOpsManager.OP_NONE, options, false, false,
getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -1321,7 +1321,7 @@
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
null, Activity.RESULT_OK, null, null, receiverPermissions,
- null /*excludedPermissions=*/, appOp, null, false, false, getUserId());
+ null /*excludedPermissions=*/, null, appOp, null, false, false, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1338,7 +1338,7 @@
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
null, Activity.RESULT_OK, null, null, receiverPermissions,
- null /*excludedPermissions=*/, AppOpsManager.OP_NONE, null, true, false,
+ null /*excludedPermissions=*/, null, AppOpsManager.OP_NONE, null, true, false,
getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -1402,7 +1402,7 @@
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
rd, initialCode, initialData, initialExtras, receiverPermissions,
- null /*excludedPermissions=*/, appOp, options, true, false, getUserId());
+ null /*excludedPermissions=*/, null, appOp, options, true, false, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1416,7 +1416,7 @@
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
null, Activity.RESULT_OK, null, null, null, null /*excludedPermissions=*/,
- AppOpsManager.OP_NONE, null, false, false, user.getIdentifier());
+ null, AppOpsManager.OP_NONE, null, false, false, user.getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1439,8 +1439,8 @@
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
null, Activity.RESULT_OK, null, null, receiverPermissions,
- null /*excludedPermissions=*/, AppOpsManager.OP_NONE, options, false, false,
- user.getIdentifier());
+ null /*excludedPermissions=*/, null, AppOpsManager.OP_NONE, options, false,
+ false, user.getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1457,7 +1457,8 @@
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
null, Activity.RESULT_OK, null, null, receiverPermissions,
- null /*excludedPermissions=*/, appOp, null, false, false, user.getIdentifier());
+ null /*excludedPermissions=*/, null, appOp, null, false, false,
+ user.getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1508,7 +1509,7 @@
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
rd, initialCode, initialData, initialExtras, receiverPermissions,
- null /*excludedPermissions=*/, appOp, options, true, false,
+ null /*excludedPermissions=*/, null, appOp, options, true, false,
user.getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -1550,7 +1551,7 @@
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
null, Activity.RESULT_OK, null, null, null, null /*excludedPermissions=*/,
- AppOpsManager.OP_NONE, null, false, true, getUserId());
+ null, AppOpsManager.OP_NONE, null, false, true, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1589,7 +1590,7 @@
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
null, Activity.RESULT_OK, null, null, null, null /*excludedPermissions=*/,
- AppOpsManager.OP_NONE, options, false, true, getUserId());
+ null, AppOpsManager.OP_NONE, options, false, true, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1625,7 +1626,7 @@
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
rd, initialCode, initialData, initialExtras, null,
- null /*excludedPermissions=*/, AppOpsManager.OP_NONE, null, true, true,
+ null /*excludedPermissions=*/, null, AppOpsManager.OP_NONE, null, true, true,
getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -1658,7 +1659,7 @@
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
null, Activity.RESULT_OK, null, null, null, null /*excludedPermissions=*/,
- AppOpsManager.OP_NONE, null, false, true, user.getIdentifier());
+ null, AppOpsManager.OP_NONE, null, false, true, user.getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1673,7 +1674,7 @@
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
null, Activity.RESULT_OK, null, null, null, null /*excludedPermissions=*/,
- AppOpsManager.OP_NONE, options, false, true, user.getIdentifier());
+ null, AppOpsManager.OP_NONE, options, false, true, user.getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1708,7 +1709,7 @@
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
rd, initialCode, initialData, initialExtras, null,
- null /*excludedPermissions=*/, AppOpsManager.OP_NONE, null, true, true,
+ null /*excludedPermissions=*/, null, AppOpsManager.OP_NONE, null, true, true,
user.getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -2592,7 +2593,8 @@
try {
return createPackageContextAsUser(getPackageName(), flags, user);
} catch (NameNotFoundException e) {
- throw new IllegalStateException("Own package not found: package=" + getPackageName());
+ throw new IllegalStateException("Own package not found for user "
+ + user.getIdentifier() + ": package=" + getPackageName());
}
}
diff --git a/core/java/android/app/IActivityClientController.aidl b/core/java/android/app/IActivityClientController.aidl
index 1307161..0138186 100644
--- a/core/java/android/app/IActivityClientController.aidl
+++ b/core/java/android/app/IActivityClientController.aidl
@@ -53,6 +53,7 @@
oneway void activityStopped(in IBinder token, in Bundle state,
in PersistableBundle persistentState, in CharSequence description);
oneway void activityDestroyed(in IBinder token);
+ oneway void activityLocalRelaunch(in IBinder token);
oneway void activityRelaunched(in IBinder token);
oneway void reportSizeConfigurations(in IBinder token,
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 4efe9df..8367441 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -141,7 +141,7 @@
int broadcastIntentWithFeature(in IApplicationThread caller, in String callingFeatureId,
in Intent intent, in String resolvedType, in IIntentReceiver resultTo, int resultCode,
in String resultData, in Bundle map, in String[] requiredPermissions, in String[] excludePermissions,
- int appOp, in Bundle options, boolean serialized, boolean sticky, int userId);
+ in String[] excludePackages, int appOp, in Bundle options, boolean serialized, boolean sticky, int userId);
void unbroadcastIntent(in IApplicationThread caller, in Intent intent, int userId);
@UnsupportedAppUsage
oneway void finishReceiver(in IBinder who, int resultCode, in String resultData, in Bundle map,
diff --git a/core/java/android/app/IApplicationThread.aidl b/core/java/android/app/IApplicationThread.aidl
index f4fbcce..75ad363 100644
--- a/core/java/android/app/IApplicationThread.aidl
+++ b/core/java/android/app/IApplicationThread.aidl
@@ -72,7 +72,7 @@
@UnsupportedAppUsage
void scheduleStopService(IBinder token);
void bindApplication(in String packageName, in ApplicationInfo info,
- in String sdkSandboxClientAppPackage,
+ in String sdkSandboxClientAppVolumeUuid, in String sdkSandboxClientAppPackage,
in ProviderInfoList providerList, in ComponentName testName,
in ProfilerInfo profilerInfo, in Bundle testArguments,
IInstrumentationWatcher testWatcher, IUiAutomationConnection uiAutomationConnection,
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index df9f2a3..da6a551 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -77,6 +77,7 @@
boolean areNotificationsEnabledForPackage(String pkg, int uid);
boolean areNotificationsEnabled(String pkg);
int getPackageImportance(String pkg);
+ boolean isImportanceLocked(String pkg, int uid);
List<String> getAllowedAssistantAdjustments(String pkg);
void allowAssistantAdjustment(String adjustmentType);
diff --git a/core/java/android/app/ITaskStackListener.aidl b/core/java/android/app/ITaskStackListener.aidl
index 7bb5d9a..36e5762 100644
--- a/core/java/android/app/ITaskStackListener.aidl
+++ b/core/java/android/app/ITaskStackListener.aidl
@@ -137,7 +137,7 @@
* activities inside it belong to a managed profile user, and that user has just
* been locked.
*/
- void onTaskProfileLocked(int taskId, int userId);
+ void onTaskProfileLocked(in ActivityManager.RunningTaskInfo taskInfo);
/**
* Called when a task snapshot got updated.
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index deefea8..0849a6f 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -400,7 +400,8 @@
mLibDir = aInfo.nativeLibraryDir;
mDataDirFile = FileUtils.newFileOrNull(aInfo.dataDir);
mDeviceProtectedDataDirFile = FileUtils.newFileOrNull(aInfo.deviceProtectedDataDir);
- mCredentialProtectedDataDirFile = FileUtils.newFileOrNull(aInfo.credentialProtectedDataDir);
+ mCredentialProtectedDataDirFile = FileUtils.newFileOrNull(
+ aInfo.credentialProtectedDataDir);
mSplitNames = aInfo.splitNames;
mSplitAppDirs = aInfo.splitSourceDirs;
@@ -412,14 +413,16 @@
}
}
- /** @hide */
- void setSdkSandboxStorage(String sdkSandboxClientAppPackage) {
+ void setSdkSandboxStorage(@Nullable String sdkSandboxClientAppVolumeUuid,
+ String sdkSandboxClientAppPackage) {
int userId = UserHandle.myUserId();
mDeviceProtectedDataDirFile = Environment
- .getDataMiscDeSharedSdkSandboxDirectory(userId, sdkSandboxClientAppPackage)
+ .getDataMiscDeSharedSdkSandboxDirectory(sdkSandboxClientAppVolumeUuid, userId,
+ sdkSandboxClientAppPackage)
.getAbsoluteFile();
mCredentialProtectedDataDirFile = Environment
- .getDataMiscCeSharedSdkSandboxDirectory(userId, sdkSandboxClientAppPackage)
+ .getDataMiscCeSharedSdkSandboxDirectory(sdkSandboxClientAppVolumeUuid, userId,
+ sdkSandboxClientAppPackage)
.getAbsoluteFile();
if ((mApplicationInfo.privateFlags
diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java
index 6f0b03a..c9cc1a1 100644
--- a/core/java/android/app/NotificationChannel.java
+++ b/core/java/android/app/NotificationChannel.java
@@ -253,7 +253,6 @@
// If this is a blockable system notification channel.
private boolean mBlockableSystem = false;
private int mAllowBubbles = DEFAULT_ALLOW_BUBBLE;
- private boolean mImportanceLockedByOEM;
private boolean mImportanceLockedDefaultApp;
private String mParentId = null;
private String mConversationId = null;
@@ -322,13 +321,13 @@
mLightColor = in.readInt();
mBlockableSystem = in.readBoolean();
mAllowBubbles = in.readInt();
- mImportanceLockedByOEM = in.readBoolean();
mOriginalImportance = in.readInt();
mParentId = in.readString();
mConversationId = in.readString();
mDemoted = in.readBoolean();
mImportantConvo = in.readBoolean();
mDeletedTime = in.readLong();
+ mImportanceLockedDefaultApp = in.readBoolean();
}
@Override
@@ -382,13 +381,13 @@
dest.writeInt(mLightColor);
dest.writeBoolean(mBlockableSystem);
dest.writeInt(mAllowBubbles);
- dest.writeBoolean(mImportanceLockedByOEM);
dest.writeInt(mOriginalImportance);
dest.writeString(mParentId);
dest.writeString(mConversationId);
dest.writeBoolean(mDemoted);
dest.writeBoolean(mImportantConvo);
dest.writeLong(mDeletedTime);
+ dest.writeBoolean(mImportanceLockedDefaultApp);
}
/**
@@ -851,14 +850,6 @@
* @hide
*/
@TestApi
- public void setImportanceLockedByOEM(boolean locked) {
- mImportanceLockedByOEM = locked;
- }
-
- /**
- * @hide
- */
- @TestApi
public void setImportanceLockedByCriticalDeviceFunction(boolean locked) {
mImportanceLockedDefaultApp = locked;
}
@@ -1107,8 +1098,8 @@
out.attributeBoolean(null, ATT_IMP_CONVERSATION, isImportantConversation());
}
- // mImportanceLockedDefaultApp and mImportanceLockedByOEM have a different source of
- // truth and so aren't written to this xml file
+ // mImportanceLockedDefaultApp has a different source of truth and so isn't written to
+ // this xml file
out.endTag(null, TAG_CHANNEL);
}
@@ -1251,7 +1242,6 @@
&& Arrays.equals(mVibration, that.mVibration)
&& Objects.equals(getGroup(), that.getGroup())
&& Objects.equals(getAudioAttributes(), that.getAudioAttributes())
- && mImportanceLockedByOEM == that.mImportanceLockedByOEM
&& mImportanceLockedDefaultApp == that.mImportanceLockedDefaultApp
&& mOriginalImportance == that.mOriginalImportance
&& Objects.equals(getParentChannelId(), that.getParentChannelId())
@@ -1267,7 +1257,7 @@
getUserLockedFields(),
isFgServiceShown(), mVibrationEnabled, mShowBadge, isDeleted(), getDeletedTimeMs(),
getGroup(), getAudioAttributes(), isBlockable(), mAllowBubbles,
- mImportanceLockedByOEM, mImportanceLockedDefaultApp, mOriginalImportance,
+ mImportanceLockedDefaultApp, mOriginalImportance,
mParentId, mConversationId, mDemoted, mImportantConvo);
result = 31 * result + Arrays.hashCode(mVibration);
return result;
@@ -1312,7 +1302,6 @@
+ ", mAudioAttributes=" + mAudioAttributes
+ ", mBlockableSystem=" + mBlockableSystem
+ ", mAllowBubbles=" + mAllowBubbles
- + ", mImportanceLockedByOEM=" + mImportanceLockedByOEM
+ ", mImportanceLockedDefaultApp=" + mImportanceLockedDefaultApp
+ ", mOriginalImp=" + mOriginalImportance
+ ", mParent=" + mParentId
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index 2a1883d..d275c83 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -365,8 +365,8 @@
@NonNull Configuration config) {
config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH;
config.densityDpi = dm.densityDpi;
- config.screenWidthDp = (int) (dm.widthPixels / dm.density);
- config.screenHeightDp = (int) (dm.heightPixels / dm.density);
+ config.screenWidthDp = (int) (dm.widthPixels / dm.density + 0.5f);
+ config.screenHeightDp = (int) (dm.heightPixels / dm.density + 0.5f);
int sl = Configuration.resetScreenLayout(config.screenLayout);
if (dm.widthPixels > dm.heightPixels) {
config.orientation = Configuration.ORIENTATION_LANDSCAPE;
diff --git a/core/java/android/app/TaskInfo.java b/core/java/android/app/TaskInfo.java
index 1b87945..f7bbd74 100644
--- a/core/java/android/app/TaskInfo.java
+++ b/core/java/android/app/TaskInfo.java
@@ -143,13 +143,6 @@
public LocusId mTopActivityLocusId;
/**
- * True if the task can go in the split-screen primary stack.
- * @hide
- */
- @UnsupportedAppUsage
- public boolean supportsSplitScreenMultiWindow;
-
- /**
* Whether this task supports multi windowing modes based on the device settings and the
* root activity resizability and configuration.
* @hide
@@ -516,7 +509,6 @@
lastActiveTime = source.readLong();
taskDescription = source.readTypedObject(ActivityManager.TaskDescription.CREATOR);
- supportsSplitScreenMultiWindow = source.readBoolean();
supportsMultiWindow = source.readBoolean();
resizeMode = source.readInt();
configuration.readFromParcel(source);
@@ -563,7 +555,6 @@
dest.writeLong(lastActiveTime);
dest.writeTypedObject(taskDescription, flags);
- dest.writeBoolean(supportsSplitScreenMultiWindow);
dest.writeBoolean(supportsMultiWindow);
dest.writeInt(resizeMode);
configuration.writeToParcel(dest, flags);
@@ -601,7 +592,6 @@
+ " realActivity=" + realActivity
+ " numActivities=" + numActivities
+ " lastActiveTime=" + lastActiveTime
- + " supportsSplitScreenMultiWindow=" + supportsSplitScreenMultiWindow
+ " supportsMultiWindow=" + supportsMultiWindow
+ " resizeMode=" + resizeMode
+ " isResizeable=" + isResizeable
diff --git a/core/java/android/app/TaskStackListener.java b/core/java/android/app/TaskStackListener.java
index 83fe29f..774bc06 100644
--- a/core/java/android/app/TaskStackListener.java
+++ b/core/java/android/app/TaskStackListener.java
@@ -155,7 +155,7 @@
@Override
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public void onTaskProfileLocked(int taskId, int userId) throws RemoteException {
+ public void onTaskProfileLocked(RunningTaskInfo taskInfo) throws RemoteException {
}
@Override
diff --git a/core/java/android/app/WindowConfiguration.java b/core/java/android/app/WindowConfiguration.java
index 5ef3fc0..40edc2e 100644
--- a/core/java/android/app/WindowConfiguration.java
+++ b/core/java/android/app/WindowConfiguration.java
@@ -104,19 +104,6 @@
public static final int WINDOWING_MODE_FULLSCREEN = 1;
/** Always on-top (always visible). of other siblings in its parent container. */
public static final int WINDOWING_MODE_PINNED = 2;
- /** The primary container driving the screen to be in split-screen mode. */
- // TODO: Remove once split-screen is migrated to wm-shell.
- public static final int WINDOWING_MODE_SPLIT_SCREEN_PRIMARY = 3;
- /**
- * The containers adjacent to the {@link #WINDOWING_MODE_SPLIT_SCREEN_PRIMARY} container in
- * split-screen mode.
- * NOTE: Containers launched with the windowing mode with APIs like
- * {@link ActivityOptions#setLaunchWindowingMode(int)} will be launched in
- * {@link #WINDOWING_MODE_FULLSCREEN} if the display isn't currently in split-screen windowing
- * mode
- */
- // TODO: Remove once split-screen is migrated to wm-shell.
- public static final int WINDOWING_MODE_SPLIT_SCREEN_SECONDARY = 4;
/** Can be freely resized within its parent container. */
// TODO: Remove once freeform is migrated to wm-shell.
public static final int WINDOWING_MODE_FREEFORM = 5;
@@ -129,8 +116,6 @@
WINDOWING_MODE_FULLSCREEN,
WINDOWING_MODE_MULTI_WINDOW,
WINDOWING_MODE_PINNED,
- WINDOWING_MODE_SPLIT_SCREEN_PRIMARY,
- WINDOWING_MODE_SPLIT_SCREEN_SECONDARY,
WINDOWING_MODE_FREEFORM,
})
public @interface WindowingMode {}
@@ -882,9 +867,8 @@
}
/**
- * Returns true if this container can be put in either
- * {@link #WINDOWING_MODE_SPLIT_SCREEN_PRIMARY} or
- * {@link #WINDOWING_MODE_SPLIT_SCREEN_SECONDARY} windowing modes based on its current state.
+ * Returns true if this container can be put in {@link #WINDOWING_MODE_MULTI_WINDOW}
+ * windowing mode based on its current state.
* @hide
*/
public boolean supportSplitScreenWindowingMode() {
@@ -903,8 +887,6 @@
case WINDOWING_MODE_FULLSCREEN: return "fullscreen";
case WINDOWING_MODE_MULTI_WINDOW: return "multi-window";
case WINDOWING_MODE_PINNED: return "pinned";
- case WINDOWING_MODE_SPLIT_SCREEN_PRIMARY: return "split-screen-primary";
- case WINDOWING_MODE_SPLIT_SCREEN_SECONDARY: return "split-screen-secondary";
case WINDOWING_MODE_FREEFORM: return "freeform";
}
return String.valueOf(windowingMode);
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 4e249d6..e23c1d2 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -11230,7 +11230,9 @@
* for enterprise use.
*
* An example of a supported preferential network service is the Enterprise
- * slice on 5G networks.
+ * slice on 5G networks. For devices on 4G networks, the profile owner needs to additionally
+ * configure enterprise APN to set up data call for the preferential network service.
+ * These APNs can be added using {@link #addOverrideApn}.
*
* By default, preferential network service is disabled on the work profile and
* fully managed devices, on supported carriers and devices.
@@ -11280,7 +11282,9 @@
* {@see PreferentialNetworkServiceConfig}
*
* An example of a supported preferential network service is the Enterprise
- * slice on 5G networks.
+ * slice on 5G networks. For devices on 4G networks, the profile owner needs to additionally
+ * configure enterprise APN to set up data call for the preferential network service.
+ * These APNs can be added using {@link #addOverrideApn}.
*
* By default, preferential network service is disabled on the work profile and fully managed
* devices, on supported carriers and devices. Admins can explicitly enable it with this API.
@@ -13802,18 +13806,13 @@
}
/**
- * Called by device owner or profile owner to add an override APN.
+ * Called by device owner or managed profile owner to add an override APN.
*
* <p>This method may returns {@code -1} if {@code apnSetting} conflicts with an existing
* override APN. Update the existing conflicted APN with
* {@link #updateOverrideApn(ComponentName, int, ApnSetting)} instead of adding a new entry.
* <p>Two override APNs are considered to conflict when all the following APIs return
* the same values on both override APNs:
- * <p> Before Android version {@link android.os.Build.VERSION_CODES#TIRAMISU}:
- * Only device owners can add APNs.
- * <p> Starting from Android version {@link android.os.Build.VERSION_CODES#TIRAMISU}:
- * Device and profile owners can add enterprise APNs
- * ({@link ApnSetting#TYPE_ENTERPRISE}), while only device owners can add other type of APNs.
* <ul>
* <li>{@link ApnSetting#getOperatorNumeric()}</li>
* <li>{@link ApnSetting#getApnName()}</li>
@@ -13828,6 +13827,15 @@
* <li>{@link ApnSetting#getRoamingProtocol()}</li>
* </ul>
*
+ * <p> Before Android version {@link android.os.Build.VERSION_CODES#TIRAMISU}:
+ * Only device owners can add APNs.
+ * <p> Starting from Android version {@link android.os.Build.VERSION_CODES#TIRAMISU}:
+ * Both device owners and managed profile owners can add enterprise APNs
+ * ({@link ApnSetting#TYPE_ENTERPRISE}), while only device owners can add other type of APNs.
+ * Enterprise APNs are specific to the managed profile and do not override any user-configured
+ * VPNs. They are prerequisites for enabling preferential network service on the managed
+ * profile on 4G networks ({@link #setPreferentialNetworkServiceConfigs}).
+ *
* @param admin which {@link DeviceAdminReceiver} this request is associated with
* @param apnSetting the override APN to insert
* @return The {@code id} of inserted override APN. Or {@code -1} when failed to insert into
@@ -13850,7 +13858,7 @@
}
/**
- * Called by device owner or profile owner to update an override APN.
+ * Called by device owner or managed profile owner to update an override APN.
*
* <p>This method may returns {@code false} if there is no override APN with the given
* {@code apnId}.
@@ -13860,7 +13868,7 @@
* <p> Before Android version {@link android.os.Build.VERSION_CODES#TIRAMISU}:
* Only device owners can update APNs.
* <p> Starting from Android version {@link android.os.Build.VERSION_CODES#TIRAMISU}:
- * Device and profile owners can update enterprise APNs
+ * Both device owners and managed profile owners can update enterprise APNs
* ({@link ApnSetting#TYPE_ENTERPRISE}), while only device owners can update other type of APNs.
*
* @param admin which {@link DeviceAdminReceiver} this request is associated with
@@ -13887,14 +13895,14 @@
}
/**
- * Called by device owner or profile owner to remove an override APN.
+ * Called by device owner or managed profile owner to remove an override APN.
*
* <p>This method may returns {@code false} if there is no override APN with the given
* {@code apnId}.
* <p> Before Android version {@link android.os.Build.VERSION_CODES#TIRAMISU}:
* Only device owners can remove APNs.
* <p> Starting from Android version {@link android.os.Build.VERSION_CODES#TIRAMISU}:
- * Device and profile owners can remove enterprise APNs
+ * Both device owners and managed profile owners can remove enterprise APNs
* ({@link ApnSetting#TYPE_ENTERPRISE}), while only device owners can remove other type of APNs.
*
* @param admin which {@link DeviceAdminReceiver} this request is associated with
@@ -13919,7 +13927,8 @@
}
/**
- * Called by device owner to get all override APNs inserted by device owner.
+ * Called by device owner or managed profile owner to get all override APNs inserted by
+ * device owner or managed profile owner previously using {@link #addOverrideApn}.
*
* @param admin which {@link DeviceAdminReceiver} this request is associated with
* @return A list of override APNs inserted by device owner.
@@ -13944,6 +13953,9 @@
* <p> Override APNs are separated from other APNs on the device, and can only be inserted or
* modified by the device owner. When enabled, only override APNs are in use, any other APNs
* are ignored.
+ * <p>Note: Enterprise APNs added by managed profile owners do not need to be enabled by
+ * this API. They are part of the preferential network service config and is controlled by
+ * {@link #setPreferentialNetworkServiceConfigs}.
*
* @param admin which {@link DeviceAdminReceiver} this request is associated with
* @param enabled {@code true} if override APNs should be enabled, {@code false} otherwise
@@ -14589,12 +14601,13 @@
}
/**
- * Called by Device owner to disable user control over apps. User will not be able to clear
- * app data or force-stop packages.
+ * Called by a device owner or a profile owner to disable user control over apps. User will not
+ * be able to clear app data or force-stop packages. When called by a device owner, applies to
+ * all users on the device.
*
* @param admin which {@link DeviceAdminReceiver} this request is associated with
* @param packages The package names for the apps.
- * @throws SecurityException if {@code admin} is not a device owner.
+ * @throws SecurityException if {@code admin} is not a device owner or a profile owner.
*/
public void setUserControlDisabledPackages(@NonNull ComponentName admin,
@NonNull List<String> packages) {
@@ -14609,12 +14622,14 @@
}
/**
- * Returns the list of packages over which user control is disabled by the device owner.
+ * Returns the list of packages over which user control is disabled by a device or profile
+ * owner.
*
* @param admin which {@link DeviceAdminReceiver} this request is associated with
- * @throws SecurityException if {@code admin} is not a device owner.
+ * @throws SecurityException if {@code admin} is not a device or profile owner.
*/
- public @NonNull List<String> getUserControlDisabledPackages(@NonNull ComponentName admin) {
+ @NonNull
+ public List<String> getUserControlDisabledPackages(@NonNull ComponentName admin) {
throwIfParentInstance("getUserControlDisabledPackages");
if (mService != null) {
try {
diff --git a/core/java/android/app/admin/DevicePolicyResources.java b/core/java/android/app/admin/DevicePolicyResources.java
index c8033fa..11b840f 100644
--- a/core/java/android/app/admin/DevicePolicyResources.java
+++ b/core/java/android/app/admin/DevicePolicyResources.java
@@ -184,6 +184,12 @@
PREFIX + "WORK_PROFILE_IT_ADMIN_CANT_RESET_SCREEN_LOCK";
/**
+ * Text shown on the CTA link shown to user to set a separate lock for work apps
+ */
+ public static final String WORK_PROFILE_IT_ADMIN_CANT_RESET_SCREEN_LOCK_ACTION =
+ PREFIX + "WORK_PROFILE_IT_ADMIN_CANT_RESET_SCREEN_LOCK_ACTION";
+
+ /**
* Message shown in screen lock picker for setting up a work profile screen lock
*/
public static final String WORK_PROFILE_SCREEN_LOCK_SETUP_MESSAGE =
@@ -1492,6 +1498,45 @@
* Content description for the work profile lock screen.
*/
public static final String WORK_LOCK_ACCESSIBILITY = PREFIX + "WORK_LOCK_ACCESSIBILITY";
+
+ /**
+ * Notification text displayed when screenshots are blocked by an IT admin.
+ */
+ public static final String SCREENSHOT_BLOCKED_BY_ADMIN =
+ PREFIX + "SCREENSHOT_BLOCKED_BY_ADMIN";
+
+ /**
+ * Message shown when user is almost at the limit of password attempts where the
+ * profile will be removed. Accepts number of failed attempts and remaining failed
+ * attempts as params.
+ */
+ public static final String KEYGUARD_DIALOG_FAILED_ATTEMPTS_ALMOST_ERASING_PROFILE =
+ PREFIX + "KEYGUARD_DIALOG_FAILED_ATTEMPTS_ALMOST_ERASING_PROFILE";
+
+ /**
+ * Message shown in dialog when user has exceeded the maximum attempts and the profile
+ * will be removed. Accepts number of failed attempts as a param.
+ */
+ public static final String KEYGUARD_DIALOG_FAILED_ATTEMPTS_ERASING_PROFILE =
+ PREFIX + "KEYGUARD_DIALOG_FAILED_ATTEMPTS_ERASING_PROFILE";
+
+ /**
+ * Monitoring dialog subtitle for the section describing VPN.
+ */
+ public static final String QS_DIALOG_MONITORING_VPN_SUBTITLE =
+ PREFIX + "QS_DIALOG_MONITORING_VPN_SUBTITLE";
+
+ /**
+ * Monitoring dialog subtitle for the section describing network logging.
+ */
+ public static final String QS_DIALOG_MONITORING_NETWORK_SUBTITLE =
+ PREFIX + "QS_DIALOG_MONITORING_NETWORK_SUBTITLE";
+
+ /**
+ * Monitoring dialog subtitle for the section describing certificate authorities.
+ */
+ public static final String QS_DIALOG_MONITORING_CA_CERT_SUBTITLE =
+ PREFIX + "QS_DIALOG_MONITORING_CA_CERT_SUBTITLE";
}
/**
diff --git a/core/java/android/app/admin/DevicePolicyResourcesManager.java b/core/java/android/app/admin/DevicePolicyResourcesManager.java
index e8eb792..2cc189f 100644
--- a/core/java/android/app/admin/DevicePolicyResourcesManager.java
+++ b/core/java/android/app/admin/DevicePolicyResourcesManager.java
@@ -26,6 +26,7 @@
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.os.RemoteException;
+import android.provider.DeviceConfig;
import android.util.DisplayMetrics;
import android.util.Log;
@@ -40,6 +41,9 @@
public class DevicePolicyResourcesManager {
private static String TAG = "DevicePolicyResourcesManager";
+ private static String DISABLE_RESOURCES_UPDATABILITY_FLAG = "disable_resources_updatability";
+ private static boolean DEFAULT_DISABLE_RESOURCES_UPDATABILITY = false;
+
private final Context mContext;
private final IDevicePolicyManager mService;
@@ -194,16 +198,20 @@
Objects.requireNonNull(drawableSource, "drawableSource can't be null");
Objects.requireNonNull(defaultDrawableLoader, "defaultDrawableLoader can't be null");
- if (drawableId.equals(DevicePolicyResources.UNDEFINED)) {
+ if (drawableId.equals(DevicePolicyResources.UNDEFINED)
+ || DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_DEVICE_POLICY_MANAGER,
+ DISABLE_RESOURCES_UPDATABILITY_FLAG,
+ DEFAULT_DISABLE_RESOURCES_UPDATABILITY)) {
return ParcelableResource.loadDefaultDrawable(defaultDrawableLoader);
}
+
if (mService != null) {
try {
ParcelableResource resource = mService.getDrawable(
drawableId, drawableStyle, drawableSource);
if (resource == null) {
- return ParcelableResource.loadDefaultDrawable(
- defaultDrawableLoader);
+ return ParcelableResource.loadDefaultDrawable(defaultDrawableLoader);
}
return resource.getDrawable(
mContext,
@@ -287,16 +295,20 @@
Objects.requireNonNull(drawableSource, "drawableSource can't be null");
Objects.requireNonNull(defaultDrawableLoader, "defaultDrawableLoader can't be null");
- if (drawableId.equals(DevicePolicyResources.UNDEFINED)) {
+ if (drawableId.equals(DevicePolicyResources.UNDEFINED)
+ || DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_DEVICE_POLICY_MANAGER,
+ DISABLE_RESOURCES_UPDATABILITY_FLAG,
+ DEFAULT_DISABLE_RESOURCES_UPDATABILITY)) {
return ParcelableResource.loadDefaultDrawable(defaultDrawableLoader);
}
+
if (mService != null) {
try {
ParcelableResource resource = mService.getDrawable(
drawableId, drawableStyle, drawableSource);
if (resource == null) {
- return ParcelableResource.loadDefaultDrawable(
- defaultDrawableLoader);
+ return ParcelableResource.loadDefaultDrawable(defaultDrawableLoader);
}
return resource.getDrawable(mContext, density, defaultDrawableLoader);
} catch (RemoteException e) {
@@ -330,9 +342,14 @@
Objects.requireNonNull(drawableSource, "drawableSource can't be null");
Objects.requireNonNull(defaultIcon, "defaultIcon can't be null");
- if (drawableId.equals(DevicePolicyResources.UNDEFINED)) {
+ if (drawableId.equals(DevicePolicyResources.UNDEFINED)
+ || DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_DEVICE_POLICY_MANAGER,
+ DISABLE_RESOURCES_UPDATABILITY_FLAG,
+ DEFAULT_DISABLE_RESOURCES_UPDATABILITY)) {
return defaultIcon;
}
+
if (mService != null) {
try {
ParcelableResource resource = mService.getDrawable(
@@ -463,7 +480,10 @@
Objects.requireNonNull(stringId, "stringId can't be null");
Objects.requireNonNull(defaultStringLoader, "defaultStringLoader can't be null");
- if (stringId.equals(DevicePolicyResources.UNDEFINED)) {
+ if (stringId.equals(DevicePolicyResources.UNDEFINED) || DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_DEVICE_POLICY_MANAGER,
+ DISABLE_RESOURCES_UPDATABILITY_FLAG,
+ DEFAULT_DISABLE_RESOURCES_UPDATABILITY)) {
return ParcelableResource.loadDefaultString(defaultStringLoader);
}
if (mService != null) {
@@ -508,7 +528,10 @@
Objects.requireNonNull(stringId, "stringId can't be null");
Objects.requireNonNull(defaultStringLoader, "defaultStringLoader can't be null");
- if (stringId.equals(DevicePolicyResources.UNDEFINED)) {
+ if (stringId.equals(DevicePolicyResources.UNDEFINED) || DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_DEVICE_POLICY_MANAGER,
+ DISABLE_RESOURCES_UPDATABILITY_FLAG,
+ DEFAULT_DISABLE_RESOURCES_UPDATABILITY)) {
return ParcelableResource.loadDefaultString(defaultStringLoader);
}
if (mService != null) {
diff --git a/core/java/android/app/admin/PasswordMetrics.java b/core/java/android/app/admin/PasswordMetrics.java
index 4c1a363..ab48791 100644
--- a/core/java/android/app/admin/PasswordMetrics.java
+++ b/core/java/android/app/admin/PasswordMetrics.java
@@ -41,6 +41,7 @@
import static com.android.internal.widget.PasswordValidationError.NOT_ENOUGH_UPPER_CASE;
import static com.android.internal.widget.PasswordValidationError.TOO_LONG;
import static com.android.internal.widget.PasswordValidationError.TOO_SHORT;
+import static com.android.internal.widget.PasswordValidationError.TOO_SHORT_WHEN_ALL_NUMERIC;
import static com.android.internal.widget.PasswordValidationError.WEAK_CREDENTIAL_TYPE;
import android.annotation.IntDef;
@@ -569,21 +570,15 @@
result.add(new PasswordValidationError(TOO_LONG, MAX_PASSWORD_LENGTH));
}
- // A flag indicating whether the provided password already has non-numeric characters in
- // it or if the admin imposes the requirement of any non-numeric characters.
- final boolean hasOrWouldNeedNonNumeric =
- actualMetrics.nonNumeric > 0 || adminMetrics.nonNumeric > 0
- || adminMetrics.letters > 0 || adminMetrics.lowerCase > 0
- || adminMetrics.upperCase > 0 || adminMetrics.symbols > 0;
- final PasswordMetrics minMetrics =
- applyComplexity(adminMetrics, hasOrWouldNeedNonNumeric, bucket);
+ final PasswordMetrics minMetrics = applyComplexity(adminMetrics,
+ actualMetrics.credType == CREDENTIAL_TYPE_PIN, bucket);
// Clamp required length between maximum and minimum valid values.
minMetrics.length = Math.min(MAX_PASSWORD_LENGTH,
Math.max(minMetrics.length, MIN_LOCK_PASSWORD_SIZE));
minMetrics.removeOverlapping();
- comparePasswordMetrics(minMetrics, actualMetrics, result);
+ comparePasswordMetrics(minMetrics, bucket, actualMetrics, result);
return result;
}
@@ -591,11 +586,23 @@
/**
* TODO: move to PasswordPolicy
*/
- private static void comparePasswordMetrics(PasswordMetrics minMetrics,
+ private static void comparePasswordMetrics(PasswordMetrics minMetrics, ComplexityBucket bucket,
PasswordMetrics actualMetrics, ArrayList<PasswordValidationError> result) {
if (actualMetrics.length < minMetrics.length) {
result.add(new PasswordValidationError(TOO_SHORT, minMetrics.length));
}
+ if (actualMetrics.nonNumeric == 0 && minMetrics.nonNumeric == 0 && minMetrics.letters == 0
+ && minMetrics.lowerCase == 0 && minMetrics.upperCase == 0
+ && minMetrics.symbols == 0) {
+ // When provided password is all numeric and all numeric password is allowed.
+ int allNumericMinimumLength = bucket.getMinimumLength(false);
+ if (allNumericMinimumLength > minMetrics.length
+ && allNumericMinimumLength > minMetrics.numeric
+ && actualMetrics.length < allNumericMinimumLength) {
+ result.add(new PasswordValidationError(
+ TOO_SHORT_WHEN_ALL_NUMERIC, allNumericMinimumLength));
+ }
+ }
if (actualMetrics.letters < minMetrics.letters) {
result.add(new PasswordValidationError(NOT_ENOUGH_LETTERS, minMetrics.letters));
}
@@ -668,15 +675,12 @@
*
* TODO: move to PasswordPolicy
*/
- public static PasswordMetrics applyComplexity(
- PasswordMetrics adminMetrics, boolean withNonNumericCharacters,
+ public static PasswordMetrics applyComplexity(PasswordMetrics adminMetrics, boolean isPin,
int complexity) {
- return applyComplexity(adminMetrics, withNonNumericCharacters,
- ComplexityBucket.forComplexity(complexity));
+ return applyComplexity(adminMetrics, isPin, ComplexityBucket.forComplexity(complexity));
}
- private static PasswordMetrics applyComplexity(
- PasswordMetrics adminMetrics, boolean withNonNumericCharacters,
+ private static PasswordMetrics applyComplexity(PasswordMetrics adminMetrics, boolean isPin,
ComplexityBucket bucket) {
final PasswordMetrics minMetrics = new PasswordMetrics(adminMetrics);
@@ -684,8 +688,7 @@
minMetrics.seqLength = Math.min(minMetrics.seqLength, MAX_ALLOWED_SEQUENCE);
}
- minMetrics.length = Math.max(minMetrics.length,
- bucket.getMinimumLength(withNonNumericCharacters));
+ minMetrics.length = Math.max(minMetrics.length, bucket.getMinimumLength(!isPin));
return minMetrics;
}
diff --git a/core/java/android/app/backup/BackupTransport.java b/core/java/android/app/backup/BackupTransport.java
index 9bb048d..f6de72b 100644
--- a/core/java/android/app/backup/BackupTransport.java
+++ b/core/java/android/app/backup/BackupTransport.java
@@ -665,184 +665,292 @@
@Override
public void name(AndroidFuture<String> resultFuture) throws RemoteException {
- String result = BackupTransport.this.name();
- resultFuture.complete(result);
+ try {
+ String result = BackupTransport.this.name();
+ resultFuture.complete(result);
+ } catch (RuntimeException e) {
+ resultFuture.cancel(/* mayInterruptIfRunning */ true);
+ }
}
@Override
public void configurationIntent(AndroidFuture<Intent> resultFuture)
throws RemoteException {
- Intent result = BackupTransport.this.configurationIntent();
- resultFuture.complete(result);
+ try {
+ Intent result = BackupTransport.this.configurationIntent();
+ resultFuture.complete(result);
+ } catch (RuntimeException e) {
+ resultFuture.cancel(/* mayInterruptIfRunning */ true);
+ }
}
@Override
public void currentDestinationString(AndroidFuture<String> resultFuture)
throws RemoteException {
- String result = BackupTransport.this.currentDestinationString();
- resultFuture.complete(result);
+ try {
+ String result = BackupTransport.this.currentDestinationString();
+ resultFuture.complete(result);
+ } catch (RuntimeException e) {
+ resultFuture.cancel(/* mayInterruptIfRunning */ true);
+ }
}
@Override
public void dataManagementIntent(AndroidFuture<Intent> resultFuture)
throws RemoteException {
- Intent result = BackupTransport.this.dataManagementIntent();
- resultFuture.complete(result);
+ try {
+ Intent result = BackupTransport.this.dataManagementIntent();
+ resultFuture.complete(result);
+ } catch (RuntimeException e) {
+ resultFuture.cancel(/* mayInterruptIfRunning */ true);
+ }
}
@Override
public void dataManagementIntentLabel(AndroidFuture<CharSequence> resultFuture)
throws RemoteException {
- CharSequence result = BackupTransport.this.dataManagementIntentLabel();
- resultFuture.complete(result);
+ try {
+ CharSequence result = BackupTransport.this.dataManagementIntentLabel();
+ resultFuture.complete(result);
+ } catch (RuntimeException e) {
+ resultFuture.cancel(/* mayInterruptIfRunning */ true);
+ }
}
@Override
public void transportDirName(AndroidFuture<String> resultFuture) throws RemoteException {
- String result = BackupTransport.this.transportDirName();
- resultFuture.complete(result);
+ try {
+ String result = BackupTransport.this.transportDirName();
+ resultFuture.complete(result);
+ } catch (RuntimeException e) {
+ resultFuture.cancel(/* mayInterruptIfRunning */ true);
+ }
}
@Override
public void requestBackupTime(AndroidFuture<Long> resultFuture) throws RemoteException {
- long result = BackupTransport.this.requestBackupTime();
- resultFuture.complete(result);
+ try {
+ long result = BackupTransport.this.requestBackupTime();
+ resultFuture.complete(result);
+ } catch (RuntimeException e) {
+ resultFuture.cancel(/* mayInterruptIfRunning */ true);
+ }
}
@Override
public void initializeDevice(ITransportStatusCallback callback) throws RemoteException {
- int result = BackupTransport.this.initializeDevice();
- callback.onOperationCompleteWithStatus(result);
+ try {
+ int result = BackupTransport.this.initializeDevice();
+ callback.onOperationCompleteWithStatus(result);
+ } catch (RuntimeException e) {
+ callback.onOperationCompleteWithStatus(BackupTransport.TRANSPORT_ERROR);
+ }
}
@Override
public void performBackup(PackageInfo packageInfo, ParcelFileDescriptor inFd, int flags,
ITransportStatusCallback callback) throws RemoteException {
- int result = BackupTransport.this.performBackup(packageInfo, inFd, flags);
- callback.onOperationCompleteWithStatus(result);
+ try {
+ int result = BackupTransport.this.performBackup(packageInfo, inFd, flags);
+ callback.onOperationCompleteWithStatus(result);
+ } catch (RuntimeException e) {
+ callback.onOperationCompleteWithStatus(BackupTransport.TRANSPORT_ERROR);
+ }
}
@Override
public void clearBackupData(PackageInfo packageInfo, ITransportStatusCallback callback)
throws RemoteException {
- int result = BackupTransport.this.clearBackupData(packageInfo);
- callback.onOperationCompleteWithStatus(result);
+ try {
+ int result = BackupTransport.this.clearBackupData(packageInfo);
+ callback.onOperationCompleteWithStatus(result);
+ } catch (RuntimeException e) {
+ callback.onOperationCompleteWithStatus(BackupTransport.TRANSPORT_ERROR);
+ }
}
@Override
public void finishBackup(ITransportStatusCallback callback) throws RemoteException {
- int result = BackupTransport.this.finishBackup();
- callback.onOperationCompleteWithStatus(result);
+ try {
+ int result = BackupTransport.this.finishBackup();
+ callback.onOperationCompleteWithStatus(result);
+ } catch (RuntimeException e) {
+ callback.onOperationCompleteWithStatus(BackupTransport.TRANSPORT_ERROR);
+ }
}
@Override
public void getAvailableRestoreSets(AndroidFuture<List<RestoreSet>> resultFuture)
throws RemoteException {
- RestoreSet[] result = BackupTransport.this.getAvailableRestoreSets();
- resultFuture.complete(Arrays.asList(result));
+ try {
+ RestoreSet[] result = BackupTransport.this.getAvailableRestoreSets();
+ resultFuture.complete(Arrays.asList(result));
+ } catch (RuntimeException e) {
+ resultFuture.cancel(/* mayInterruptIfRunning */ true);
+ }
}
@Override
public void getCurrentRestoreSet(AndroidFuture<Long> resultFuture)
throws RemoteException {
- long result = BackupTransport.this.getCurrentRestoreSet();
- resultFuture.complete(result);
+ try {
+ long result = BackupTransport.this.getCurrentRestoreSet();
+ resultFuture.complete(result);
+ } catch (RuntimeException e) {
+ resultFuture.cancel(/* mayInterruptIfRunning */ true);
+ }
}
@Override
public void startRestore(long token, PackageInfo[] packages,
ITransportStatusCallback callback) throws RemoteException {
- int result = BackupTransport.this.startRestore(token, packages);
- callback.onOperationCompleteWithStatus(result);
+ try {
+ int result = BackupTransport.this.startRestore(token, packages);
+ callback.onOperationCompleteWithStatus(result);
+ } catch (RuntimeException e) {
+ callback.onOperationCompleteWithStatus(BackupTransport.TRANSPORT_ERROR);
+ }
}
@Override
public void nextRestorePackage(AndroidFuture<RestoreDescription> resultFuture)
throws RemoteException {
- RestoreDescription result = BackupTransport.this.nextRestorePackage();
- resultFuture.complete(result);
+ try {
+ RestoreDescription result = BackupTransport.this.nextRestorePackage();
+ resultFuture.complete(result);
+ } catch (RuntimeException e) {
+ resultFuture.cancel(/* mayInterruptIfRunning */ true);
+ }
}
@Override
public void getRestoreData(ParcelFileDescriptor outFd,
ITransportStatusCallback callback) throws RemoteException {
- int result = BackupTransport.this.getRestoreData(outFd);
- callback.onOperationCompleteWithStatus(result);
+ try {
+ int result = BackupTransport.this.getRestoreData(outFd);
+ callback.onOperationCompleteWithStatus(result);
+ } catch (RuntimeException e) {
+ callback.onOperationCompleteWithStatus(BackupTransport.TRANSPORT_ERROR);
+ }
}
@Override
public void finishRestore(ITransportStatusCallback callback)
throws RemoteException {
- BackupTransport.this.finishRestore();
- callback.onOperationComplete();
+ try {
+ BackupTransport.this.finishRestore();
+ callback.onOperationComplete();
+ } catch (RuntimeException e) {
+ callback.onOperationCompleteWithStatus(BackupTransport.TRANSPORT_ERROR);
+ }
}
@Override
public void requestFullBackupTime(AndroidFuture<Long> resultFuture)
throws RemoteException {
- long result = BackupTransport.this.requestFullBackupTime();
- resultFuture.complete(result);
+ try {
+ long result = BackupTransport.this.requestFullBackupTime();
+ resultFuture.complete(result);
+ } catch (RuntimeException e) {
+ resultFuture.cancel(/* mayInterruptIfRunning */ true);
+ }
}
@Override
public void performFullBackup(PackageInfo targetPackage, ParcelFileDescriptor socket,
int flags, ITransportStatusCallback callback) throws RemoteException {
- int result = BackupTransport.this.performFullBackup(targetPackage, socket, flags);
- callback.onOperationCompleteWithStatus(result);
+ try {
+ int result = BackupTransport.this.performFullBackup(targetPackage, socket, flags);
+ callback.onOperationCompleteWithStatus(result);
+ } catch (RuntimeException e) {
+ callback.onOperationCompleteWithStatus(BackupTransport.TRANSPORT_ERROR);
+ }
}
@Override
public void checkFullBackupSize(long size, ITransportStatusCallback callback)
throws RemoteException {
- int result = BackupTransport.this.checkFullBackupSize(size);
- callback.onOperationCompleteWithStatus(result);
+ try {
+ int result = BackupTransport.this.checkFullBackupSize(size);
+ callback.onOperationCompleteWithStatus(result);
+ } catch (RuntimeException e) {
+ callback.onOperationCompleteWithStatus(BackupTransport.TRANSPORT_ERROR);
+ }
}
@Override
public void sendBackupData(int numBytes, ITransportStatusCallback callback)
throws RemoteException {
- int result = BackupTransport.this.sendBackupData(numBytes);
- callback.onOperationCompleteWithStatus(result);
+ try {
+ int result = BackupTransport.this.sendBackupData(numBytes);
+ callback.onOperationCompleteWithStatus(result);
+ } catch (RuntimeException e) {
+ callback.onOperationCompleteWithStatus(BackupTransport.TRANSPORT_ERROR);
+ }
}
@Override
public void cancelFullBackup(ITransportStatusCallback callback) throws RemoteException {
- BackupTransport.this.cancelFullBackup();
- callback.onOperationComplete();
+ try {
+ BackupTransport.this.cancelFullBackup();
+ callback.onOperationComplete();
+ } catch (RuntimeException e) {
+ callback.onOperationCompleteWithStatus(BackupTransport.TRANSPORT_ERROR);
+ }
}
@Override
public void isAppEligibleForBackup(PackageInfo targetPackage, boolean isFullBackup,
AndroidFuture<Boolean> resultFuture) throws RemoteException {
- boolean result = BackupTransport.this.isAppEligibleForBackup(targetPackage,
- isFullBackup);
- resultFuture.complete(result);
+ try {
+ boolean result = BackupTransport.this.isAppEligibleForBackup(targetPackage,
+ isFullBackup);
+ resultFuture.complete(result);
+ } catch (RuntimeException e) {
+ resultFuture.cancel(/* mayInterruptIfRunning */ true);
+ }
}
@Override
public void getBackupQuota(String packageName, boolean isFullBackup,
AndroidFuture<Long> resultFuture) throws RemoteException {
- long result = BackupTransport.this.getBackupQuota(packageName, isFullBackup);
- resultFuture.complete(result);
+ try {
+ long result = BackupTransport.this.getBackupQuota(packageName, isFullBackup);
+ resultFuture.complete(result);
+ } catch (RuntimeException e) {
+ resultFuture.cancel(/* mayInterruptIfRunning */ true);
+ }
}
@Override
public void getTransportFlags(AndroidFuture<Integer> resultFuture) throws RemoteException {
- int result = BackupTransport.this.getTransportFlags();
- resultFuture.complete(result);
+ try {
+ int result = BackupTransport.this.getTransportFlags();
+ resultFuture.complete(result);
+ } catch (RuntimeException e) {
+ resultFuture.cancel(/* mayInterruptIfRunning */ true);
+ }
}
@Override
public void getNextFullRestoreDataChunk(ParcelFileDescriptor socket,
ITransportStatusCallback callback) throws RemoteException {
- int result = BackupTransport.this.getNextFullRestoreDataChunk(socket);
- callback.onOperationCompleteWithStatus(result);
+ try {
+ int result = BackupTransport.this.getNextFullRestoreDataChunk(socket);
+ callback.onOperationCompleteWithStatus(result);
+ } catch (RuntimeException e) {
+ callback.onOperationCompleteWithStatus(BackupTransport.TRANSPORT_ERROR);
+ }
}
@Override
public void abortFullRestore(ITransportStatusCallback callback) throws RemoteException {
- int result = BackupTransport.this.abortFullRestore();
- callback.onOperationCompleteWithStatus(result);
+ try {
+ int result = BackupTransport.this.abortFullRestore();
+ callback.onOperationCompleteWithStatus(result);
+ } catch (RuntimeException e) {
+ callback.onOperationCompleteWithStatus(BackupTransport.TRANSPORT_ERROR);
+ }
}
}
}
diff --git a/core/java/android/app/smartspace/SmartspaceTarget.java b/core/java/android/app/smartspace/SmartspaceTarget.java
index be077435..79d7b21 100644
--- a/core/java/android/app/smartspace/SmartspaceTarget.java
+++ b/core/java/android/app/smartspace/SmartspaceTarget.java
@@ -174,7 +174,7 @@
public static final int FEATURE_MEDIA_HEADS_UP = 36;
public static final int FEATURE_STEP_COUNTING = 37;
public static final int FEATURE_EARTHQUAKE_ALERT = 38;
- public static final int FEATURE_STEP_DATE = 39;
+ public static final int FEATURE_STEP_DATE = 39; // This represents a DATE. "STEP" is a typo.
public static final int FEATURE_BLAZE_BUILD_PROGRESS = 40;
public static final int FEATURE_EARTHQUAKE_OCCURRED = 41;
@@ -283,7 +283,7 @@
this.mAssociatedSmartspaceTargetId = in.readString();
this.mSliceUri = in.readTypedObject(Uri.CREATOR);
this.mWidget = in.readTypedObject(AppWidgetProviderInfo.CREATOR);
- this.mTemplateData = in.readTypedObject(BaseTemplateData.CREATOR);
+ this.mTemplateData = in.readParcelable(/* loader= */null, BaseTemplateData.class);
}
private SmartspaceTarget(String smartspaceTargetId,
@@ -491,7 +491,7 @@
dest.writeString(this.mAssociatedSmartspaceTargetId);
dest.writeTypedObject(this.mSliceUri, flags);
dest.writeTypedObject(this.mWidget, flags);
- dest.writeTypedObject(this.mTemplateData, flags);
+ dest.writeParcelable(this.mTemplateData, flags);
}
@Override
diff --git a/core/java/android/appwidget/OWNERS b/core/java/android/appwidget/OWNERS
index 439df4b..554b0de 100644
--- a/core/java/android/appwidget/OWNERS
+++ b/core/java/android/appwidget/OWNERS
@@ -1,3 +1,4 @@
pinyaoting@google.com
+sihua@google.com
suprabh@google.com
sunnygoyal@google.com
diff --git a/core/java/android/companion/virtual/OWNERS b/core/java/android/companion/virtual/OWNERS
new file mode 100644
index 0000000..2968104
--- /dev/null
+++ b/core/java/android/companion/virtual/OWNERS
@@ -0,0 +1 @@
+include /services/companion/java/com/android/server/companion/virtual/OWNERS
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 907db7d..836bff5 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2269,6 +2269,19 @@
*/
public void sendBroadcastMultiplePermissions(@NonNull Intent intent,
@NonNull String[] receiverPermissions, @Nullable String[] excludedPermissions) {
+ sendBroadcastMultiplePermissions(intent, receiverPermissions, excludedPermissions, null);
+ }
+
+
+ /**
+ * Like {@link #sendBroadcastMultiplePermissions(Intent, String[], String[])}, but also allows
+ * specification of a list of excluded packages.
+ *
+ * @hide
+ */
+ public void sendBroadcastMultiplePermissions(@NonNull Intent intent,
+ @NonNull String[] receiverPermissions, @Nullable String[] excludedPermissions,
+ @Nullable String[] excludedPackages) {
throw new RuntimeException("Not implemented. Must override in a subclass.");
}
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 4ecd776..e654918 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -515,8 +515,10 @@
/** @hide */
@Override
public void sendBroadcastMultiplePermissions(@NonNull Intent intent,
- @NonNull String[] receiverPermissions, @Nullable String[] excludedPermissions) {
- mBase.sendBroadcastMultiplePermissions(intent, receiverPermissions, excludedPermissions);
+ @NonNull String[] receiverPermissions, @Nullable String[] excludedPermissions,
+ @Nullable String[] excludedPackages) {
+ mBase.sendBroadcastMultiplePermissions(intent, receiverPermissions, excludedPermissions,
+ excludedPackages);
}
/** @hide */
diff --git a/core/java/android/content/pm/AppSearchShortcutInfo.java b/core/java/android/content/pm/AppSearchShortcutInfo.java
index 1b84686b..fb41b89 100644
--- a/core/java/android/content/pm/AppSearchShortcutInfo.java
+++ b/core/java/android/content/pm/AppSearchShortcutInfo.java
@@ -413,7 +413,10 @@
final int iconResId = (int) getPropertyLong(KEY_ICON_RES_ID);
final String iconResName = getPropertyString(KEY_ICON_RES_NAME);
final String iconUri = getPropertyString(KEY_ICON_URI);
- final int disabledReason = Integer.parseInt(getPropertyString(KEY_DISABLED_REASON));
+ final String disabledReasonString = getPropertyString(KEY_DISABLED_REASON);
+ final int disabledReason = !TextUtils.isEmpty(disabledReasonString)
+ ? Integer.parseInt(getPropertyString(KEY_DISABLED_REASON))
+ : ShortcutInfo.DISABLED_REASON_NOT_DISABLED;
final Map<String, Map<String, List<String>>> capabilityBindings =
parseCapabilityBindings(getPropertyStringArray(KEY_CAPABILITY_BINDINGS));
return new ShortcutInfo(
diff --git a/core/java/android/content/res/AssetFileDescriptor.java b/core/java/android/content/res/AssetFileDescriptor.java
index dd00c3a..ac65933 100644
--- a/core/java/android/content/res/AssetFileDescriptor.java
+++ b/core/java/android/content/res/AssetFileDescriptor.java
@@ -21,8 +21,6 @@
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.Parcelable;
-import android.system.ErrnoException;
-import android.system.Os;
import java.io.Closeable;
import java.io.FileDescriptor;
@@ -54,11 +52,11 @@
/**
* Create a new AssetFileDescriptor from the given values.
*
- * @param fd The underlying file descriptor.
+ * @param fd The underlying file descriptor.
* @param startOffset The location within the file that the asset starts.
- * This must be 0 if length is UNKNOWN_LENGTH.
- * @param length The number of bytes of the asset, or
- * {@link #UNKNOWN_LENGTH} if it extends to the end of the file.
+ * This must be 0 if length is UNKNOWN_LENGTH.
+ * @param length The number of bytes of the asset, or
+ * {@link #UNKNOWN_LENGTH} if it extends to the end of the file.
*/
public AssetFileDescriptor(ParcelFileDescriptor fd, long startOffset,
long length) {
@@ -68,13 +66,13 @@
/**
* Create a new AssetFileDescriptor from the given values.
*
- * @param fd The underlying file descriptor.
+ * @param fd The underlying file descriptor.
* @param startOffset The location within the file that the asset starts.
- * This must be 0 if length is UNKNOWN_LENGTH.
- * @param length The number of bytes of the asset, or
- * {@link #UNKNOWN_LENGTH} if it extends to the end of the file.
- * @param extras additional details that can be used to interpret the
- * underlying file descriptor. May be null.
+ * This must be 0 if length is UNKNOWN_LENGTH.
+ * @param length The number of bytes of the asset, or
+ * {@link #UNKNOWN_LENGTH} if it extends to the end of the file.
+ * @param extras additional details that can be used to interpret the
+ * underlying file descriptor. May be null.
*/
public AssetFileDescriptor(ParcelFileDescriptor fd, long startOffset,
long length, Bundle extras) {
@@ -205,24 +203,19 @@
*/
public static class AutoCloseInputStream
extends ParcelFileDescriptor.AutoCloseInputStream {
- private final long mSizeFromStartOffset;
- private final long mStartOffset;
- private long mPosFromStartOffset;
+ private long mRemaining;
public AutoCloseInputStream(AssetFileDescriptor fd) throws IOException {
super(fd.getParcelFileDescriptor());
- // this skip is necessary if getChannel() is called
super.skip(fd.getStartOffset());
- mSizeFromStartOffset = fd.getLength();
- mStartOffset = fd.getStartOffset();
+ mRemaining = (int) fd.getLength();
}
@Override
public int available() throws IOException {
- long available = mSizeFromStartOffset - mPosFromStartOffset;
- return available >= 0
- ? (available < 0x7fffffff ? (int) available : 0x7fffffff)
- : 0;
+ return mRemaining >= 0
+ ? (mRemaining < 0x7fffffff ? (int) mRemaining : 0x7fffffff)
+ : super.available();
}
@Override
@@ -234,24 +227,15 @@
@Override
public int read(byte[] buffer, int offset, int count) throws IOException {
- int available = available();
-
- if (available <= 0) {
- return -1;
- } else {
- if (count > available) count = available;
- try {
- int res = Os.pread(getFD(), buffer, offset, count,
- mStartOffset + mPosFromStartOffset);
- // pread returns 0 at end of file, while java's InputStream interface
- // requires -1
- if (res == 0) res = -1;
- if (res >= 0) mPosFromStartOffset += res;
- return res;
- } catch (ErrnoException e) {
- throw new IOException(e);
- }
+ if (mRemaining >= 0) {
+ if (mRemaining == 0) return -1;
+ if (count > mRemaining) count = (int) mRemaining;
+ int res = super.read(buffer, offset, count);
+ if (res >= 0) mRemaining -= res;
+ return res;
}
+
+ return super.read(buffer, offset, count);
}
@Override
@@ -261,31 +245,41 @@
@Override
public long skip(long count) throws IOException {
- int available = available();
- if (available <= 0) {
- return -1;
- } else {
- if (count > available) count = available;
- mPosFromStartOffset += count;
- return count;
+ if (mRemaining >= 0) {
+ if (mRemaining == 0) return -1;
+ if (count > mRemaining) count = mRemaining;
+ long res = super.skip(count);
+ if (res >= 0) mRemaining -= res;
+ return res;
}
+
+ return super.skip(count);
}
@Override
public void mark(int readlimit) {
- // Not supported.
- return;
+ if (mRemaining >= 0) {
+ // Not supported.
+ return;
+ }
+ super.mark(readlimit);
}
@Override
public boolean markSupported() {
- return false;
+ if (mRemaining >= 0) {
+ return false;
+ }
+ return super.markSupported();
}
@Override
public synchronized void reset() throws IOException {
- // Not supported.
- return;
+ if (mRemaining >= 0) {
+ // Not supported.
+ return;
+ }
+ super.reset();
}
}
@@ -381,7 +375,6 @@
public AssetFileDescriptor createFromParcel(Parcel in) {
return new AssetFileDescriptor(in);
}
-
public AssetFileDescriptor[] newArray(int size) {
return new AssetFileDescriptor[size];
}
diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java
index 0d3aaf5..10c3730 100644
--- a/core/java/android/hardware/Sensor.java
+++ b/core/java/android/hardware/Sensor.java
@@ -712,14 +712,16 @@
public static final String STRING_TYPE_HINGE_ANGLE = "android.sensor.hinge_angle";
/**
- * A constant describing a head tracker sensor.
+ * A constant describing a head tracker sensor. Note that this sensor type is typically not
+ * available for apps to use.
*
* See {@link android.hardware.SensorEvent#values SensorEvent.values} for more details.
*/
public static final int TYPE_HEAD_TRACKER = 37;
/**
- * A constant string describing a head tracker sensor.
+ * A constant string describing a head tracker sensor. Note that this sensor type is typically
+ * not available for apps to use.
*
* See {@link android.hardware.SensorEvent#values SensorEvent.values} for more details.
*/
diff --git a/core/java/android/hardware/camera2/CameraCaptureSession.java b/core/java/android/hardware/camera2/CameraCaptureSession.java
index 5dbe9bf..5b1973a 100644
--- a/core/java/android/hardware/camera2/CameraCaptureSession.java
+++ b/core/java/android/hardware/camera2/CameraCaptureSession.java
@@ -1241,8 +1241,9 @@
* {@link #onCaptureStarted}. Unlike {@link #onCaptureStarted}, instead of passing
* a timestamp of start of exposure, this callback passes a timestamp of start of
* camera data readout. This is useful because for a camera running at fixed frame
- * rate, the start of readout is at fixed interval, but not necessary for the start
- * of exposure.</p>
+ * rate, the start of readout is at fixed interval, which is not necessarily true for
+ * the start of exposure, particularly when autoexposure is changing exposure duration
+ * between frames.</p>
*
* <p>This timestamp may not match {@link CaptureResult#SENSOR_TIMESTAMP the result
* timestamp field}. It will, however, match the timestamp of buffers sent to the
diff --git a/core/java/android/hardware/camera2/params/OutputConfiguration.java b/core/java/android/hardware/camera2/params/OutputConfiguration.java
index 204e6b6..9e87037 100644
--- a/core/java/android/hardware/camera2/params/OutputConfiguration.java
+++ b/core/java/android/hardware/camera2/params/OutputConfiguration.java
@@ -166,7 +166,16 @@
* {@link #TIMESTAMP_BASE_MONOTONIC}, which is roughly the same time base as
* {@link android.os.SystemClock#uptimeMillis}.</li>
* <li> For all other cases, the timestamp base is {@link #TIMESTAMP_BASE_SENSOR}, the same
- * as what's specified by {@link CameraCharacteristics#SENSOR_INFO_TIMESTAMP_SOURCE}.</li>
+ * as what's specified by {@link CameraCharacteristics#SENSOR_INFO_TIMESTAMP_SOURCE}.
+ * <ul><li> For a SurfaceTexture output surface, the camera system re-spaces the delivery
+ * of output frames based on image readout intervals, reducing viewfinder jitter. The timestamps
+ * of images remain to be {@link #TIMESTAMP_BASE_SENSOR}.</li></ul></li>
+ *
+ * <p>Note that the reduction of frame jitter for SurfaceView and SurfaceTexture comes with
+ * slight increase in photon-to-photon latency, which is the time from when photons hit the
+ * scene to when the corresponding pixels show up on the screen. If the photon-to-photon latency
+ * is more important than the smoothness of viewfinder, {@link #TIMESTAMP_BASE_SENSOR} should be
+ * used instead.</p>
*
* @see #TIMESTAMP_BASE_CHOREOGRAPHER_SYNCED
* @see #TIMESTAMP_BASE_MONOTONIC
diff --git a/core/java/android/hardware/display/AmbientDisplayConfiguration.java b/core/java/android/hardware/display/AmbientDisplayConfiguration.java
index 7d8f2ff..8c71b36 100644
--- a/core/java/android/hardware/display/AmbientDisplayConfiguration.java
+++ b/core/java/android/hardware/display/AmbientDisplayConfiguration.java
@@ -89,7 +89,8 @@
/** @hide */
public boolean pulseOnNotificationAvailable() {
- return ambientDisplayAvailable();
+ return mContext.getResources().getBoolean(R.bool.config_pulseOnNotificationsAvailable)
+ && ambientDisplayAvailable();
}
/** @hide */
diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java
index 06edf66..7092e43 100644
--- a/core/java/android/hardware/face/FaceManager.java
+++ b/core/java/android/hardware/face/FaceManager.java
@@ -1369,13 +1369,17 @@
case FACE_ACQUIRED_TOO_FAR:
return context.getString(R.string.face_acquired_too_far);
case FACE_ACQUIRED_TOO_HIGH:
- return context.getString(R.string.face_acquired_too_high);
- case FACE_ACQUIRED_TOO_LOW:
+ // TODO(b/181269243) Change back once error codes are fixed.
return context.getString(R.string.face_acquired_too_low);
+ case FACE_ACQUIRED_TOO_LOW:
+ // TODO(b/181269243) Change back once error codes are fixed.
+ return context.getString(R.string.face_acquired_too_high);
case FACE_ACQUIRED_TOO_RIGHT:
- return context.getString(R.string.face_acquired_too_right);
- case FACE_ACQUIRED_TOO_LEFT:
+ // TODO(b/181269243) Change back once error codes are fixed.
return context.getString(R.string.face_acquired_too_left);
+ case FACE_ACQUIRED_TOO_LEFT:
+ // TODO(b/181269243) Change back once error codes are fixed.
+ return context.getString(R.string.face_acquired_too_right);
case FACE_ACQUIRED_POOR_GAZE:
return context.getString(R.string.face_acquired_poor_gaze);
case FACE_ACQUIRED_PAN_TOO_EXTREME:
diff --git a/core/java/android/hardware/input/TEST_MAPPING b/core/java/android/hardware/input/TEST_MAPPING
new file mode 100644
index 0000000..9626d8d
--- /dev/null
+++ b/core/java/android/hardware/input/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "imports": [
+ {
+ "path": "frameworks/native/services/inputflinger"
+ }
+ ]
+}
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 0ecb866..95ba669 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -593,7 +593,7 @@
private InlineSuggestionSessionController mInlineSuggestionSessionController;
- private boolean mAutomotiveHideNavBarForKeyboard;
+ private boolean mHideNavBarForKeyboard;
private boolean mIsAutomotive;
private @NonNull OptionalInt mHandwritingRequestId = OptionalInt.empty();
private InputEventReceiver mHandwritingEventReceiver;
@@ -1499,9 +1499,8 @@
// shown the first time (cold start).
mSettingsObserver.shouldShowImeWithHardKeyboard();
- mIsAutomotive = isAutomotive();
- mAutomotiveHideNavBarForKeyboard = getApplicationContext().getResources().getBoolean(
- com.android.internal.R.bool.config_automotiveHideNavBarForKeyboard);
+ mHideNavBarForKeyboard = getApplicationContext().getResources().getBoolean(
+ com.android.internal.R.bool.config_hideNavBarForKeyboard);
// TODO(b/111364446) Need to address context lifecycle issue if need to re-create
// for update resources & configuration correctly when show soft input
@@ -1540,11 +1539,11 @@
window.setFlags(windowFlags, windowFlagsMask);
// Automotive devices may request the navigation bar to be hidden when the IME shows up
- // (controlled via config_automotiveHideNavBarForKeyboard) in order to maximize the
- // visible screen real estate. When this happens, the IME window should animate from the
+ // (controlled via config_hideNavBarForKeyboard) in order to maximize the visible
+ // screen real estate. When this happens, the IME window should animate from the
// bottom of the screen to reduce the jank that happens from the lack of synchronization
// between the bottom system window and the IME window.
- if (mIsAutomotive && mAutomotiveHideNavBarForKeyboard) {
+ if (mHideNavBarForKeyboard) {
window.setDecorFitsSystemWindows(false);
}
}
@@ -1626,7 +1625,6 @@
// when IME developers are doing something unsupported.
InputMethodPrivilegedOperationsRegistry.remove(mToken);
}
- unregisterCompatOnBackInvokedCallback();
mImeDispatcher = null;
}
@@ -2789,6 +2787,11 @@
if (mInkWindow != null) {
finishStylusHandwriting();
}
+ // Back callback is typically unregistered in {@link #hideWindow()}, but it's possible
+ // for {@link #doFinishInput()} to be called without {@link #hideWindow()} so we also
+ // unregister here.
+ // TODO(b/232341407): Add CTS to verify back behavior after screen on / off.
+ unregisterCompatOnBackInvokedCallback();
}
void doStartInput(InputConnection ic, EditorInfo attribute, boolean restarting) {
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index 022d213..5177cb4 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -478,8 +478,15 @@
}
/** {@hide} */
- public static File getDataMiscCeSharedSdkSandboxDirectory(int userId, String packageName) {
- return buildPath(getDataMiscCeDirectory(userId), "sdksandbox", packageName, "shared");
+ private static File getDataMiscCeDirectory(String volumeUuid, int userId) {
+ return buildPath(getDataDirectory(volumeUuid), "misc_ce", String.valueOf(userId));
+ }
+
+ /** {@hide} */
+ public static File getDataMiscCeSharedSdkSandboxDirectory(String volumeUuid, int userId,
+ String packageName) {
+ return buildPath(getDataMiscCeDirectory(volumeUuid, userId), "sdksandbox",
+ packageName, "shared");
}
/** {@hide} */
@@ -488,8 +495,15 @@
}
/** {@hide} */
- public static File getDataMiscDeSharedSdkSandboxDirectory(int userId, String packageName) {
- return buildPath(getDataMiscDeDirectory(userId), "sdksandbox", packageName, "shared");
+ private static File getDataMiscDeDirectory(String volumeUuid, int userId) {
+ return buildPath(getDataDirectory(volumeUuid), "misc_de", String.valueOf(userId));
+ }
+
+ /** {@hide} */
+ public static File getDataMiscDeSharedSdkSandboxDirectory(String volumeUuid, int userId,
+ String packageName) {
+ return buildPath(getDataMiscDeDirectory(volumeUuid, userId), "sdksandbox",
+ packageName, "shared");
}
private static File getDataProfilesDeDirectory(int userId) {
diff --git a/core/java/android/os/IBinder.java b/core/java/android/os/IBinder.java
index 9e47a70..90e4b17 100644
--- a/core/java/android/os/IBinder.java
+++ b/core/java/android/os/IBinder.java
@@ -311,9 +311,11 @@
public void binderDied();
/**
- * @hide
+ * Interface for receiving a callback when the process hosting an IBinder
+ * has gone away.
+ * @param who The IBinder that has become invalid
*/
- default void binderDied(IBinder who) {
+ default void binderDied(@NonNull IBinder who) {
binderDied();
}
}
diff --git a/core/java/android/permission/PermissionControllerManager.java b/core/java/android/permission/PermissionControllerManager.java
index 3c2c7f0..b494c7f 100644
--- a/core/java/android/permission/PermissionControllerManager.java
+++ b/core/java/android/permission/PermissionControllerManager.java
@@ -860,7 +860,7 @@
Binder.restoreCallingIdentity(token);
}
}
- });
+ }, executor);
}
/**
diff --git a/core/java/android/permission/PermissionUsageHelper.java b/core/java/android/permission/PermissionUsageHelper.java
index 4ed939c..f5f1c37 100644
--- a/core/java/android/permission/PermissionUsageHelper.java
+++ b/core/java/android/permission/PermissionUsageHelper.java
@@ -30,6 +30,7 @@
import static android.app.AppOpsManager.OPSTR_FINE_LOCATION;
import static android.app.AppOpsManager.OPSTR_PHONE_CALL_CAMERA;
import static android.app.AppOpsManager.OPSTR_PHONE_CALL_MICROPHONE;
+import static android.app.AppOpsManager.OPSTR_RECEIVE_AMBIENT_TRIGGER_AUDIO;
import static android.app.AppOpsManager.OPSTR_RECORD_AUDIO;
import static android.app.AppOpsManager.OP_CAMERA;
import static android.app.AppOpsManager.OP_FLAGS_ALL_TRUSTED;
@@ -137,6 +138,7 @@
private static final List<String> MIC_OPS = List.of(
OPSTR_PHONE_CALL_MICROPHONE,
+ OPSTR_RECEIVE_AMBIENT_TRIGGER_AUDIO,
OPSTR_RECORD_AUDIO
);
@@ -147,6 +149,7 @@
private static @NonNull String getGroupForOp(String op) {
switch (op) {
+ case OPSTR_RECEIVE_AMBIENT_TRIGGER_AUDIO:
case OPSTR_RECORD_AUDIO:
return MICROPHONE;
case OPSTR_CAMERA:
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index 442723f..d403030 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -614,6 +614,14 @@
public static final String NAMESPACE_VOICE_INTERACTION = "voice_interaction";
/**
+ * Namespace for DevicePolicyManager related features.
+ *
+ * @hide
+ */
+ public static final String NAMESPACE_DEVICE_POLICY_MANAGER =
+ "device_policy_manager";
+
+ /**
* List of namespaces which can be read without READ_DEVICE_CONFIG permission
*
* @hide
@@ -621,7 +629,8 @@
@NonNull
private static final List<String> PUBLIC_NAMESPACES =
Arrays.asList(NAMESPACE_TEXTCLASSIFIER, NAMESPACE_RUNTIME, NAMESPACE_STATSD_JAVA,
- NAMESPACE_STATSD_JAVA_BOOT, NAMESPACE_SELECTION_TOOLBAR, NAMESPACE_AUTOFILL);
+ NAMESPACE_STATSD_JAVA_BOOT, NAMESPACE_SELECTION_TOOLBAR, NAMESPACE_AUTOFILL,
+ NAMESPACE_DEVICE_POLICY_MANAGER);
/**
* Privacy related properties definitions.
*
@@ -745,14 +754,6 @@
*/
public static final String NAMESPACE_VENDOR_SYSTEM_NATIVE = "vendor_system_native";
- /**
- * Namespace for DevicePolicyManager related features.
- *
- * @hide
- */
- public static final String NAMESPACE_DEVICE_POLICY_MANAGER =
- "device_policy_manager";
-
private static final Object sLock = new Object();
@GuardedBy("sLock")
private static ArrayMap<OnPropertiesChangedListener, Pair<String, Executor>> sListeners =
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 4be82fc..9741d34 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -14521,6 +14521,18 @@
public static final String ANGLE_EGL_FEATURES = "angle_egl_features";
/**
+ * Comma-separated list of package names that ANGLE may have issues with
+ * @hide
+ */
+ public static final String ANGLE_DEFERLIST = "angle_deferlist";
+
+ /**
+ * Integer mode of the logic for applying `angle_deferlist`
+ * @hide
+ */
+ public static final String ANGLE_DEFERLIST_MODE = "angle_deferlist_mode";
+
+ /**
* Show the "ANGLE In Use" dialog box to the user when ANGLE is the OpenGL driver.
* The value is a boolean (1 or 0).
* @hide
diff --git a/core/java/android/service/voice/AbstractHotwordDetector.java b/core/java/android/service/voice/AbstractHotwordDetector.java
index 5b3b78b..84d6711 100644
--- a/core/java/android/service/voice/AbstractHotwordDetector.java
+++ b/core/java/android/service/voice/AbstractHotwordDetector.java
@@ -204,5 +204,14 @@
.setHotwordDetectedResult(hotwordDetectedResult)
.build()));
}
+
+ /** Called when the detection fails due to an error. */
+ @Override
+ public void onError() {
+ Slog.v(TAG, "BinderCallback#onError");
+ mHandler.sendMessage(obtainMessage(
+ HotwordDetector.Callback::onError,
+ mCallback));
+ }
}
}
diff --git a/core/java/android/service/voice/IMicrophoneHotwordDetectionVoiceInteractionCallback.aidl b/core/java/android/service/voice/IMicrophoneHotwordDetectionVoiceInteractionCallback.aidl
index 80f20fe..e865089 100644
--- a/core/java/android/service/voice/IMicrophoneHotwordDetectionVoiceInteractionCallback.aidl
+++ b/core/java/android/service/voice/IMicrophoneHotwordDetectionVoiceInteractionCallback.aidl
@@ -33,4 +33,9 @@
in HotwordDetectedResult hotwordDetectedResult,
in AudioFormat audioFormat,
in ParcelFileDescriptor audioStream);
+
+ /**
+ * Called when the detection fails due to an error.
+ */
+ void onError();
}
diff --git a/core/java/android/service/voice/SoftwareHotwordDetector.java b/core/java/android/service/voice/SoftwareHotwordDetector.java
index 36ea91e..6600fb7 100644
--- a/core/java/android/service/voice/SoftwareHotwordDetector.java
+++ b/core/java/android/service/voice/SoftwareHotwordDetector.java
@@ -166,6 +166,15 @@
.setHotwordDetectedResult(hotwordDetectedResult)
.build()));
}
+
+ /** Called when the detection fails due to an error. */
+ @Override
+ public void onError() {
+ Slog.v(TAG, "BinderCallback#onError");
+ mHandler.sendMessage(obtainMessage(
+ HotwordDetector.Callback::onError,
+ mCallback));
+ }
}
private static class InitializationStateListener
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 0ec95c6..1e22856 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -27,6 +27,7 @@
import static android.view.ViewRootImpl.LOCAL_LAYOUT;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
+import android.animation.AnimationHandler;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
@@ -888,7 +889,6 @@
if (mShouldDimByDefault != mShouldDim && mWallpaperDimAmount == 0f) {
mShouldDim = mShouldDimByDefault;
updateSurfaceDimming();
- updateSurface(false, false, true);
}
}
@@ -898,6 +898,10 @@
* @param dimAmount Float amount between [0.0, 1.0] to dim the wallpaper.
*/
private void updateWallpaperDimming(float dimAmount) {
+ if (dimAmount == mWallpaperDimAmount) {
+ return;
+ }
+
// Custom dim amount cannot be less than the default dim amount.
mWallpaperDimAmount = Math.max(mDefaultDimAmount, dimAmount);
// If dim amount is 0f (additional dimming is removed), then the wallpaper should dim
@@ -1195,7 +1199,6 @@
.setParent(mSurfaceControl)
.setCallsite("Wallpaper#relayout")
.build();
- updateSurfaceDimming();
}
// Propagate transform hint from WM, so we can use the right hint for the
// first frame.
@@ -1366,7 +1369,6 @@
mSession.finishDrawing(mWindow, null /* postDrawTransaction */,
Integer.MAX_VALUE);
processLocalColors(mPendingXOffset, mPendingXOffsetStep);
- notifyColorsChanged();
}
reposition();
reportEngineShown(shouldWaitForEngineShown());
@@ -1515,6 +1517,8 @@
mVisible = visible;
reportVisibility();
if (mReportedVisible) processLocalColors(mPendingXOffset, mPendingXOffsetStep);
+ } else {
+ AnimationHandler.requestAnimatorsEnabled(visible, this);
}
}
@@ -1543,6 +1547,7 @@
if (DEBUG) Log.v(TAG, "Freezing wallpaper after visibility update");
freeze();
}
+ AnimationHandler.requestAnimatorsEnabled(visible, this);
}
}
}
@@ -2071,6 +2076,8 @@
return;
}
+ AnimationHandler.removeRequestor(this);
+
mDestroyed = true;
if (mIWallpaperEngine.mDisplayManager != null) {
diff --git a/core/java/android/speech/RecognitionService.java b/core/java/android/speech/RecognitionService.java
index 6a65efb..6b59f54 100644
--- a/core/java/android/speech/RecognitionService.java
+++ b/core/java/android/speech/RecognitionService.java
@@ -129,8 +129,9 @@
@NonNull AttributionSource attributionSource) {
try {
if (mCurrentCallback == null) {
- boolean preflightPermissionCheckPassed = checkPermissionForPreflightNotHardDenied(
- attributionSource);
+ boolean preflightPermissionCheckPassed =
+ intent.hasExtra(RecognizerIntent.EXTRA_AUDIO_SOURCE)
+ || checkPermissionForPreflightNotHardDenied(attributionSource);
if (preflightPermissionCheckPassed) {
if (DBG) {
Log.d(TAG, "created new mCurrentCallback, listener = "
diff --git a/core/java/android/view/IDisplayWindowRotationCallback.aidl b/core/java/android/view/IDisplayChangeWindowCallback.aidl
similarity index 77%
rename from core/java/android/view/IDisplayWindowRotationCallback.aidl
rename to core/java/android/view/IDisplayChangeWindowCallback.aidl
index 1ffe2dd..00a5b7b 100644
--- a/core/java/android/view/IDisplayWindowRotationCallback.aidl
+++ b/core/java/android/view/IDisplayChangeWindowCallback.aidl
@@ -17,13 +17,15 @@
package android.view;
import android.window.WindowContainerTransaction;
+import android.window.DisplayAreaInfo;
/**
- * Interface to be invoked by the controller when it has finished preparing for a display rotation.
+ * Interface to be invoked by the controller when it has finished preparing for a display
+ * size change.
*
- * @see IDisplayWindowRotationController
+ * @see IDisplayChangeWindowController
* @hide
*/
-interface IDisplayWindowRotationCallback {
- void continueRotateDisplay(int targetRotation, in WindowContainerTransaction t);
+interface IDisplayChangeWindowCallback {
+ void continueDisplayChange(in WindowContainerTransaction t);
}
diff --git a/core/java/android/view/IDisplayWindowRotationController.aidl b/core/java/android/view/IDisplayChangeWindowController.aidl
similarity index 66%
rename from core/java/android/view/IDisplayWindowRotationController.aidl
rename to core/java/android/view/IDisplayChangeWindowController.aidl
index c1c7464..8c0bb6a 100644
--- a/core/java/android/view/IDisplayWindowRotationController.aidl
+++ b/core/java/android/view/IDisplayChangeWindowController.aidl
@@ -16,11 +16,12 @@
package android.view;
-import android.view.IDisplayWindowRotationCallback;
+import android.view.IDisplayChangeWindowCallback;
+import android.window.DisplayAreaInfo;
/**
- * Singular controller of a "remote" display rotation. When a display rotation is started, WM
- * freezes the screen. It will then call into this controller and wait for a response via the
+ * Singular controller of a "remote" display change. When a display rotation or change is started,
+ * WM freezes the screen. It will then call into this controller and wait for a response via the
* callback.
*
* This needs to provide configuration changes because those changes need to be applied in sync
@@ -36,17 +37,18 @@
*
* @hide
*/
-oneway interface IDisplayWindowRotationController {
+oneway interface IDisplayChangeWindowController {
/**
- * Called when WM needs to know how to update tasks in response to a display rotation.
- * If this isn't called, a timeout will continue the rotation in WM.
+ * Called when WM needs to know how to update tasks in response to a display change.
+ * If this isn't called, a timeout will continue the change in WM.
*
- * @param displayId the display that is rotating.
- * @param fromRotation the rotation the display is rotating from.
- * @param toRotation the rotation the display is rotating to.
+ * @param fromRotation the old rotation
+ * @param newRotation the new rotation
+ * @param newDisplayAreaInfo the new display area info after the change
* @param callback A callback to be called when this has calculated updated configs.
*/
- void onRotateDisplay(int displayId, int fromRotation, int toRotation,
- in IDisplayWindowRotationCallback callback);
+ void onDisplayChange(int displayId, int fromRotation, int toRotation,
+ in DisplayAreaInfo newDisplayAreaInfo, in IDisplayChangeWindowCallback callback);
+
}
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index ee49d7bf..ebdb79c 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -40,7 +40,7 @@
import android.view.IDisplayWindowInsetsController;
import android.view.IDisplayWindowListener;
import android.view.IDisplayFoldListener;
-import android.view.IDisplayWindowRotationController;
+import android.view.IDisplayChangeWindowController;
import android.view.IOnKeyguardExitResult;
import android.view.IPinnedTaskListener;
import android.view.IScrollCaptureResponseListener;
@@ -146,7 +146,7 @@
* controller is called after the display has "frozen" for a rotation and display rotation will
* only continue once the controller has finished calculating associated configurations.
*/
- void setDisplayWindowRotationController(IDisplayWindowRotationController controller);
+ void setDisplayChangeWindowController(IDisplayChangeWindowController controller);
/**
* Adds a root container that a client shell can populate with its own windows (usually via
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index e5ec260..691452f 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -341,10 +341,12 @@
*/
@UnsupportedAppUsage
public void destroy() {
- if (mNativeObject != 0) {
- nativeDestroy(mNativeObject);
+ synchronized (mLock) {
+ if (mNativeObject != 0) {
+ nativeDestroy(mNativeObject);
+ }
+ release();
}
- release();
}
/**
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 86672d6..387b547 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -11973,7 +11973,7 @@
@NonNull
public final List<Rect> getUnrestrictedPreferKeepClearRects() {
final ListenerInfo info = mListenerInfo;
- if (info != null && info.mKeepClearRects != null) {
+ if (info != null && info.mUnrestrictedKeepClearRects != null) {
return new ArrayList(info.mUnrestrictedKeepClearRects);
}
@@ -21281,6 +21281,11 @@
}
AccessibilityNodeIdManager.getInstance().unregisterViewWithId(getAccessibilityViewId());
+
+ if (mBackgroundRenderNode != null) {
+ mBackgroundRenderNode.forceEndAnimators();
+ }
+ mRenderNode.forceEndAnimators();
}
private void cleanupDraw() {
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 2bdc581..d705a3d 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -90,6 +90,7 @@
import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.INSETS_CONTROLLER;
import android.Manifest;
+import android.animation.AnimationHandler;
import android.animation.LayoutTransition;
import android.annotation.AnyThread;
import android.annotation.NonNull;
@@ -1369,6 +1370,8 @@
mFirstInputStage = nativePreImeStage;
mFirstPostImeInputStage = earlyPostImeStage;
mPendingInputEventQueueLengthCounterName = "aq:pending:" + counterSuffix;
+
+ AnimationHandler.requestAnimatorsEnabled(mAppVisible, this);
}
}
}
@@ -1714,6 +1717,7 @@
if (!mAppVisible) {
WindowManagerGlobal.trimForeground();
}
+ AnimationHandler.requestAnimatorsEnabled(mAppVisible, this);
}
}
@@ -1773,7 +1777,7 @@
}
}
- mForceNextWindowRelayout = forceNextWindowRelayout;
+ mForceNextWindowRelayout |= forceNextWindowRelayout;
mPendingAlwaysConsumeSystemBars = args.argi2 != 0;
mSyncSeqId = args.argi4 > mSyncSeqId ? args.argi4 : mSyncSeqId;
@@ -5234,6 +5238,9 @@
// the buffers may still have content in previous rotation. And the next draw may
// not update all regions, that causes some afterimages to flicker.
mUpdateSurfaceNeeded = true;
+ if (!mIsInTraversal) {
+ mForceNextWindowRelayout = true;
+ }
}
Configuration globalConfig = mergedConfiguration.getGlobalConfiguration();
@@ -8501,6 +8508,7 @@
mInsetsController.onControlsChanged(null);
mAdded = false;
+ AnimationHandler.removeRequestor(this);
}
WindowManagerGlobal.getInstance().doRemoveView(this);
}
diff --git a/core/java/android/window/ImeOnBackInvokedDispatcher.java b/core/java/android/window/ImeOnBackInvokedDispatcher.java
index d5763aa..8bdf233 100644
--- a/core/java/android/window/ImeOnBackInvokedDispatcher.java
+++ b/core/java/android/window/ImeOnBackInvokedDispatcher.java
@@ -158,6 +158,12 @@
/** Clears all registered callbacks on the instance. */
public void clear() {
+ // Unregister previously registered callbacks if there's any.
+ if (getReceivingDispatcher() != null) {
+ for (OnBackInvokedCallback callback : mImeCallbackMap.values()) {
+ getReceivingDispatcher().unregisterOnBackInvokedCallback(callback);
+ }
+ }
mImeCallbackMap.clear();
}
diff --git a/core/java/android/window/TransitionInfo.java b/core/java/android/window/TransitionInfo.java
index 51da61f..c81184f 100644
--- a/core/java/android/window/TransitionInfo.java
+++ b/core/java/android/window/TransitionInfo.java
@@ -107,8 +107,11 @@
*/
public static final int FLAG_DISPLAY_HAS_ALERT_WINDOWS = 1 << 7;
+ /** The container is an input-method window. */
+ public static final int FLAG_IS_INPUT_METHOD = 1 << 8;
+
/** The first unused bit. This can be used by remotes to attach custom flags to this change. */
- public static final int FLAG_FIRST_CUSTOM = 1 << 8;
+ public static final int FLAG_FIRST_CUSTOM = 1 << 9;
/** @hide */
@IntDef(prefix = { "FLAG_" }, value = {
@@ -121,6 +124,7 @@
FLAG_IS_DISPLAY,
FLAG_OCCLUDES_KEYGUARD,
FLAG_DISPLAY_HAS_ALERT_WINDOWS,
+ FLAG_IS_INPUT_METHOD,
FLAG_FIRST_CUSTOM
})
public @interface ChangeFlags {}
@@ -300,6 +304,9 @@
if ((flags & FLAG_IS_WALLPAPER) != 0) {
sb.append("IS_WALLPAPER");
}
+ if ((flags & FLAG_IS_INPUT_METHOD) != 0) {
+ sb.append("IS_INPUT_METHOD");
+ }
if ((flags & FLAG_TRANSLUCENT) != 0) {
sb.append((sb.length() == 0 ? "" : "|") + "TRANSLUCENT");
}
diff --git a/core/java/com/android/internal/app/AppLocaleStore.java b/core/java/com/android/internal/app/AppLocaleStore.java
index 599e6d2..f3a322c 100644
--- a/core/java/com/android/internal/app/AppLocaleStore.java
+++ b/core/java/com/android/internal/app/AppLocaleStore.java
@@ -20,12 +20,15 @@
import android.app.LocaleConfig;
import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.InstallSourceInfo;
import android.content.pm.PackageManager;
import android.os.LocaleList;
import android.util.Log;
-import java.util.ArrayList;
+import java.util.HashSet;
import java.util.Locale;
+import java.util.stream.Collectors;
class AppLocaleStore {
private static final String TAG = AppLocaleStore.class.getSimpleName();
@@ -34,7 +37,8 @@
Context context, String packageName) {
LocaleConfig localeConfig = null;
AppLocaleResult.LocaleStatus localeStatus = LocaleStatus.UNKNOWN_FAILURE;
- ArrayList<Locale> appSupportedLocales = new ArrayList<>();
+ HashSet<Locale> appSupportedLocales = new HashSet<>();
+ HashSet<Locale> assetLocale = getAssetLocales(context, packageName);
try {
localeConfig = new LocaleConfig(context.createPackageContext(packageName, 0));
@@ -45,32 +49,43 @@
if (localeConfig != null) {
if (localeConfig.getStatus() == LocaleConfig.STATUS_SUCCESS) {
LocaleList packageLocaleList = localeConfig.getSupportedLocales();
- if (packageLocaleList.size() > 0) {
+ boolean shouldFilterNotMatchingLocale = !hasInstallerInfo(context, packageName) &&
+ isSystemApp(context, packageName);
+
+ Log.d(TAG, "filterNonMatchingLocale. " +
+ ", shouldFilterNotMatchingLocale: " + shouldFilterNotMatchingLocale +
+ ", assetLocale size: " + assetLocale.size() +
+ ", packageLocaleList size: " + packageLocaleList.size());
+
+ for (int i = 0; i < packageLocaleList.size(); i++) {
+ appSupportedLocales.add(packageLocaleList.get(i));
+ }
+ if (shouldFilterNotMatchingLocale) {
+ appSupportedLocales = filterNotMatchingLocale(appSupportedLocales, assetLocale);
+ }
+
+ if (appSupportedLocales.size() > 0) {
localeStatus = LocaleStatus.GET_SUPPORTED_LANGUAGE_FROM_LOCAL_CONFIG;
- for (int i = 0; i < packageLocaleList.size(); i++) {
- appSupportedLocales.add(packageLocaleList.get(i));
- }
} else {
localeStatus = LocaleStatus.NO_SUPPORTED_LANGUAGE_IN_APP;
}
} else if (localeConfig.getStatus() == LocaleConfig.STATUS_NOT_SPECIFIED) {
- String[] languages = getAssetLocales(context, packageName);
- if (languages.length > 0) {
+ if (assetLocale.size() > 0) {
localeStatus = LocaleStatus.GET_SUPPORTED_LANGUAGE_FROM_ASSET;
- for (String language : languages) {
- appSupportedLocales.add(Locale.forLanguageTag(language));
- }
+ appSupportedLocales = assetLocale;
} else {
localeStatus = LocaleStatus.ASSET_LOCALE_IS_EMPTY;
}
}
}
- Log.d(TAG, "getAppSupportedLocales(). status: " + localeStatus
+ Log.d(TAG, "getAppSupportedLocales(). package: " + packageName
+ + ", status: " + localeStatus
+ ", appSupportedLocales:" + appSupportedLocales.size());
return new AppLocaleResult(localeStatus, appSupportedLocales);
}
- private static String[] getAssetLocales(Context context, String packageName) {
+ private static HashSet<Locale> getAssetLocales(Context context, String packageName) {
+ HashSet<Locale> result = new HashSet<>();
try {
PackageManager packageManager = context.getPackageManager();
String[] locales = packageManager.getResourcesForApplication(
@@ -78,16 +93,59 @@
.applicationInfo).getAssets().getNonSystemLocales();
if (locales == null) {
Log.i(TAG, "[" + packageName + "] locales are null.");
- return new String[0];
} else if (locales.length <= 0) {
Log.i(TAG, "[" + packageName + "] locales length is 0.");
- return new String[0];
+ } else {
+ for (String language : locales) {
+ result.add(Locale.forLanguageTag(language));
+ }
}
- return locales;
} catch (PackageManager.NameNotFoundException e) {
Log.w(TAG, "Can not found the package name : " + packageName + " / " + e);
}
- return new String[0];
+ return result;
+ }
+
+ private static HashSet<Locale> filterNotMatchingLocale(
+ HashSet<Locale> appSupportedLocales, HashSet<Locale> assetLocale) {
+ return appSupportedLocales.stream()
+ .filter(locale -> matchLanguageInSet(locale, assetLocale))
+ .collect(Collectors.toCollection(HashSet::new));
+ }
+
+ private static boolean matchLanguageInSet(Locale locale, HashSet<Locale> localesSet) {
+ if (localesSet.contains(locale)) {
+ return true;
+ }
+ for (Locale l: localesSet) {
+ if(LocaleList.matchesLanguageAndScript(l, locale)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static boolean hasInstallerInfo(Context context, String packageName) {
+ InstallSourceInfo installSourceInfo;
+ try {
+ installSourceInfo = context.getPackageManager().getInstallSourceInfo(packageName);
+ return installSourceInfo != null;
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.w(TAG, "Installer info not found for: " + packageName);
+ }
+ return false;
+ }
+
+ private static boolean isSystemApp(Context context, String packageName) {
+ ApplicationInfo applicationInfo;
+ try {
+ applicationInfo = context.getPackageManager()
+ .getApplicationInfoAsUser(packageName, /* flags= */ 0, context.getUserId());
+ return applicationInfo.isSystemApp();
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.w(TAG, "Application info not found for: " + packageName);
+ }
+ return false;
}
static class AppLocaleResult {
@@ -100,9 +158,9 @@
}
LocaleStatus mLocaleStatus;
- ArrayList<Locale> mAppSupportedLocales;
+ HashSet<Locale> mAppSupportedLocales;
- public AppLocaleResult(LocaleStatus localeStatus, ArrayList<Locale> appSupportedLocales) {
+ public AppLocaleResult(LocaleStatus localeStatus, HashSet<Locale> appSupportedLocales) {
this.mLocaleStatus = localeStatus;
this.mAppSupportedLocales = appSupportedLocales;
}
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 8163f4b..315db59 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -190,6 +190,7 @@
private static final String SHORTCUT_TARGET = "shortcut_target";
private static final int APP_PREDICTION_SHARE_TARGET_QUERY_PACKAGE_LIMIT = 20;
public static final String APP_PREDICTION_INTENT_FILTER_KEY = "intent_filter";
+ private static final String SHARED_TEXT_KEY = "shared_text";
private static final String PLURALS_COUNT = "count";
private static final String PLURALS_FILE_NAME = "file_name";
@@ -1874,10 +1875,10 @@
try {
final Intent intent = getTargetIntent();
String dataString = intent.getDataString();
- if (!TextUtils.isEmpty(dataString)) {
- return new IntentFilter(intent.getAction(), dataString);
- }
if (intent.getType() == null) {
+ if (!TextUtils.isEmpty(dataString)) {
+ return new IntentFilter(intent.getAction(), dataString);
+ }
Log.e(TAG, "Failed to get target intent filter: intent data and type are null");
return null;
}
@@ -2214,6 +2215,7 @@
final IntentFilter filter = getTargetIntentFilter();
Bundle extras = new Bundle();
extras.putParcelable(APP_PREDICTION_INTENT_FILTER_KEY, filter);
+ populateTextContent(extras);
AppPredictionContext appPredictionContext = new AppPredictionContext.Builder(contextAsUser)
.setUiSurface(APP_PREDICTION_SHARE_UI_SURFACE)
.setPredictedTargetCount(APP_PREDICTION_SHARE_TARGET_QUERY_PACKAGE_LIMIT)
@@ -2232,6 +2234,12 @@
return appPredictionSession;
}
+ private void populateTextContent(Bundle extras) {
+ final Intent intent = getTargetIntent();
+ String sharedText = intent.getStringExtra(Intent.EXTRA_TEXT);
+ extras.putString(SHARED_TEXT_KEY, sharedText);
+ }
+
/**
* This will return an app predictor if it is enabled for direct share sorting
* and if one exists. Otherwise, it returns null.
diff --git a/core/java/com/android/internal/app/ChooserListAdapter.java b/core/java/com/android/internal/app/ChooserListAdapter.java
index f6445849..8dd8272 100644
--- a/core/java/com/android/internal/app/ChooserListAdapter.java
+++ b/core/java/com/android/internal/app/ChooserListAdapter.java
@@ -144,7 +144,9 @@
}
}
if (ai == null) {
- ri = packageManager.resolveActivity(ii, PackageManager.MATCH_DEFAULT_ONLY);
+ // Because of AIDL bug, resolveActivity can't accept subclasses of Intent.
+ final Intent rii = (ii.getClass() == Intent.class) ? ii : new Intent(ii);
+ ri = packageManager.resolveActivity(rii, PackageManager.MATCH_DEFAULT_ONLY);
ai = ri != null ? ri.activityInfo : null;
}
if (ai == null) {
diff --git a/core/java/com/android/internal/app/ChooserTargetActionsDialogFragment.java b/core/java/com/android/internal/app/ChooserTargetActionsDialogFragment.java
index 4f1f380..3e1b5f0 100644
--- a/core/java/com/android/internal/app/ChooserTargetActionsDialogFragment.java
+++ b/core/java/com/android/internal/app/ChooserTargetActionsDialogFragment.java
@@ -269,7 +269,7 @@
protected CharSequence getItemLabel(DisplayResolveInfo dri) {
final PackageManager pm = getContext().getPackageManager();
return getPinLabel(isPinned(dri),
- isShortcutTarget() ? "" : dri.getResolveInfo().loadLabel(pm));
+ isShortcutTarget() ? mShortcutTitle : dri.getResolveInfo().loadLabel(pm));
}
@Nullable
diff --git a/core/java/com/android/internal/app/LocalePickerWithRegion.java b/core/java/com/android/internal/app/LocalePickerWithRegion.java
index a06ba9b..965895f 100644
--- a/core/java/com/android/internal/app/LocalePickerWithRegion.java
+++ b/core/java/com/android/internal/app/LocalePickerWithRegion.java
@@ -29,13 +29,13 @@
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
+import android.view.MenuItem.OnActionExpandListener;
import android.view.View;
import android.widget.ListView;
import android.widget.SearchView;
import com.android.internal.R;
-import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Locale;
@@ -64,6 +64,7 @@
private int mTopDistance = 0;
private String mAppPackageName;
private CharSequence mTitle = null;
+ private OnActionExpandListener mOnActionExpandListener;
/**
* Other classes can register to be notified when a locale was selected.
@@ -80,8 +81,10 @@
private static LocalePickerWithRegion createCountryPicker(Context context,
LocaleSelectedListener listener, LocaleStore.LocaleInfo parent,
- boolean translatedOnly, String appPackageName) {
+ boolean translatedOnly, String appPackageName,
+ OnActionExpandListener onActionExpandListener) {
LocalePickerWithRegion localePicker = new LocalePickerWithRegion();
+ localePicker.setOnActionExpandListener(onActionExpandListener);
boolean shouldShowTheList = localePicker.setListener(context, listener, parent,
translatedOnly, appPackageName);
return shouldShowTheList ? localePicker : null;
@@ -95,8 +98,10 @@
}
public static LocalePickerWithRegion createLanguagePicker(Context context,
- LocaleSelectedListener listener, boolean translatedOnly, String appPackageName) {
+ LocaleSelectedListener listener, boolean translatedOnly, String appPackageName,
+ OnActionExpandListener onActionExpandListener) {
LocalePickerWithRegion localePicker = new LocalePickerWithRegion();
+ localePicker.setOnActionExpandListener(onActionExpandListener);
localePicker.setListener(
context, listener, /* parent */ null, translatedOnly, appPackageName);
return localePicker;
@@ -198,13 +203,20 @@
}
private Set<LocaleStore.LocaleInfo> filterTheLanguagesNotSupportedInApp(
- boolean shouldShowList, ArrayList<Locale> supportedLocales) {
+ boolean shouldShowList, HashSet<Locale> supportedLocales) {
Set<LocaleStore.LocaleInfo> filteredList = new HashSet<>();
- if (shouldShowList) {
- for(LocaleStore.LocaleInfo li: mLocaleList) {
+ if (!shouldShowList) {
+ return filteredList;
+ }
+
+ for(LocaleStore.LocaleInfo li: mLocaleList) {
+ if (supportedLocales.contains(li.getLocale())) {
+ filteredList.add(li);
+ } else {
for(Locale l: supportedLocales) {
if(LocaleList.matchesLanguageAndScript(li.getLocale(), l)) {
filteredList.add(li);
+ break;
}
}
}
@@ -310,7 +322,7 @@
} else {
LocalePickerWithRegion selector = LocalePickerWithRegion.createCountryPicker(
getContext(), mListener, locale, mTranslatedOnly /* translate only */,
- mAppPackageName);
+ mAppPackageName, mOnActionExpandListener);
if (selector != null) {
getFragmentManager().beginTransaction()
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
@@ -328,8 +340,11 @@
inflater.inflate(R.menu.language_selection_list, menu);
final MenuItem searchMenuItem = menu.findItem(R.id.locale_search_menu);
- mSearchView = (SearchView) searchMenuItem.getActionView();
+ if (!TextUtils.isEmpty(mAppPackageName) && mOnActionExpandListener != null) {
+ searchMenuItem.setOnActionExpandListener(mOnActionExpandListener);
+ }
+ mSearchView = (SearchView) searchMenuItem.getActionView();
mSearchView.setQueryHint(getText(R.string.search_language_hint));
mSearchView.setOnQueryTextListener(this);
@@ -363,4 +378,11 @@
}
return false;
}
+
+ /**
+ * Sets OnActionExpandListener to LocalePickerWithRegion to dectect action of search bar.
+ */
+ public void setOnActionExpandListener(OnActionExpandListener onActionExpandListener) {
+ mOnActionExpandListener = onActionExpandListener;
+ }
}
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index bd5a73d..7e53a5a 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -119,6 +119,11 @@
@UnsupportedAppUsage
public ResolverActivity() {
+ mIsIntentPicker = getClass().equals(ResolverActivity.class);
+ }
+
+ protected ResolverActivity(boolean isIntentPicker) {
+ mIsIntentPicker = isIntentPicker;
}
private boolean mSafeForwardingMode;
@@ -135,6 +140,8 @@
private String mReferrerPackage;
private CharSequence mTitle;
private int mDefaultTitleResId;
+ // Expected to be true if this object is ResolverActivity or is ResolverWrapperActivity.
+ private final boolean mIsIntentPicker;
// Whether or not this activity supports choosing a default handler for the intent.
@VisibleForTesting
@@ -445,10 +452,6 @@
+ (categories != null ? Arrays.toString(categories.toArray()) : ""));
}
- private boolean isIntentPicker() {
- return getClass().equals(ResolverActivity.class);
- }
-
protected AbstractMultiProfilePagerAdapter createMultiProfilePagerAdapter(
Intent[] initialIntents,
List<ResolveInfo> rList,
@@ -637,6 +640,11 @@
resetButtonBar();
+ if (shouldUseMiniResolver()) {
+ View buttonContainer = findViewById(R.id.button_bar_container);
+ buttonContainer.setPadding(0, 0, 0, mSystemWindowInsets.bottom);
+ }
+
// Need extra padding so the list can fully scroll up
if (shouldAddFooterView()) {
applyFooterView(mSystemWindowInsets.bottom);
@@ -649,7 +657,8 @@
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
mMultiProfilePagerAdapter.getActiveListAdapter().handlePackagesChanged();
- if (isIntentPicker() && shouldShowTabs() && !useLayoutWithDefault()) {
+ if (mIsIntentPicker && shouldShowTabs() && !useLayoutWithDefault()
+ && !shouldUseMiniResolver()) {
updateIntentPickerPaddings();
}
@@ -1084,7 +1093,7 @@
if (isAutolaunching()) {
return;
}
- if (isIntentPicker()) {
+ if (mIsIntentPicker) {
((ResolverMultiProfilePagerAdapter) mMultiProfilePagerAdapter)
.setUseLayoutWithDefault(useLayoutWithDefault());
}
@@ -1108,7 +1117,7 @@
protected void onListRebuilt(ResolverListAdapter listAdapter, boolean rebuildCompleted) {
final ItemClickListener listener = new ItemClickListener();
setupAdapterListView((ListView) mMultiProfilePagerAdapter.getActiveAdapterView(), listener);
- if (shouldShowTabs() && isIntentPicker()) {
+ if (shouldShowTabs() && mIsIntentPicker) {
final ResolverDrawerLayout rdl = findViewById(R.id.contentPanel);
if (rdl != null) {
rdl.setMaxCollapsedHeight(getResources()
@@ -1448,6 +1457,12 @@
return postRebuildList(rebuildCompleted);
}
+ /**
+ * Mini resolver is shown when the user is choosing between browser[s] in this profile and a
+ * single app in the other profile (see shouldUseMiniResolver()). It shows the single app icon
+ * and asks the user if they'd like to open that cross-profile app or use the in-profile
+ * browser.
+ */
private void configureMiniResolverContent() {
mLayoutId = R.layout.miniresolver;
setContentView(mLayoutId);
@@ -1456,10 +1471,14 @@
mMultiProfilePagerAdapter.getActiveListAdapter().mDisplayList.get(0);
boolean inWorkProfile = getCurrentProfile() == PROFILE_WORK;
- DisplayResolveInfo otherProfileResolveInfo =
- mMultiProfilePagerAdapter.getInactiveListAdapter().mDisplayList.get(0);
+ ResolverListAdapter inactiveAdapter = mMultiProfilePagerAdapter.getInactiveListAdapter();
+ DisplayResolveInfo otherProfileResolveInfo = inactiveAdapter.mDisplayList.get(0);
+
+ // Load the icon asynchronously
ImageView icon = findViewById(R.id.icon);
- // TODO: Set icon drawable to app icon.
+ ResolverListAdapter.LoadIconTask iconTask = inactiveAdapter.new LoadIconTask(
+ otherProfileResolveInfo, new ResolverListAdapter.ViewHolder(icon));
+ iconTask.execute();
((TextView) findViewById(R.id.open_cross_profile)).setText(
getResources().getString(
@@ -1479,12 +1498,20 @@
prepareIntentForCrossProfileLaunch(intent);
}
safelyStartActivityAsUser(otherProfileResolveInfo,
- mMultiProfilePagerAdapter.getInactiveListAdapter().mResolverListController
- .getUserHandle());
+ inactiveAdapter.mResolverListController.getUserHandle());
});
}
+ /**
+ * Mini resolver should be used when all of the following are true:
+ * 1. This is the intent picker (ResolverActivity).
+ * 2. This profile only has web browser matches.
+ * 3. The other profile has a single non-browser match.
+ */
private boolean shouldUseMiniResolver() {
+ if (!mIsIntentPicker) {
+ return false;
+ }
if (mMultiProfilePagerAdapter.getActiveListAdapter() == null
|| mMultiProfilePagerAdapter.getInactiveListAdapter() == null) {
return false;
@@ -1790,7 +1817,7 @@
void onHorizontalSwipeStateChanged(int state) {}
private void maybeHideDivider() {
- if (!isIntentPicker()) {
+ if (!mIsIntentPicker) {
return;
}
final View divider = findViewById(R.id.divider);
@@ -1807,7 +1834,7 @@
protected void onProfileTabSelected() { }
private void resetCheckedItem() {
- if (!isIntentPicker()) {
+ if (!mIsIntentPicker) {
return;
}
mLastSelected = ListView.INVALID_POSITION;
diff --git a/core/java/com/android/internal/app/procstats/ProcessStats.java b/core/java/com/android/internal/app/procstats/ProcessStats.java
index b7abe73..9fea86e 100644
--- a/core/java/com/android/internal/app/procstats/ProcessStats.java
+++ b/core/java/com/android/internal/app/procstats/ProcessStats.java
@@ -374,14 +374,12 @@
}
}
thisProc.add(otherProc);
- if (thisProc.isActive()) {
- UidState uidState = mUidStates.get(uid);
- if (uidState == null) {
- uidState = new UidState(this, uid);
- mUidStates.put(uid, uidState);
- }
- uidState.addProcess(thisProc);
+ UidState uidState = mUidStates.get(uid);
+ if (uidState == null) {
+ uidState = new UidState(this, uid);
+ mUidStates.put(uid, uidState);
}
+ uidState.addProcess(thisProc);
}
}
@@ -1185,9 +1183,7 @@
+ " " + proc);
mProcesses.put(procName, uid, proc);
- if (proc.isActive()) {
- mUidStates.get(uid).addProcess(proc);
- }
+ mUidStates.get(uid).addProcess(proc);
}
}
diff --git a/core/java/com/android/internal/appwidget/OWNERS b/core/java/com/android/internal/appwidget/OWNERS
new file mode 100644
index 0000000..0add4f6
--- /dev/null
+++ b/core/java/com/android/internal/appwidget/OWNERS
@@ -0,0 +1,2 @@
+include /core/java/android/appwidget/OWNERS
+
diff --git a/core/java/com/android/internal/jank/InteractionJankMonitor.java b/core/java/com/android/internal/jank/InteractionJankMonitor.java
index e466c88..2dcc585 100644
--- a/core/java/com/android/internal/jank/InteractionJankMonitor.java
+++ b/core/java/com/android/internal/jank/InteractionJankMonitor.java
@@ -71,8 +71,10 @@
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SUW_LOADING_TO_NEXT_FLOW;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SUW_LOADING_TO_SHOW_INFO_WITH_ACTIONS;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SUW_SHOW_FUNCTION_SCREEN_WITH_ACTIONS;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__TAKE_SCREENSHOT;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__UNFOLD_ANIM;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__USER_SWITCH;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__VOLUME_CONTROL;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__WALLPAPER_TRANSITION;
import android.annotation.IntDef;
@@ -194,6 +196,8 @@
public static final int CUJ_LOCKSCREEN_LAUNCH_CAMERA = 51; // reserved.
public static final int CUJ_SPLIT_SCREEN_RESIZE = 52;
public static final int CUJ_SETTINGS_SLIDER = 53;
+ public static final int CUJ_TAKE_SCREENSHOT = 54;
+ public static final int CUJ_VOLUME_CONTROL = 55;
private static final int NO_STATSD_LOGGING = -1;
@@ -256,6 +260,8 @@
UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_LAUNCH_CAMERA,
UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SPLIT_SCREEN_RESIZE,
UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SETTINGS_SLIDER,
+ UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__TAKE_SCREENSHOT,
+ UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__VOLUME_CONTROL,
};
private static volatile InteractionJankMonitor sInstance;
@@ -330,6 +336,8 @@
CUJ_LOCKSCREEN_LAUNCH_CAMERA,
CUJ_SPLIT_SCREEN_RESIZE,
CUJ_SETTINGS_SLIDER,
+ CUJ_TAKE_SCREENSHOT,
+ CUJ_VOLUME_CONTROL,
})
@Retention(RetentionPolicy.SOURCE)
public @interface CujType {
@@ -756,6 +764,10 @@
return "CUJ_SPLIT_SCREEN_RESIZE";
case CUJ_SETTINGS_SLIDER:
return "SETTINGS_SLIDER";
+ case CUJ_TAKE_SCREENSHOT:
+ return "TAKE_SCREENSHOT";
+ case CUJ_VOLUME_CONTROL:
+ return "VOLUME_CONTROL";
}
return "UNKNOWN";
}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index b03a8cb..6829f3d 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -644,7 +644,7 @@
/** Schedule removal of UIDs corresponding to a removed user */
Future<?> scheduleCleanupDueToRemovedUser(int userId);
/** Schedule a sync because of a process state change */
- Future<?> scheduleSyncDueToProcessStateChange(long delayMillis);
+ void scheduleSyncDueToProcessStateChange(int flags, long delayMillis);
}
public Handler mHandler;
@@ -6215,9 +6215,7 @@
long elapsedRealtimeMs, long uptimeMs) {
if (mMobileRadioPowerState != powerState) {
long realElapsedRealtimeMs;
- final boolean active =
- powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_MEDIUM
- || powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH;
+ final boolean active = isActiveRadioPowerState(powerState);
if (active) {
if (uid > 0) {
noteMobileRadioApWakeupLocked(elapsedRealtimeMs, uptimeMs, uid);
@@ -6259,6 +6257,11 @@
return false;
}
+ private static boolean isActiveRadioPowerState(int powerState) {
+ return powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_MEDIUM
+ || powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH;
+ }
+
@GuardedBy("this")
public void notePowerSaveModeLocked(boolean enabled) {
notePowerSaveModeLocked(enabled, mClock.elapsedRealtime(), mClock.uptimeMillis());
@@ -12042,7 +12045,13 @@
return;
}
- mBsi.mExternalSync.scheduleSyncDueToProcessStateChange(
+ int flags = ExternalStatsSync.UPDATE_ON_PROC_STATE_CHANGE;
+ // Skip querying for inactive radio, where power usage is probably negligible.
+ if (!BatteryStatsImpl.isActiveRadioPowerState(mBsi.mMobileRadioPowerState)) {
+ flags &= ~ExternalStatsSync.UPDATE_RADIO;
+ }
+
+ mBsi.mExternalSync.scheduleSyncDueToProcessStateChange(flags,
mBsi.mConstants.PROC_STATE_CHANGE_COLLECTION_DELAY_MS);
}
diff --git a/core/java/com/android/internal/policy/ForceShowNavBarSettingsObserver.java b/core/java/com/android/internal/policy/ForceShowNavBarSettingsObserver.java
index fc064ea..4173abf 100644
--- a/core/java/com/android/internal/policy/ForceShowNavBarSettingsObserver.java
+++ b/core/java/com/android/internal/policy/ForceShowNavBarSettingsObserver.java
@@ -16,13 +16,18 @@
package com.android.internal.policy;
+import android.annotation.NonNull;
+import android.app.ActivityManager;
import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
+import android.net.Uri;
import android.os.Handler;
import android.os.UserHandle;
import android.provider.Settings;
+import java.util.Collection;
+
/**
* A ContentObserver for listening {@link Settings.Secure#NAV_BAR_FORCE_VISIBLE} setting key.
*
@@ -59,7 +64,11 @@
}
@Override
- public void onChange(boolean selfChange) {
+ public void onChange(boolean selfChange, @NonNull Collection<Uri> uris, int flags, int userId) {
+ if (userId != ActivityManager.getCurrentUser()) {
+ return;
+ }
+
if (mOnChangeRunnable != null) {
mOnChangeRunnable.run();
}
diff --git a/core/java/com/android/internal/view/ScrollCaptureViewSupport.java b/core/java/com/android/internal/view/ScrollCaptureViewSupport.java
index f2c27a4..d842eb6 100644
--- a/core/java/com/android/internal/view/ScrollCaptureViewSupport.java
+++ b/core/java/com/android/internal/view/ScrollCaptureViewSupport.java
@@ -395,7 +395,7 @@
@SyncAndDrawResult
public int renderView(View view, Rect sourceRect) {
HardwareRenderer.FrameRenderRequest request = mRenderer.createRenderRequest();
- request.setVsyncTime(SystemClock.elapsedRealtimeNanos());
+ request.setVsyncTime(System.nanoTime());
if (updateForView(view)) {
setupLighting(view);
}
diff --git a/core/java/com/android/internal/widget/PasswordValidationError.java b/core/java/com/android/internal/widget/PasswordValidationError.java
index 41b234e..f678b13 100644
--- a/core/java/com/android/internal/widget/PasswordValidationError.java
+++ b/core/java/com/android/internal/widget/PasswordValidationError.java
@@ -24,16 +24,17 @@
public static final int WEAK_CREDENTIAL_TYPE = 1;
public static final int CONTAINS_INVALID_CHARACTERS = 2;
public static final int TOO_SHORT = 3;
- public static final int TOO_LONG = 4;
- public static final int CONTAINS_SEQUENCE = 5;
- public static final int NOT_ENOUGH_LETTERS = 6;
- public static final int NOT_ENOUGH_UPPER_CASE = 7;
- public static final int NOT_ENOUGH_LOWER_CASE = 8;
- public static final int NOT_ENOUGH_DIGITS = 9;
- public static final int NOT_ENOUGH_SYMBOLS = 10;
- public static final int NOT_ENOUGH_NON_LETTER = 11;
- public static final int NOT_ENOUGH_NON_DIGITS = 12;
- public static final int RECENTLY_USED = 13;
+ public static final int TOO_SHORT_WHEN_ALL_NUMERIC = 4;
+ public static final int TOO_LONG = 5;
+ public static final int CONTAINS_SEQUENCE = 6;
+ public static final int NOT_ENOUGH_LETTERS = 7;
+ public static final int NOT_ENOUGH_UPPER_CASE = 8;
+ public static final int NOT_ENOUGH_LOWER_CASE = 9;
+ public static final int NOT_ENOUGH_DIGITS = 10;
+ public static final int NOT_ENOUGH_SYMBOLS = 11;
+ public static final int NOT_ENOUGH_NON_LETTER = 12;
+ public static final int NOT_ENOUGH_NON_DIGITS = 13;
+ public static final int RECENTLY_USED = 14;
// WARNING: if you add a new error, make sure it is presented to the user correctly in Settings.
public final int errorCode;
@@ -61,6 +62,7 @@
case WEAK_CREDENTIAL_TYPE: return "Weak credential type";
case CONTAINS_INVALID_CHARACTERS: return "Contains an invalid character";
case TOO_SHORT: return "Password too short";
+ case TOO_SHORT_WHEN_ALL_NUMERIC: return "Password too short";
case TOO_LONG: return "Password too long";
case CONTAINS_SEQUENCE: return "Sequence too long";
case NOT_ENOUGH_LETTERS: return "Too few letters";
diff --git a/core/jni/android_net_LocalSocketImpl.cpp b/core/jni/android_net_LocalSocketImpl.cpp
index 42cf1f4..9bd0700 100644
--- a/core/jni/android_net_LocalSocketImpl.cpp
+++ b/core/jni/android_net_LocalSocketImpl.cpp
@@ -257,7 +257,7 @@
err = socket_read_all(env, object, fd, &buf, 1);
if (err < 0) {
- jniThrowIOException(env, errno);
+ // socket_read_all has already thrown
return (jint)0;
}
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index da16232..8cc591d 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -1921,6 +1921,7 @@
FocusRequest request;
request.timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
request.displayId = displayId;
+ request.windowName = "<null>";
transaction->setFocusedWindow(request);
}
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index 3c2a48a..e165b07 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -468,6 +468,10 @@
optional SettingProto updatable_driver_prerelease_opt_in_apps = 18;
optional SettingProto angle_egl_features = 19;
+ // ANGLE - List of Apps that ANGLE may have issues with
+ optional SettingProto angle_deferlist = 20;
+ // ANGLE - Integer mode of the logic for applying `angle_deferlist`
+ optional SettingProto angle_deferlist_mode = 21;
}
optional Gpu gpu = 59;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 91ed67c..5c3b9a5 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -6442,11 +6442,11 @@
<!-- @SystemApi Must be required by a safety source to send an update using the
{@link android.safetycenter.SafetyCenterManager}.
- <p>Protection level: signature|privileged
+ <p>Protection level: internal|privileged
@hide
-->
<permission android:name="android.permission.SEND_SAFETY_CENTER_UPDATE"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="internal|privileged" />
<!-- @SystemApi Allows an application to launch device manager setup screens.
<p>Not for use by third-party applications.
@@ -7045,7 +7045,7 @@
android:permission="android.permission.BIND_JOB_SERVICE">
</service>
- <service android:name="com.android.server.companion.AssociationCleanUpService"
+ <service android:name="com.android.server.companion.InactiveAssociationsRemovalService"
android:permission="android.permission.BIND_JOB_SERVICE">
</service>
diff --git a/core/res/res/anim-ldrtl/task_fragment_close_enter.xml b/core/res/res/anim-ldrtl/task_fragment_close_enter.xml
new file mode 100644
index 0000000..e5f5707
--- /dev/null
+++ b/core/res/res/anim-ldrtl/task_fragment_close_enter.xml
@@ -0,0 +1,38 @@
+<?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:shareInterpolator="false">
+
+ <alpha
+ android:fromAlpha="1.0"
+ android:toAlpha="1.0"
+ android:fillEnabled="true"
+ android:fillBefore="true"
+ android:fillAfter="true"
+ android:interpolator="@interpolator/linear"
+ android:startOffset="0"
+ android:duration="200" />
+
+ <translate
+ android:fillEnabled="true"
+ android:fillBefore="true"
+ android:fillAfter="true"
+ android:interpolator="@interpolator/fast_out_extra_slow_in"
+ android:startOffset="0"
+ android:duration="200" />
+</set>
\ No newline at end of file
diff --git a/core/res/res/anim-ldrtl/task_fragment_close_exit.xml b/core/res/res/anim-ldrtl/task_fragment_close_exit.xml
new file mode 100644
index 0000000..c5a3654
--- /dev/null
+++ b/core/res/res/anim-ldrtl/task_fragment_close_exit.xml
@@ -0,0 +1,40 @@
+<?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:shareInterpolator="false">
+
+ <alpha
+ android:fromAlpha="1.0"
+ android:toAlpha="0.0"
+ android:fillEnabled="true"
+ android:fillBefore="true"
+ android:fillAfter="true"
+ android:interpolator="@interpolator/linear"
+ android:startOffset="35"
+ android:duration="83" />
+
+ <translate
+ android:fromXDelta="0"
+ android:toXDelta="-10%"
+ android:fillEnabled="true"
+ android:fillBefore="true"
+ android:fillAfter="true"
+ android:interpolator="@interpolator/fast_out_extra_slow_in"
+ android:startOffset="0"
+ android:duration="200" />
+</set>
\ No newline at end of file
diff --git a/core/res/res/anim-ldrtl/task_fragment_open_enter.xml b/core/res/res/anim-ldrtl/task_fragment_open_enter.xml
new file mode 100644
index 0000000..b6f1af3
--- /dev/null
+++ b/core/res/res/anim-ldrtl/task_fragment_open_enter.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+/*
+** Copyright 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:shareInterpolator="false">
+
+ <alpha
+ android:fromAlpha="0"
+ android:toAlpha="1.0"
+ android:fillEnabled="true"
+ android:fillBefore="true"
+ android:fillAfter="true"
+ android:interpolator="@interpolator/linear"
+ android:startOffset="50"
+ android:duration="83" />
+
+ <translate
+ android:fromXDelta="-10%"
+ android:toXDelta="0"
+ android:fillEnabled="true"
+ android:fillBefore="true"
+ android:fillAfter="true"
+ android:interpolator="@interpolator/fast_out_extra_slow_in"
+ android:duration="450" />
+</set>
\ No newline at end of file
diff --git a/core/res/res/anim-ldrtl/task_fragment_open_exit.xml b/core/res/res/anim-ldrtl/task_fragment_open_exit.xml
new file mode 100644
index 0000000..6cea53c
--- /dev/null
+++ b/core/res/res/anim-ldrtl/task_fragment_open_exit.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+/*
+** Copyright 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:shareInterpolator="false">
+
+ <alpha
+ android:fromAlpha="1.0"
+ android:toAlpha="1.0"
+ android:fillEnabled="true"
+ android:fillBefore="true"
+ android:fillAfter="true"
+ android:interpolator="@interpolator/standard_accelerate"
+ android:startOffset="0"
+ android:duration="450" />
+
+ <translate
+ android:fillEnabled="true"
+ android:fillBefore="true"
+ android:fillAfter="true"
+ android:interpolator="@interpolator/fast_out_extra_slow_in"
+ android:duration="450" />
+</set>
\ No newline at end of file
diff --git a/core/res/res/anim/task_fragment_close_enter.xml b/core/res/res/anim/task_fragment_close_enter.xml
index c940552..cb6cdbe 100644
--- a/core/res/res/anim/task_fragment_close_enter.xml
+++ b/core/res/res/anim/task_fragment_close_enter.xml
@@ -17,16 +17,21 @@
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
- <scale
- android:fromXScale="1.1"
- android:toXScale="1"
- android:fromYScale="1.1"
- android:toYScale="1"
- android:pivotX="50%"
- android:pivotY="50%"
+ <alpha
+ android:fromAlpha="1.0"
+ android:toAlpha="1.0"
+ android:fillEnabled="true"
+ android:fillBefore="true"
+ android:fillAfter="true"
+ android:interpolator="@interpolator/linear"
+ android:startOffset="0"
+ android:duration="200" />
+
+ <translate
android:fillEnabled="true"
android:fillBefore="true"
android:fillAfter="true"
android:interpolator="@interpolator/fast_out_extra_slow_in"
- android:duration="400"/>
+ android:startOffset="0"
+ android:duration="200" />
</set>
\ No newline at end of file
diff --git a/core/res/res/anim/task_fragment_close_exit.xml b/core/res/res/anim/task_fragment_close_exit.xml
index 8998f76..84d8b7e 100644
--- a/core/res/res/anim/task_fragment_close_exit.xml
+++ b/core/res/res/anim/task_fragment_close_exit.xml
@@ -19,24 +19,21 @@
android:shareInterpolator="false"
android:zAdjustment="top">
<alpha
- android:fromAlpha="1"
+ android:fromAlpha="1.0"
android:toAlpha="0.0"
android:fillEnabled="true"
android:fillBefore="true"
android:fillAfter="true"
android:interpolator="@interpolator/linear"
- android:startOffset="33"
- android:duration="50"/>
- <scale
- android:fromXScale="1"
- android:toXScale="0.9"
- android:fromYScale="1"
- android:toYScale="0.9"
- android:pivotX="50%"
- android:pivotY="50%"
+ android:startOffset="0"
+ android:duration="83" />
+
+ <translate
+ android:fromXDelta="0"
+ android:toXDelta="10%"
android:fillEnabled="true"
android:fillBefore="true"
android:fillAfter="true"
android:interpolator="@interpolator/fast_out_extra_slow_in"
- android:duration="400"/>
+ android:duration="200" />
</set>
diff --git a/core/res/res/anim/task_fragment_open_enter.xml b/core/res/res/anim/task_fragment_open_enter.xml
index 6bc47de..aa61e6f 100644
--- a/core/res/res/anim/task_fragment_open_enter.xml
+++ b/core/res/res/anim/task_fragment_open_enter.xml
@@ -25,17 +25,13 @@
android:fillAfter="true"
android:interpolator="@interpolator/linear"
android:startOffset="50"
- android:duration="50"/>
- <scale
- android:fromXScale="0.85"
- android:toXScale="1"
- android:fromYScale="0.85"
- android:toYScale="1"
- android:pivotX="50%"
- android:pivotY="50%"
+ android:duration="83" />
+ <translate
+ android:fromXDelta="10%"
+ android:toXDelta="0"
android:fillEnabled="true"
android:fillBefore="true"
android:fillAfter="true"
android:interpolator="@interpolator/fast_out_extra_slow_in"
- android:duration="400"/>
+ android:duration="400" />
</set>
diff --git a/core/res/res/anim/task_fragment_open_exit.xml b/core/res/res/anim/task_fragment_open_exit.xml
index 160eb84..b4914d2 100644
--- a/core/res/res/anim/task_fragment_open_exit.xml
+++ b/core/res/res/anim/task_fragment_open_exit.xml
@@ -17,16 +17,20 @@
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
- <scale
- android:fromXScale="1"
- android:toXScale="1.05"
- android:fromYScale="1"
- android:toYScale="1.05"
- android:pivotX="50%"
- android:pivotY="50%"
+ <alpha
+ android:fromAlpha="1.0"
+ android:toAlpha="1.0"
+ android:fillEnabled="true"
+ android:fillBefore="true"
+ android:fillAfter="true"
+ android:interpolator="@interpolator/standard_accelerate"
+ android:startOffset="0"
+ android:duration="400" />
+
+ <translate
android:fillEnabled="true"
android:fillBefore="true"
android:fillAfter="true"
android:interpolator="@interpolator/fast_out_extra_slow_in"
- android:duration="400"/>
+ android:duration="400" />
</set>
\ No newline at end of file
diff --git a/core/res/res/layout/autofill_fill_dialog.xml b/core/res/res/layout/autofill_fill_dialog.xml
index 252f59e..0b6a201 100644
--- a/core/res/res/layout/autofill_fill_dialog.xml
+++ b/core/res/res/layout/autofill_fill_dialog.xml
@@ -50,6 +50,7 @@
android:visibility="gone" />
</LinearLayout>
+ <!-- For Authentication. -->
<LinearLayout
android:id="@+id/autofill_dialog_container"
android:layout_width="fill_parent"
@@ -58,7 +59,7 @@
android:paddingStart="@dimen/autofill_save_inner_padding"
android:paddingEnd="@dimen/autofill_save_inner_padding"
android:visibility="gone"
- style="@style/AutofillDatasetPicker" />
+ android:background="@drawable/autofill_dataset_picker_background"/>
<ListView
android:id="@+id/autofill_dialog_list"
@@ -68,8 +69,8 @@
android:drawSelectorOnTop="true"
android:clickable="true"
android:divider="?android:attr/listDivider"
- android:visibility="gone"
- style="@style/AutofillDatasetPicker" />
+ android:background="@drawable/autofill_dataset_picker_background"
+ android:visibility="gone"/>
<com.android.internal.widget.ButtonBarLayout
android:layout_width="match_parent"
diff --git a/core/res/res/layout/miniresolver.xml b/core/res/res/layout/miniresolver.xml
index 44ed6f2..85fe283 100644
--- a/core/res/res/layout/miniresolver.xml
+++ b/core/res/res/layout/miniresolver.xml
@@ -24,12 +24,11 @@
android:id="@id/contentPanel">
<RelativeLayout
- android:id="@+id/title_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alwaysShow="true"
android:elevation="@dimen/resolver_elevation"
- android:paddingTop="@dimen/resolver_small_margin"
+ android:paddingTop="24dp"
android:paddingStart="@dimen/resolver_edge_margin"
android:paddingEnd="@dimen/resolver_edge_margin"
android:paddingBottom="@dimen/resolver_title_padding_bottom"
@@ -47,8 +46,12 @@
android:id="@+id/open_cross_profile"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:paddingTop="16dp"
android:layout_below="@id/icon"
android:layout_centerHorizontal="true"
+ android:textSize="24sp"
+ android:lineHeight="32sp"
+ android:gravity="center"
android:textColor="?android:textColorPrimary"
/>
</RelativeLayout>
@@ -58,15 +61,11 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alwaysShow="true"
+ android:paddingTop="32dp"
+ android:paddingBottom="@dimen/resolver_button_bar_spacing"
android:orientation="vertical"
android:background="?attr/colorBackground"
android:layout_ignoreOffset="true">
- <View
- android:id="@+id/resolver_button_bar_divider"
- android:layout_width="match_parent"
- android:layout_height="1dp"
- android:background="?attr/colorBackground"
- android:foreground="?attr/dividerVertical" />
<RelativeLayout
style="?attr/buttonBarStyle"
android:layout_width="match_parent"
@@ -77,7 +76,6 @@
android:orientation="horizontal"
android:layoutDirection="locale"
android:measureWithLargestChild="true"
- android:paddingTop="@dimen/resolver_button_bar_spacing"
android:paddingBottom="@dimen/resolver_button_bar_spacing"
android:paddingStart="@dimen/resolver_edge_margin"
android:paddingEnd="@dimen/resolver_small_margin"
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index c49d1b4..d95478d 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -1685,7 +1685,7 @@
<string name="accessibility_shortcut_menu_item_status_off" msgid="5531598275559472393">"FRA"</string>
<string name="accessibility_enable_service_title" msgid="3931558336268541484">"Vil du give <xliff:g id="SERVICE">%1$s</xliff:g> fuld kontrol over din enhed?"</string>
<string name="accessibility_service_warning_description" msgid="291674995220940133">"Fuld kontrol er velegnet til apps, der hjælper dig med hjælpefunktioner, men ikke de fleste apps."</string>
- <string name="accessibility_service_screen_control_title" msgid="190017412626919776">"Se og styre skærm"</string>
+ <string name="accessibility_service_screen_control_title" msgid="190017412626919776">"Se og styre skærmen"</string>
<string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"Den kan læse alt indhold på skærmen og vise indhold oven på andre apps."</string>
<string name="accessibility_service_action_perform_title" msgid="779670378951658160">"Se og udføre handlinger"</string>
<string name="accessibility_service_action_perform_description" msgid="2718852014003170558">"Den kan spore dine interaktioner med en app eller en hardwaresensor og interagere med apps på dine vegne."</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index fccda03..a8860af 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -1392,7 +1392,7 @@
<string name="alert_windows_notification_channel_group_name" msgid="6063891141815714246">"Bistaratu beste aplikazioen gainean"</string>
<string name="alert_windows_notification_channel_name" msgid="3437528564303192620">"<xliff:g id="NAME">%s</xliff:g> aplikazioen gainean agertzea"</string>
<string name="alert_windows_notification_title" msgid="6331662751095228536">"Besteen gainean agertzen da <xliff:g id="NAME">%s</xliff:g>"</string>
- <string name="alert_windows_notification_message" msgid="6538171456970725333">"Ez baduzu nahi <xliff:g id="NAME">%s</xliff:g> zerbitzuak eginbide hori erabiltzea, sakatu hau ezarpenak ireki eta aukera desaktibatzeko."</string>
+ <string name="alert_windows_notification_message" msgid="6538171456970725333">"<xliff:g id="NAME">%s</xliff:g> zerbitzuak eginbide hori erabiltzea nahi ez baduzu, sakatu hau ezarpenak ireki eta aukera desaktibatzeko."</string>
<string name="alert_windows_notification_turn_off_action" msgid="7805857234839123780">"Desaktibatu"</string>
<string name="ext_media_checking_notification_title" msgid="8299199995416510094">"<xliff:g id="NAME">%s</xliff:g> egiaztatzen…"</string>
<string name="ext_media_checking_notification_message" msgid="2231566971425375542">"Edukia berrikusten"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 1de93fb..e082e32 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -1317,7 +1317,7 @@
<string name="select_character" msgid="3352797107930786979">"درج نویسه"</string>
<string name="sms_control_title" msgid="4748684259903148341">"درحال ارسال پیامکها"</string>
<string name="sms_control_message" msgid="6574313876316388239">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> درحال ارسال تعداد زیادی پیامک است. آیا اجازه میدهید این برنامه همچنان پیامک ارسال کند؟"</string>
- <string name="sms_control_yes" msgid="4858845109269524622">"مجاز است"</string>
+ <string name="sms_control_yes" msgid="4858845109269524622">"اجازه دادن"</string>
<string name="sms_control_no" msgid="4845717880040355570">"مجاز نبودن"</string>
<string name="sms_short_code_confirm_message" msgid="1385416688897538724">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> مایل است پیامی به <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b> ارسال کند."</string>
<string name="sms_short_code_details" msgid="2723725738333388351">"این مورد "<b>"شاید هزینهای"</b>" را به حساب دستگاه همراهتان بگذارد."</string>
@@ -1689,7 +1689,7 @@
<string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"میتواند همه محتوای صفحه را بخواند و آن را روی بقیه برنامهها نمایش دهد."</string>
<string name="accessibility_service_action_perform_title" msgid="779670378951658160">"مشاهده و انجام کنشها"</string>
<string name="accessibility_service_action_perform_description" msgid="2718852014003170558">"این عملکرد میتواند با برنامه یا حسگری سختافزاری تعاملاتتان را ردیابی کند و ازطرف شما با برنامهها تعامل داشته باشد."</string>
- <string name="accessibility_dialog_button_allow" msgid="2092558122987144530">"مجاز"</string>
+ <string name="accessibility_dialog_button_allow" msgid="2092558122987144530">"اجازه دادن"</string>
<string name="accessibility_dialog_button_deny" msgid="4129575637812472671">"مجاز نبودن"</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"برای استفاده از ویژگی، روی آن ضربه بزنید:"</string>
<string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"انتخاب ویژگیهای موردنظر برای استفاده با دکمه دسترسپذیری"</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index eab052c..a971242 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -2266,7 +2266,7 @@
<string name="window_magnification_prompt_title" msgid="2876703640772778215">"Novas opcións de configuración de ampliación"</string>
<string name="window_magnification_prompt_content" msgid="8159173903032344891">"Xa podes ampliar parte da pantalla"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"Activar en Configuración"</string>
- <string name="dismiss_action" msgid="1728820550388704784">"Ignorar"</string>
+ <string name="dismiss_action" msgid="1728820550388704784">"Pechar"</string>
<string name="sensor_privacy_start_use_mic_notification_content_title" msgid="2420858361276370367">"Desbloquea o micrófono do dispositivo"</string>
<string name="sensor_privacy_start_use_camera_notification_content_title" msgid="7287720213963466672">"Desbloquea a cámara do dispositivo"</string>
<string name="sensor_privacy_start_use_notification_content_text" msgid="7595608891015777346">"Para <b><xliff:g id="APP">%s</xliff:g></b> e todas as aplicacións e servizos"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index f18af9d..6074b4a 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -245,10 +245,10 @@
<string name="global_action_power_options" msgid="1185286119330160073">"Սնուցման կոճակ"</string>
<string name="global_action_restart" msgid="4678451019561687074">"Վերագործարկել"</string>
<string name="global_action_emergency" msgid="1387617624177105088">"Շտապ կանչ"</string>
- <string name="global_action_bug_report" msgid="5127867163044170003">"Վրիպակի զեկույց"</string>
+ <string name="global_action_bug_report" msgid="5127867163044170003">"Հաղորդում վրիպակի մասին"</string>
<string name="global_action_logout" msgid="6093581310002476511">"Ավարտել աշխատաշրջանը"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"Սքրինշոթ"</string>
- <string name="bugreport_title" msgid="8549990811777373050">"Հաշվետվություն վրիպակի մասին"</string>
+ <string name="bugreport_title" msgid="8549990811777373050">"Հաղորդում վրիպակի մասին"</string>
<string name="bugreport_message" msgid="5212529146119624326">"Սա տեղեկություններ կհավաքագրի ձեր սարքի առկա կարգավիճակի մասին և կուղարկի այն էլեկտրոնային նամակով: Որոշակի ժամանակ կպահանջվի վրիպակի մասին զեկուցելու պահից սկսած մինչ ուղարկելը: Խնդրում ենք փոքր-ինչ համբերատար լինել:"</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"Ինտերակտիվ զեկույց"</string>
<string name="bugreport_option_interactive_summary" msgid="8493795476325339542">"Հիմնականում օգտագործեք այս տարբերակը: Այն ձեզ թույլ է տալիս հետևել զեկույցի ստեղծման գործընթացին, խնդրի մասին լրացուցիչ տեղեկություններ մուտքագրել և սքրինշոթներ ստեղծել: Կարող է բաց թողնել քիչ օգտագործվող որոշ բաժիններ, որոնց ստեղծումը երկար է տևում:"</string>
@@ -1377,7 +1377,7 @@
<string name="usb_contaminant_not_detected_title" msgid="2651167729563264053">"USB միացքը կարող է օգտագործվել"</string>
<string name="usb_contaminant_not_detected_message" msgid="892863190942660462">"Հեռախոսում ջուր կամ աղտ չի հայտնաբերվել:"</string>
<string name="taking_remote_bugreport_notification_title" msgid="1582531382166919850">"Վրիպակի զեկույցի ստեղծում…"</string>
- <string name="share_remote_bugreport_notification_title" msgid="6708897723753334999">"Տրամադրե՞լ վրիպակի զեկույցը:"</string>
+ <string name="share_remote_bugreport_notification_title" msgid="6708897723753334999">"Կիսվե՞լ վրիպակի մասին հաղորդմամբ"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="3077385149217638550">"Վրիպակի զեկույցի տրամադրում…"</string>
<string name="share_remote_bugreport_notification_message_finished" msgid="7325635795739260135">"Այս սարքի անսարքությունների վերացման նպատակով ձեր ադմինիստրատորին անհրաժեշտ է վրիպակի հաշվետվություն: Կարող են տրամադրվել տեղեկություններ հավելվածների մասին և այլ տվյալներ։"</string>
<string name="share_remote_bugreport_action" msgid="7630880678785123682">"ՏՐԱՄԱԴՐԵԼ"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 54377f7..5ecea3f 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -1701,7 +1701,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"단축키 사용"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"색상 반전"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"색상 보정"</string>
- <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"한 손 사용 모드"</string>
+ <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"한 손 모드"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"더 어둡게"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"볼륨 키를 길게 눌렀습니다. <xliff:g id="SERVICE_NAME">%1$s</xliff:g>이(가) 사용 설정되었습니다."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"볼륨 키를 길게 눌렀습니다. <xliff:g id="SERVICE_NAME">%1$s</xliff:g>이(가) 사용 중지되었습니다."</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index bfc0234..85a58c2 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -221,7 +221,7 @@
<string name="silent_mode_silent" msgid="5079789070221150912">"Коңгуроо өчүк"</string>
<string name="silent_mode_vibrate" msgid="8821830448369552678">"Чалганда титирөө"</string>
<string name="silent_mode_ring" msgid="6039011004781526678">"Коңгуроо жандырылган"</string>
- <string name="reboot_to_update_title" msgid="2125818841916373708">"Android тутум жаңыртуусу"</string>
+ <string name="reboot_to_update_title" msgid="2125818841916373708">"Android системасын жаңыртуу"</string>
<string name="reboot_to_update_prepare" msgid="6978842143587422365">"Жаңыртууга даярдалууда…"</string>
<string name="reboot_to_update_package" msgid="4644104795527534811">"Жаңыртуу топтому иштелүүдө…"</string>
<string name="reboot_to_update_reboot" msgid="4474726009984452312">"Өчүрүлүп күйгүзүлүүдө…"</string>
@@ -1675,10 +1675,10 @@
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Ыкчам иштетесизби?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Атайын мүмкүнчүлүктөр функциясын пайдалануу үчүн ал күйгүзүлгөндө, үндү катуулатып/акырындаткан эки баскычты тең 3 секунддай коё бербей басып туруңуз."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Атайын мүмкүнчүлүктөрдүн ыкчам баскычын иштетесизби?"</string>
- <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Атайын мүмкүнчүлүктөр функциясын иштетүү үчүн үндү чоңойтуп/кичирейтүү баскычтарын бир нече секунд коё бербей басып туруңуз. Ушуну менен, түзмөгүңүз бир аз башкача иштеп калышы мүмкүн.\n\nУчурдагы функциялар:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nТандалган функцияларды өзгөртүү үчүн Жөндөөлөр > Атайын мүмкүнчүлүктөр бөлүмүнө өтүңүз."</string>
+ <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Атайын мүмкүнчүлүктөр функциясын иштетүү үчүн үндү катуулатуу/акырындатуу баскычтарын бир нече секунд коё бербей басып туруңуз. Ушуну менен, түзмөгүңүз бир аз башкача иштеп калышы мүмкүн.\n\nУчурдагы функциялар:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nТандалган функцияларды өзгөртүү үчүн Жөндөөлөр > Атайын мүмкүнчүлүктөр бөлүмүнө өтүңүз."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="2128323171922023762">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g> ыкчам баскычын иштетесизби?"</string>
- <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"<xliff:g id="SERVICE">%1$s</xliff:g> кызматын иштетүү үчүн үндү чоңойтуп/кичирейтүү баскычтарын бир нече секунд коё бербей басып туруңуз. Ушуну менен, түзмөгүңүз бир аз башкача иштеп калышы мүмкүн.\n\nБаскычтардын ушул айкалышын башка функцияга дайындоо үчүн, Жөндөөлөр > Атайын мүмкүнчүлүктөр бөлүмүнө өтүңүз."</string>
+ <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"<xliff:g id="SERVICE">%1$s</xliff:g> кызматын иштетүү үчүн үндү катуулатуу/акырындатуу баскычтарын бир нече секунд коё бербей басып туруңуз. Ушуну менен, түзмөгүңүз бир аз башкача иштеп калышы мүмкүн.\n\nБаскычтардын ушул айкалышын башка функцияга дайындоо үчүн, Жөндөөлөр > Атайын мүмкүнчүлүктөр бөлүмүнө өтүңүз."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Ооба"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"Жок"</string>
<string name="accessibility_shortcut_menu_item_status_on" msgid="6608392117189732543">"КҮЙҮК"</string>
@@ -1686,7 +1686,7 @@
<string name="accessibility_enable_service_title" msgid="3931558336268541484">"<xliff:g id="SERVICE">%1$s</xliff:g> кызматына түзмөгүңүздү толугу менен көзөмөлдөөгө уруксат бересизби?"</string>
<string name="accessibility_service_warning_description" msgid="291674995220940133">"Толук көзөмөл атайын мүмкүнчүлүктөрдү пайдаланууга керек, бирок калган көпчүлүк колдонмолорго кереги жок."</string>
<string name="accessibility_service_screen_control_title" msgid="190017412626919776">"Экранды көрүп, көзөмөлдөө"</string>
- <string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"Кызмат экрандагы нерселерди окуп, материалды башка колдонмолордун үстүнөн көрсөтөт."</string>
+ <string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"Кызмат экрандагы нерселерди окуп, аларды башка колдонмолордун үстүнөн көрсөтөт."</string>
<string name="accessibility_service_action_perform_title" msgid="779670378951658160">"Аракеттерди көрүп, аткаруу"</string>
<string name="accessibility_service_action_perform_description" msgid="2718852014003170558">"Кызмат колдонмодо жасаган аракеттериңизге же түзмөктүн сенсорлоруна көз салып, сиздин атыңыздан буйруктарды берет."</string>
<string name="accessibility_dialog_button_allow" msgid="2092558122987144530">"Уруксат берүү"</string>
diff --git a/core/res/res/values-mcc262/config.xml b/core/res/res/values-mcc262/config.xml
index 79eefb7..d234061 100644
--- a/core/res/res/values-mcc262/config.xml
+++ b/core/res/res/values-mcc262/config.xml
@@ -21,5 +21,5 @@
for different hardware and product builds. -->
<resources>
<!-- Set to false to disable emergency alert. -->
- <bool name="config_cellBroadcastAppLinks">false</bool>
+ <bool name="config_cellBroadcastAppLinks">true</bool>
</resources>
\ No newline at end of file
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index c151712..7694742 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -1686,7 +1686,7 @@
<string name="accessibility_enable_service_title" msgid="3931558336268541484">"<xliff:g id="SERVICE">%1$s</xliff:g> എന്നതിന് നിങ്ങളുടെ ഉപകരണത്തിന്മേൽ പൂർണ്ണ നിയന്ത്രണം അനുവദിക്കണോ?"</string>
<string name="accessibility_service_warning_description" msgid="291674995220940133">"ഉപയോഗസഹായി ആവശ്യങ്ങൾക്കായി നിങ്ങളെ സഹായിക്കുന്ന ആപ്പുകൾക്ക് പൂർണ്ണ നിയന്ത്രണം അനുയോജ്യമാണെങ്കിലും മിക്ക ആപ്പുകൾക്കും അനുയോജ്യമല്ല."</string>
<string name="accessibility_service_screen_control_title" msgid="190017412626919776">"സ്ക്രീൻ കാണുക, നിയന്ത്രിക്കുക"</string>
- <string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"ഇതിന് സ്ക്രീനിലെ എല്ലാ ഉള്ളടക്കവും വായിക്കാനും മറ്റ് ആപ്പുകളിൽ ഉള്ളടക്കം പ്രദർശിപ്പിക്കാനുമാവും."</string>
+ <string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"ഇതിന് സ്ക്രീനിലെ എല്ലാ ഉള്ളടക്കവും വായിക്കാനും മറ്റ് ആപ്പുകൾക്ക് മുകളിൽ ഉള്ളടക്കം പ്രദർശിപ്പിക്കാനുമാകും."</string>
<string name="accessibility_service_action_perform_title" msgid="779670378951658160">"കാണുക, പ്രവർത്തനങ്ങൾ നിർവഹിക്കുക"</string>
<string name="accessibility_service_action_perform_description" msgid="2718852014003170558">"ഇതിന് ഒരു ആപ്പുമായോ ഹാർഡ്വെയർ സെൻസറുമായോ ഉള്ള നിങ്ങളുടെ ആശയവിനിമയങ്ങൾ ട്രാക്ക് ചെയ്യാനും നിങ്ങളുടെ പേരിൽ ആശയവിനിമയം നടത്താനും കഴിയും."</string>
<string name="accessibility_dialog_button_allow" msgid="2092558122987144530">"അനുവദിക്കൂ"</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index f0d1b8e..cfb85c63 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -103,7 +103,7 @@
<string name="serviceClassVoice" msgid="2065556932043454987">"व्हॉइस"</string>
<string name="serviceClassData" msgid="4148080018967300248">"डेटा"</string>
<string name="serviceClassFAX" msgid="2561653371698904118">"फॅक्स"</string>
- <string name="serviceClassSMS" msgid="1547664561704509004">"SMS"</string>
+ <string name="serviceClassSMS" msgid="1547664561704509004">"एसएमएस"</string>
<string name="serviceClassDataAsync" msgid="2029856900898545984">"असंकालिक"</string>
<string name="serviceClassDataSync" msgid="7895071363569133704">"सिंक करा"</string>
<string name="serviceClassPacket" msgid="1430642951399303804">"पॅकेट"</string>
@@ -303,7 +303,7 @@
<string name="permgroupdesc_location" msgid="1995955142118450685">"या डिव्हाइसच्या स्थानावर प्रवेश"</string>
<string name="permgrouplab_calendar" msgid="6426860926123033230">"कॅलेंडर"</string>
<string name="permgroupdesc_calendar" msgid="6762751063361489379">"आपल्या कॅलेंडरवर प्रवेश"</string>
- <string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string>
+ <string name="permgrouplab_sms" msgid="795737735126084874">"एसएमएस"</string>
<string name="permgroupdesc_sms" msgid="5726462398070064542">"SMS मेसेज पाठवणे आणि पाहणे हे"</string>
<string name="permgrouplab_storage" msgid="5570124978732352858">"फाइल आणि दस्तऐवज"</string>
<string name="permgroupdesc_storage" msgid="8352226729501080525">"तुमच्या डिव्हाइसवर फाइल आणि दस्तऐवज अॅक्सेस करा"</string>
@@ -1688,7 +1688,7 @@
<string name="accessibility_service_screen_control_title" msgid="190017412626919776">"स्क्रीन पहा आणि नियंत्रित करा"</string>
<string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"ते स्क्रीनवरील सर्व आशय वाचू शकते आणि इतर ॲप्सवर आशय प्रदर्शित करू शकते."</string>
<string name="accessibility_service_action_perform_title" msgid="779670378951658160">"पहा आणि क्रिया करा"</string>
- <string name="accessibility_service_action_perform_description" msgid="2718852014003170558">"तुम्ही ॲप किंवा हार्डवेअर सेन्सर कसे वापरता याचा हे मागोवा घेऊ शकते आणि इतर ॲप्ससोबत तुमच्या वतीने काम करू शकते."</string>
+ <string name="accessibility_service_action_perform_description" msgid="2718852014003170558">"हे तुम्ही ॲप किंवा हार्डवेअर सेन्सर कसे वापरता ते ट्रॅक करू शकते आणि इतर ॲप्ससोबत तुमच्या वतीने संवाद साधू शकते."</string>
<string name="accessibility_dialog_button_allow" msgid="2092558122987144530">"अनुमती द्या"</string>
<string name="accessibility_dialog_button_deny" msgid="4129575637812472671">"नकार द्या"</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"वैशिष्ट्य वापरणे सुरू करण्यासाठी त्यावर टॅप करा:"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 19e6712..69ccf9b 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -1688,7 +1688,7 @@
<string name="accessibility_service_screen_control_title" msgid="190017412626919776">"Melihat dan mengawal skrin"</string>
<string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"Ciri ini boleh membaca semua kandungan pada skrin dan memaparkan kandungan di atas apl lain."</string>
<string name="accessibility_service_action_perform_title" msgid="779670378951658160">"Lihat dan laksanakan tindakan"</string>
- <string name="accessibility_service_action_perform_description" msgid="2718852014003170558">"Tindakan ini boleh menjejak interaksi anda dengan apl atau penderia perkakasan dan berinteraksi dengan apl bagi pihak anda."</string>
+ <string name="accessibility_service_action_perform_description" msgid="2718852014003170558">"Ciri ini boleh menjejak interaksi anda dengan apl atau penderia perkakasan dan berinteraksi dengan apl bagi pihak anda."</string>
<string name="accessibility_dialog_button_allow" msgid="2092558122987144530">"Benarkan"</string>
<string name="accessibility_dialog_button_deny" msgid="4129575637812472671">"Tolak"</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Ketik ciri untuk mula menggunakan ciri itu:"</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index c00e7ba..ea80234 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -1686,7 +1686,7 @@
<string name="accessibility_enable_service_title" msgid="3931558336268541484">"<xliff:g id="SERVICE">%1$s</xliff:g> ကို သင့်စက်အား အပြည့်အဝထိန်းချုပ်ခွင့် ပေးလိုပါသလား။"</string>
<string name="accessibility_service_warning_description" msgid="291674995220940133">"အများသုံးစွဲနိုင်မှု လိုအပ်ချက်များအတွက် အထောက်အကူပြုသည့် အက်ပ်များအား အပြည့်အဝ ထိန်းချုပ်ခွင့်ပေးခြင်းသည် သင့်လျော်သော်လည်း အက်ပ်အများစုအတွက် မသင့်လျော်ပါ။"</string>
<string name="accessibility_service_screen_control_title" msgid="190017412626919776">"ဖန်သားပြင်ကို ကြည့်ရှုထိန်းချုပ်ခြင်း"</string>
- <string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"၎င်းသည် မျက်နှာပြင်ပေါ်ရှိ အကြောင်းအရာများအားလုံးကို ဖတ်နိုင်ပြီး အခြားအက်ပ်များအပေါ်တွင် ထိုအကြောင်းအရာကို ဖော်ပြနိုင်သည်။"</string>
+ <string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"၎င်းသည် မျက်နှာပြင်ပေါ်ရှိ အကြောင်းအရာအားလုံးကို ဖတ်နိုင်ပြီး အခြားအက်ပ်များအပေါ်တွင် အကြောင်းအရာကို ဖော်ပြနိုင်သည်။"</string>
<string name="accessibility_service_action_perform_title" msgid="779670378951658160">"လုပ်ဆောင်ချက်များကို ကြည့်ရှုဆောင်ရွက်ခြင်း"</string>
<string name="accessibility_service_action_perform_description" msgid="2718852014003170558">"၎င်းသည် အက်ပ်တစ်ခု သို့မဟုတ် အာရုံခံကိရိယာကို အသုံးပြု၍ သင့်ပြန်လှန်တုံ့ပြန်မှုများကို မှတ်သားနိုင်ပြီး သင့်ကိုယ်စား အက်ပ်များနှင့် ပြန်လှန်တုံ့ပြန်နိုင်သည်။"</string>
<string name="accessibility_dialog_button_allow" msgid="2092558122987144530">"ခွင့်ပြုရန်"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index e61d38e..c59ba63 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -1684,9 +1684,9 @@
<string name="accessibility_shortcut_menu_item_status_on" msgid="6608392117189732543">"AAN"</string>
<string name="accessibility_shortcut_menu_item_status_off" msgid="5531598275559472393">"UIT"</string>
<string name="accessibility_enable_service_title" msgid="3931558336268541484">"Toestaan dat <xliff:g id="SERVICE">%1$s</xliff:g> volledige controle over je apparaat heeft?"</string>
- <string name="accessibility_service_warning_description" msgid="291674995220940133">"Volledige controle is gepast voor apps die je helpen met toegankelijkheid, maar voor de meeste apps is het ongepast."</string>
+ <string name="accessibility_service_warning_description" msgid="291674995220940133">"Volledige controle is gepast voor apps die je helpen met toegankelijkheid, maar niet voor de meeste apps."</string>
<string name="accessibility_service_screen_control_title" msgid="190017412626919776">"Scherm bekijken en bedienen"</string>
- <string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"De functie kan alle content op het scherm lezen en content bovenop andere apps weergeven"</string>
+ <string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"De functie kan alle content op het scherm lezen en content bovenop andere apps weergeven."</string>
<string name="accessibility_service_action_perform_title" msgid="779670378951658160">"Acties bekijken en uitvoeren"</string>
<string name="accessibility_service_action_perform_description" msgid="2718852014003170558">"De functie kan je interacties met een app of een hardwaresensor bijhouden en namens jou met apps communiceren."</string>
<string name="accessibility_dialog_button_allow" msgid="2092558122987144530">"Toestaan"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 28bfaa1..183940d 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -351,7 +351,7 @@
<string name="permdesc_expandStatusBar" msgid="7180756900448498536">"Aplikaciji omogoča razširjanje ali strnjevanje vrstice stanja."</string>
<string name="permlab_fullScreenIntent" msgid="4310888199502509104">"Prikaz obvestil kot celozaslonskih dejavnosti v zaklenjeni napravi"</string>
<string name="permdesc_fullScreenIntent" msgid="1100721419406643997">"Aplikaciji dovoli, da prikaže obvestila kot celozaslonske dejavnosti v zaklenjeni napravi."</string>
- <string name="permlab_install_shortcut" msgid="7451554307502256221">"nameščanje bližnjic"</string>
+ <string name="permlab_install_shortcut" msgid="7451554307502256221">"Nameščanje bližnjic"</string>
<string name="permdesc_install_shortcut" msgid="4476328467240212503">"Aplikaciji omogoča dodajanje bližnjic na začetni zaslon brez posredovanja uporabnika."</string>
<string name="permlab_uninstall_shortcut" msgid="295263654781900390">"odstranjevanje bližnjic"</string>
<string name="permdesc_uninstall_shortcut" msgid="1924735350988629188">"Aplikaciji omogoča odstranjevanje bližnjic z začetnega zaslona brez posredovanja uporabnika."</string>
@@ -1704,7 +1704,7 @@
<string name="color_inversion_feature_name" msgid="326050048927789012">"Inverzija barv"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Popravljanje barv"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Enoročni način"</string>
- <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Zelo zatemnjeno"</string>
+ <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Zelo zatemnjen zaslon"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Tipki za glasnost sta pridržani. Storitev <xliff:g id="SERVICE_NAME">%1$s</xliff:g> je vklopljena."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Tipki za glasnost sta pridržani. Storitev <xliff:g id="SERVICE_NAME">%1$s</xliff:g> je izklopljena."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Za uporabo storitve <xliff:g id="SERVICE_NAME">%1$s</xliff:g> pritisnite obe tipki za glasnost in ju pridržite tri sekunde"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index ded84df..2298c1c 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -1684,7 +1684,7 @@
<string name="accessibility_shortcut_menu_item_status_on" msgid="6608392117189732543">"เปิด"</string>
<string name="accessibility_shortcut_menu_item_status_off" msgid="5531598275559472393">"ปิด"</string>
<string name="accessibility_enable_service_title" msgid="3931558336268541484">"อนุญาตให้ <xliff:g id="SERVICE">%1$s</xliff:g> ควบคุมอุปกรณ์อย่างเต็มที่ไหม"</string>
- <string name="accessibility_service_warning_description" msgid="291674995220940133">"การควบคุมอย่างเต็มที่เหมาะสำหรับแอปที่ช่วยคุณในเรื่องความต้องการความช่วยเหลือพิเศษแต่ไม่เหมาะสำหรับแอปส่วนใหญ่"</string>
+ <string name="accessibility_service_warning_description" msgid="291674995220940133">"การควบคุมอย่างเต็มที่เหมาะสำหรับแอปเกี่ยวกับความช่วยเหลือพิเศษ แต่ไม่เหมาะสำหรับแอปส่วนใหญ่"</string>
<string name="accessibility_service_screen_control_title" msgid="190017412626919776">"ดูและควบคุมหน้าจอ"</string>
<string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"การควบคุมนี้สามารถอ่านเนื้อหาทั้งหมดบนหน้าจอและแสดงเนื้อหาทับแอปอื่นๆ"</string>
<string name="accessibility_service_action_perform_title" msgid="779670378951658160">"ดูและดำเนินการ"</string>
@@ -1717,7 +1717,7 @@
<string name="user_switching_message" msgid="1912993630661332336">"กำลังเปลี่ยนเป็น <xliff:g id="NAME">%1$s</xliff:g>…"</string>
<string name="user_logging_out_message" msgid="7216437629179710359">"กำลังออกจากระบบ <xliff:g id="NAME">%1$s</xliff:g>…"</string>
<string name="owner_name" msgid="8713560351570795743">"เจ้าของ"</string>
- <string name="guest_name" msgid="8502103277839834324">"ผู้มาเยือน"</string>
+ <string name="guest_name" msgid="8502103277839834324">"ผู้ใช้ชั่วคราว"</string>
<string name="error_message_title" msgid="4082495589294631966">"ข้อผิดพลาด"</string>
<string name="error_message_change_not_allowed" msgid="843159705042381454">"ผู้ดูแลระบบไม่อนุญาตให้ทำการเปลี่ยนแปลงนี้"</string>
<string name="app_not_found" msgid="3429506115332341800">"ไม่พบแอปพลิเคชันสำหรับการทำงานนี้"</string>
@@ -1963,7 +1963,7 @@
<string name="usb_mtp_launch_notification_title" msgid="774319638256707227">"เชื่อมต่อ <xliff:g id="PRODUCT_NAME">%1$s</xliff:g> แล้ว"</string>
<string name="usb_mtp_launch_notification_description" msgid="6942535713629852684">"แตะเพื่อดูไฟล์"</string>
<string name="pin_target" msgid="8036028973110156895">"ปักหมุด"</string>
- <string name="pin_specific_target" msgid="7824671240625957415">"ตรึง <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="pin_specific_target" msgid="7824671240625957415">"ปักหมุด <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="unpin_target" msgid="3963318576590204447">"เลิกปักหมุด"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"เลิกปักหมุด <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="app_info" msgid="6113278084877079851">"ข้อมูลแอป"</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 6d1ed06..75e72e2 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -1686,9 +1686,9 @@
<string name="accessibility_enable_service_title" msgid="3931558336268541484">"<xliff:g id="SERVICE">%1$s</xliff:g> کو آپ کے آلے کا مکمل کنٹرول حاصل کرنے کی اجازت دیں؟"</string>
<string name="accessibility_service_warning_description" msgid="291674995220940133">"مکمل کنٹرول ان ایپس کے لیے مناسب ہے جو ایکسیسبیلٹی کی ضروریات میں آپ کی مدد کرتی ہیں، لیکن زیادہ تر ایپس کیلئے مناسب نہیں۔"</string>
<string name="accessibility_service_screen_control_title" msgid="190017412626919776">"اسکرین کو دیکھیں اور کنٹرول کریں"</string>
- <string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"یہ تمام مواد کو اسکرین پر پڑھ اور دیگر ایپس پر مواد کو ڈسپلے کر سکتا ہے۔"</string>
+ <string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"یہ اسکرین پر موجود تمام مواد کو پڑھ سکتا ہے اور دیگر ایپس پر مواد کو ڈسپلے کر سکتا ہے۔"</string>
<string name="accessibility_service_action_perform_title" msgid="779670378951658160">"کارروائیاں دیکھیں اور انجام دیں"</string>
- <string name="accessibility_service_action_perform_description" msgid="2718852014003170558">"یہ آپ کے تعاملات کو ایپ یا ہارڈویئر سینسر کے ذریعے ٹریک کر سکتا ہے، اور آپ کی طرف سے ایپ کے ساتھ تعمل کر سکتا ہے۔"</string>
+ <string name="accessibility_service_action_perform_description" msgid="2718852014003170558">"یہ کسی ایپ یا ہارڈویئر سینسر کے ساتھ آپ کے تعاملات کو ٹریک کر سکتا ہے، اور آپ کی طرف سے ایپس کے ساتھ تعامل کر سکتا ہے۔"</string>
<string name="accessibility_dialog_button_allow" msgid="2092558122987144530">"اجازت دیں"</string>
<string name="accessibility_dialog_button_deny" msgid="4129575637812472671">"مسترد کریں"</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"ایک خصوصیت کا استعمال شروع کرنے کیلئے اسے تھپتھپائیں:"</string>
@@ -1702,7 +1702,7 @@
<string name="color_inversion_feature_name" msgid="326050048927789012">"رنگوں کی تقلیب"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"رنگ کی تصحیح"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"ایک ہاتھ کی وضع"</string>
- <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"اضافی دھندلا"</string>
+ <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"اضافی مدھم"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"والیوم کی کلیدوں کو دبائے رکھا گیا۔ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> آن ہے۔"</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"والیوم کی کلیدوں کو دبائے رکھا گیا۔ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> آف ہے۔"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> کا استعمال کرنے کے لیے 3 سیکنڈ تک والیوم کی دونوں کلیدوں کو چھوئیں اور دبائے رکھیں"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 9be8939..985af20 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -581,7 +581,7 @@
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"已取消驗證"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"未能識別"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"已取消驗證"</string>
- <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"未設定 PIN、圖形或密碼"</string>
+ <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"未設定 PIN、圖案或密碼"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"驗證時發生錯誤"</string>
<string name="screen_lock_app_setting_name" msgid="6054944352976789228">"使用螢幕鎖定"</string>
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"如要繼續操作,請輸入螢幕鎖定解鎖憑證"</string>
@@ -781,7 +781,7 @@
<string name="policylab_setGlobalProxy" msgid="215332221188670221">"設定裝置的全域代理伺服器"</string>
<string name="policydesc_setGlobalProxy" msgid="7149665222705519604">"設定政策啟用時所要使用的裝置全域代理伺服器,只有裝置擁有者可以設定全域代理伺服器。"</string>
<string name="policylab_expirePassword" msgid="6015404400532459169">"設定螢幕鎖定密碼期限"</string>
- <string name="policydesc_expirePassword" msgid="9136524319325960675">"變更螢幕鎖定密碼、PIN 或圖形的更改頻率。"</string>
+ <string name="policydesc_expirePassword" msgid="9136524319325960675">"變更螢幕鎖定密碼、PIN 或圖案的更改頻率。"</string>
<string name="policylab_encryptedStorage" msgid="9012936958126670110">"設定儲存裝置加密"</string>
<string name="policydesc_encryptedStorage" msgid="1102516950740375617">"必須為儲存的應用程式資料加密。"</string>
<string name="policylab_disableCamera" msgid="5749486347810162018">"停用相機"</string>
@@ -916,7 +916,7 @@
<string name="lockscreen_screen_locked" msgid="7364905540516041817">"螢幕已鎖定。"</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"按選單鍵解鎖或撥打緊急電話。"</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"按選單鍵解鎖。"</string>
- <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"畫出解鎖圖形來為螢幕解鎖"</string>
+ <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"畫出解鎖圖案來為螢幕解鎖"</string>
<string name="lockscreen_emergency_call" msgid="7500692654885445299">"緊急電話"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"返回通話"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"正確!"</string>
@@ -945,12 +945,12 @@
<string name="lockscreen_sim_puk_locked_instructions" msgid="5307979043730860995">"請參閱使用者指南或與客戶服務中心聯絡。"</string>
<string name="lockscreen_sim_locked_message" msgid="3160196135801185938">"SIM 卡處於鎖定狀態。"</string>
<string name="lockscreen_sim_unlock_progress_dialog_message" msgid="2286497117428409709">"正在解除 SIM 卡鎖定..."</string>
- <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6458790975898594240">"您已畫錯解鎖圖形 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。\n\n請在 <xliff:g id="NUMBER_1">%2$d</xliff:g> 秒後再試一次。"</string>
+ <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6458790975898594240">"您已畫錯解鎖圖案 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。\n\n請在 <xliff:g id="NUMBER_1">%2$d</xliff:g> 秒後再試一次。"</string>
<string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="3118353451602377380">"您已輸入錯誤的密碼 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。\n\n請在 <xliff:g id="NUMBER_1">%2$d</xliff:g> 秒後再試一次。"</string>
<string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="2874278239714821984">"您已輸入錯誤的 PIN 碼 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。\n\n請在 <xliff:g id="NUMBER_1">%2$d</xliff:g> 秒後再試一次。"</string>
- <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="3069635524964070596">"您已畫錯解鎖圖形 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次,如果再嘗試 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次仍未成功,系統會要求您使用您的 Google 登入資料解開上鎖的平板電腦。\n\n請在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後再試一次。"</string>
- <string name="lockscreen_failed_attempts_almost_glogin" product="tv" msgid="6399092175942158529">"您已畫錯解鎖圖形 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次,如果再嘗試 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次仍未成功,系統會要求您使用 Google 登入資料將 Android TV 裝置解鎖。\n\n請在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後再試一次。"</string>
- <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="5691623136957148335">"您已畫錯解鎖圖形 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次,如果再嘗試 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次仍未成功,系統會要求您使用您的 Google 登入資料解開上鎖的手機。\n\n請在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後再試一次。"</string>
+ <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="3069635524964070596">"您已畫錯解鎖圖案 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次,如果再嘗試 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次仍未成功,系統會要求您使用您的 Google 登入資料解開上鎖的平板電腦。\n\n請在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後再試一次。"</string>
+ <string name="lockscreen_failed_attempts_almost_glogin" product="tv" msgid="6399092175942158529">"您已畫錯解鎖圖案 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次,如果再嘗試 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次仍未成功,系統會要求您使用 Google 登入資料將 Android TV 裝置解鎖。\n\n請在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後再試一次。"</string>
+ <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="5691623136957148335">"您已畫錯解鎖圖案 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次,如果再嘗試 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次仍未成功,系統會要求您使用您的 Google 登入資料解開上鎖的手機。\n\n請在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後再試一次。"</string>
<string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="7914445759242151426">"您嘗試解除這部平板電腦的鎖定已失敗 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次,剩餘 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次嘗試機會。如果失敗次數超過嘗試次數限制,平板電腦將恢復原廠設定,所有使用者資料均會遺失。"</string>
<string name="lockscreen_failed_attempts_almost_at_wipe" product="tv" msgid="4275591249631864248">"您已 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次無法解鎖 Android TV 裝置。如果再失敗 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次,Android TV 裝置將回復原廠設定,所有使用者資料均會遺失。"</string>
<string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="1166532464798446579">"您嘗試解除這部手機的鎖定已失敗 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次,剩餘 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次嘗試機會。如果失敗次數超過嘗試次數限制,手機將恢復原廠設定,所有使用者資料均會遺失。"</string>
@@ -958,9 +958,9 @@
<string name="lockscreen_failed_attempts_now_wiping" product="tv" msgid="2205435033340091883">"您已 <xliff:g id="NUMBER">%d</xliff:g> 次無法解鎖 Android TV 裝置,Android TV 裝置現在將回復原廠設定。"</string>
<string name="lockscreen_failed_attempts_now_wiping" product="default" msgid="2203704707679895487">"您嘗試解除這部手機的鎖定已失敗 <xliff:g id="NUMBER">%d</xliff:g> 次。手機現在會重設為原廠預設值。"</string>
<string name="lockscreen_too_many_failed_attempts_countdown" msgid="6807200118164539589">"<xliff:g id="NUMBER">%d</xliff:g> 秒後再試一次。"</string>
- <string name="lockscreen_forgot_pattern_button_text" msgid="8362442730606839031">"忘記圖形?"</string>
+ <string name="lockscreen_forgot_pattern_button_text" msgid="8362442730606839031">"忘記圖案?"</string>
<string name="lockscreen_glogin_forgot_pattern" msgid="9218940117797602518">"帳戶解鎖"</string>
- <string name="lockscreen_glogin_too_many_attempts" msgid="3775904917743034195">"圖形嘗試次數過多"</string>
+ <string name="lockscreen_glogin_too_many_attempts" msgid="3775904917743034195">"圖案嘗試次數過多"</string>
<string name="lockscreen_glogin_instructions" msgid="4695162942525531700">"如要解鎖,請以 Google 帳戶登入。"</string>
<string name="lockscreen_glogin_username_hint" msgid="6916101478673157045">"使用者名稱 (電子郵件)"</string>
<string name="lockscreen_glogin_password_hint" msgid="3031027901286812848">"密碼"</string>
@@ -971,12 +971,12 @@
<string name="lockscreen_unlock_label" msgid="4648257878373307582">"解除鎖定"</string>
<string name="lockscreen_sound_on_label" msgid="1660281470535492430">"開啟音效"</string>
<string name="lockscreen_sound_off_label" msgid="2331496559245450053">"關閉音效"</string>
- <string name="lockscreen_access_pattern_start" msgid="3778502525702613399">"已開始繪畫解鎖圖形"</string>
- <string name="lockscreen_access_pattern_cleared" msgid="7493849102641167049">"已清除解鎖圖形"</string>
+ <string name="lockscreen_access_pattern_start" msgid="3778502525702613399">"已開始繪畫解鎖圖案"</string>
+ <string name="lockscreen_access_pattern_cleared" msgid="7493849102641167049">"已清除解鎖圖案"</string>
<string name="lockscreen_access_pattern_cell_added" msgid="6746676335293144163">"已加入一格"</string>
<string name="lockscreen_access_pattern_cell_added_verbose" msgid="2931364927622563465">"已加入 <xliff:g id="CELL_INDEX">%1$s</xliff:g> 點"</string>
- <string name="lockscreen_access_pattern_detected" msgid="3931150554035194012">"已畫出解鎖圖形"</string>
- <string name="lockscreen_access_pattern_area" msgid="1288780416685002841">"圖形區域。"</string>
+ <string name="lockscreen_access_pattern_detected" msgid="3931150554035194012">"已畫出解鎖圖案"</string>
+ <string name="lockscreen_access_pattern_area" msgid="1288780416685002841">"圖案區域。"</string>
<string name="keyguard_accessibility_widget_changed" msgid="7298011259508200234">"%1$s。第 %2$d 個小工具,共 %3$d 個。"</string>
<string name="keyguard_accessibility_add_widget" msgid="8245795023551343672">"新增小工具。"</string>
<string name="keyguard_accessibility_widget_empty_slot" msgid="544239307077644480">"空白"</string>
@@ -992,13 +992,13 @@
<string name="keyguard_accessibility_widget_deleted" msgid="1509738950119878705">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g>小工具已刪除。"</string>
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"展開解鎖區域。"</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"滑動解鎖。"</string>
- <string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"圖形解鎖。"</string>
+ <string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"圖案解鎖。"</string>
<string name="keyguard_accessibility_face_unlock" msgid="4533832120787386728">"面孔解鎖。"</string>
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"PIN 解鎖。"</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"SIM 卡 PIN 碼解鎖。"</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"SIM 卡 PUK 解鎖。"</string>
<string name="keyguard_accessibility_password_unlock" msgid="6130186108581153265">"密碼解鎖。"</string>
- <string name="keyguard_accessibility_pattern_area" msgid="1419570880512350689">"圖形區域。"</string>
+ <string name="keyguard_accessibility_pattern_area" msgid="1419570880512350689">"圖案區域。"</string>
<string name="keyguard_accessibility_slide_area" msgid="4331399051142520176">"滑動區域。"</string>
<string name="password_keyboard_label_symbol_key" msgid="2716255580853511949">"?123"</string>
<string name="password_keyboard_label_alpha_key" msgid="5294837425652726684">"ABC"</string>
@@ -1632,11 +1632,11 @@
<string name="display_manager_overlay_display_name" msgid="5306088205181005861">"重疊效果 #<xliff:g id="ID">%1$d</xliff:g>"</string>
<string name="display_manager_overlay_display_title" msgid="1480158037150469170">"<xliff:g id="NAME">%1$s</xliff:g>:<xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>,<xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
<string name="display_manager_overlay_display_secure_suffix" msgid="2810034719482834679">"(安全)"</string>
- <string name="kg_forgot_pattern_button_text" msgid="406145459223122537">"忘記了圖形"</string>
- <string name="kg_wrong_pattern" msgid="1342812634464179931">"圖形錯誤"</string>
+ <string name="kg_forgot_pattern_button_text" msgid="406145459223122537">"忘記了圖案"</string>
+ <string name="kg_wrong_pattern" msgid="1342812634464179931">"圖案錯誤"</string>
<string name="kg_wrong_password" msgid="2384677900494439426">"密碼錯誤"</string>
<string name="kg_wrong_pin" msgid="3680925703673166482">"PIN 錯誤"</string>
- <string name="kg_pattern_instructions" msgid="8366024510502517748">"畫出圖形"</string>
+ <string name="kg_pattern_instructions" msgid="8366024510502517748">"畫出圖案"</string>
<string name="kg_sim_pin_instructions" msgid="6479401489471690359">"輸入 SIM 卡 PIN 碼"</string>
<string name="kg_pin_instructions" msgid="7355933174673539021">"輸入 PIN 碼"</string>
<string name="kg_password_instructions" msgid="7179782578809398050">"輸入密碼"</string>
@@ -1649,7 +1649,7 @@
<string name="kg_invalid_sim_puk_hint" msgid="2539364558870734339">"PUK 碼應由 8 位數字組成。"</string>
<string name="kg_invalid_puk" msgid="4809502818518963344">"請重新輸入正確的 PUK 碼。如果嘗試輸入的次數過多,SIM 卡將永久停用。"</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="4705368340409816254">"PIN 碼不符"</string>
- <string name="kg_login_too_many_attempts" msgid="699292728290654121">"圖形嘗試次數過多"</string>
+ <string name="kg_login_too_many_attempts" msgid="699292728290654121">"圖案嘗試次數過多"</string>
<string name="kg_login_instructions" msgid="3619844310339066827">"如要解鎖,請以 Google 帳戶登入。"</string>
<string name="kg_login_username_hint" msgid="1765453775467133251">"使用者名稱 (電子郵件)"</string>
<string name="kg_login_password_hint" msgid="3330530727273164402">"密碼"</string>
@@ -1659,16 +1659,16 @@
<string name="kg_login_checking_password" msgid="4676010303243317253">"正在檢查帳戶…"</string>
<string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="23741434207544038">"您已輸入錯誤的 PIN 碼 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。\n\n請在 <xliff:g id="NUMBER_1">%2$d</xliff:g> 秒後再試一次。"</string>
<string name="kg_too_many_failed_password_attempts_dialog_message" msgid="3328686432962224215">"您已輸入錯誤的密碼 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。\n\n請在 <xliff:g id="NUMBER_1">%2$d</xliff:g> 秒後再試一次。"</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="7357404233979139075">"您已畫錯解鎖圖形 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。\n\n請在 <xliff:g id="NUMBER_1">%2$d</xliff:g> 秒後再試一次。"</string>
+ <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="7357404233979139075">"您已畫錯解鎖圖案 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。\n\n請在 <xliff:g id="NUMBER_1">%2$d</xliff:g> 秒後再試一次。"</string>
<string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="3479940221343361587">"您嘗試了 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次仍未能成功解開這部上鎖的平板電腦。如果再嘗試 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次仍未成功,平板電腦將回復原廠設定,所有使用者資料均會失去。"</string>
<string name="kg_failed_attempts_almost_at_wipe" product="tv" msgid="9064457748587850217">"您已 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次無法解鎖 Android TV 裝置。如果再失敗 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次,Android TV 裝置將回復原廠設定,所有使用者資料均會遺失。"</string>
<string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="5955398963754432548">"您嘗試了 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次仍未能成功解開這部上鎖的手機。如果再嘗試 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次仍未成功,手機將回復原廠設定,所有使用者資料均會失去。"</string>
<string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2299099385175083308">"您嘗試了 <xliff:g id="NUMBER">%d</xliff:g> 次仍未能成功解開這部上鎖的平板電腦。平板電腦現在將回復原廠設定。"</string>
<string name="kg_failed_attempts_now_wiping" product="tv" msgid="5045460916106267585">"您已 <xliff:g id="NUMBER">%d</xliff:g> 次無法解鎖 Android TV 裝置,Android TV 裝置現在將回復原廠設定。"</string>
<string name="kg_failed_attempts_now_wiping" product="default" msgid="5043730590446071189">"您嘗試了 <xliff:g id="NUMBER">%d</xliff:g> 次仍未能成功解開這部上鎖的手機。手機現在將回復原廠設定。"</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="7086799295109717623">"您已畫錯解鎖圖形 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次,如果再嘗試 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次仍未成功,系統會要求您透過電郵帳戶解開上鎖的平板電腦。\n\n請在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後再試一次。"</string>
- <string name="kg_failed_attempts_almost_at_login" product="tv" msgid="4670840383567106114">"您已畫錯解鎖圖形 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。如果再嘗試 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次仍未成功,系統會要求您使用電郵帳戶解鎖 Android TV 裝置。\n\n請在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後再試一次。"</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"您已畫錯解鎖圖形 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次,如果再嘗試 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次仍未成功,系統會要求您透過電郵帳戶解開上鎖的手機。\n\n請在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後再試一次。"</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="7086799295109717623">"您已畫錯解鎖圖案 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次,如果再嘗試 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次仍未成功,系統會要求您透過電郵帳戶解開上鎖的平板電腦。\n\n請在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後再試一次。"</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tv" msgid="4670840383567106114">"您已畫錯解鎖圖案 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。如果再嘗試 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次仍未成功,系統會要求您使用電郵帳戶解鎖 Android TV 裝置。\n\n請在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後再試一次。"</string>
+ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"您已畫錯解鎖圖案 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次,如果再嘗試 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次仍未成功,系統會要求您透過電郵帳戶解開上鎖的手機。\n\n請在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後再試一次。"</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"移除"</string>
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"要調高音量 (比建議的音量更大聲) 嗎?\n\n長時間聆聽高分貝音量可能會導致您的聽力受損。"</string>
@@ -1848,7 +1848,7 @@
<string name="managed_profile_label_badge_2" msgid="5673187309555352550">"第二個工作<xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="managed_profile_label_badge_3" msgid="6882151970556391957">"第三個工作<xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"取消固定時必須輸入 PIN"</string>
- <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"取消固定時必須提供解鎖圖形"</string>
+ <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"取消固定時必須提供解鎖圖案"</string>
<string name="lock_to_app_unlock_password" msgid="9126722403506560473">"取消固定時必須輸入密碼"</string>
<string name="package_installed_device_owner" msgid="7035926868974878525">"已由您的管理員安裝"</string>
<string name="package_updated_device_owner" msgid="7560272363805506941">"已由您的管理員更新"</string>
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index 5df3dde..b515abc 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -448,5 +448,6 @@
<color name="accessibility_color_inversion_background">#546E7A</color>
<!-- Color of camera light when camera is in use -->
- <color name="camera_privacy_light">#FFFFFF</color>
+ <color name="camera_privacy_light_day">#FFFFFF</color>
+ <color name="camera_privacy_light_night">#FFFFFF</color>
</resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 9d75493..a3a37e3 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1869,6 +1869,11 @@
-->
<string name="config_defaultSearchSelectorPackageName" translatable="false"></string>
+ <!-- The package name of the default captive portal login app. Must be granted the
+ POST_NOTIFICATIONS permission.
+ -->
+ <string name="config_defaultCaptivePortalLoginPackageName" translatable="false"></string>
+
<!-- Whether to enable geocoder overlay which allows geocoder to be replaced
by an app at run-time. When disabled, only the
config_geocoderProviderPackageName package will be searched for
@@ -3002,12 +3007,6 @@
</string-array>
- <!-- When migrating notification settings into the permission framework, whether all existing
- apps should be marked as 'user-set' (true) or whether only the apps that have explicitly
- modified notification settings should be marked as 'user-set' (false). Users will not see
- system generated permission prompts for 'user-set' apps. -->
- <bool name="config_notificationForceUserSetOnUpgrade">true</bool>
-
<!-- Default Gravity setting for the system Toast view. Equivalent to: Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM -->
<integer name="config_toastDefaultGravity">0x00000051</integer>
@@ -4902,7 +4901,7 @@
<!-- Whether or not to hide the navigation bar when the soft keyboard is visible in order to
create additional screen real estate outside beyond the keyboard. Note that the user needs
to have a confirmed way to dismiss the keyboard when desired. -->
- <bool name="config_automotiveHideNavBarForKeyboard">false</bool>
+ <bool name="config_hideNavBarForKeyboard">false</bool>
<!-- Whether or not to show the built-in charging animation when the device begins charging
wirelessly. -->
@@ -5137,16 +5136,24 @@
-->
<color name="config_letterboxBackgroundColor">@android:color/system_neutral2_900</color>
- <!-- Horizonal position of a center of the letterboxed app window.
+ <!-- Horizontal position of a center of the letterboxed app window.
0 corresponds to the left side of the screen and 1 to the right side. If given value < 0
- or > 1, it is ignored and central positionis used (0.5). -->
+ or > 1, it is ignored and central position is used (0.5). -->
<item name="config_letterboxHorizontalPositionMultiplier" format="float" type="dimen">0.5</item>
- <!-- Whether reachability repositioning is allowed for letterboxed fullscreen apps in landscape
- device orientation. -->
- <bool name="config_letterboxIsReachabilityEnabled">false</bool>
+ <!-- Vertical position of a center of the letterboxed app window.
+ 0 corresponds to the upper side of the screen and 1 to the lower side. If given value < 0
+ or > 1, it is ignored and central position is used (0.5). -->
+ <item name="config_letterboxVerticalPositionMultiplier" format="float" type="dimen">0.5</item>
- <!-- Default horizonal position of the letterboxed app window when reachability is
+ <!-- Whether horizontal reachability repositioning is allowed for letterboxed fullscreen apps.
+ -->
+ <bool name="config_letterboxIsHorizontalReachabilityEnabled">false</bool>
+
+ <!-- Whether vertical reachability repositioning is allowed for letterboxed fullscreen apps. -->
+ <bool name="config_letterboxIsVerticalReachabilityEnabled">false</bool>
+
+ <!-- Default horizontal position of the letterboxed app window when reachability is
enabled and an app is fullscreen in landscape device orientation. When reachability is
enabled, the position can change between left, center and right. This config defines the
default one:
@@ -5154,7 +5161,17 @@
- Option 1 - Center.
- Option 2 - Right.
If given value is outside of this range, the option 1 (center) is assummed. -->
- <integer name="config_letterboxDefaultPositionForReachability">1</integer>
+ <integer name="config_letterboxDefaultPositionForHorizontalReachability">1</integer>
+
+ <!-- Default vertical position of the letterboxed app window when reachability is
+ enabled and an app is fullscreen in portrait device orientation. When reachability is
+ enabled, the position can change between top, center and bottom. This config defines the
+ default one:
+ - Option 0 - Top.
+ - Option 1 - Center.
+ - Option 2 - Bottom.
+ If given value is outside of this range, the option 1 (center) is assummed. -->
+ <integer name="config_letterboxDefaultPositionForVerticalReachability">1</integer>
<!-- Whether displaying letterbox education is enabled for letterboxed fullscreen apps. -->
<bool name="config_letterboxIsEducationEnabled">false</bool>
@@ -5669,6 +5686,9 @@
<!-- Whether or not to enable the lock screen entry point for the QR code scanner. -->
<bool name="config_enableQrCodeScannerOnLockScreen">false</bool>
+ <!-- Default component for QR code scanner -->
+ <string name="config_defaultQrCodeComponent"></string>
+
<!-- Whether Low Power Standby is supported and can be enabled. -->
<bool name="config_lowPowerStandbySupported">false</bool>
@@ -5759,6 +5779,14 @@
-->
<integer name="config_bg_current_drain_location_min_duration">1800</integer>
+ <!-- The behavior when the system detects it has abusive current drains, whether or not to
+ move the app to the restricted standby bucket level.
+ True - we'll move the app to restricted standby bucket as long as its bg battery usage
+ goes beyond the threshold, False - we'll not move it.
+ Note: This should be only enabled on devices with high confidence on power measurement.
+ -->
+ <bool name="config_bg_current_drain_auto_restrict_abusive_apps">false</bool>
+
<!-- The behavior for an app with a FGS and its notification is still showing, when the system
detects it's abusive and should be put into bg restricted level. True - we'll
show the prompt to user, False - we'll not show it.
@@ -5794,4 +5822,20 @@
<!-- List of the labels of requestable device state config values -->
<string-array name="config_deviceStatesAvailableForAppRequests"/>
+
+ <!-- Interval in milliseconds to average light sensor values for camera light brightness -->
+ <integer name="config_cameraPrivacyLightAlsAveragingIntervalMillis">3000</integer>
+ <!-- Light sensor's lux value to use as the threshold between using day or night brightness -->
+ <integer name="config_cameraPrivacyLightAlsNightThreshold">4</integer>
+
+ <!-- List of system components which are allowed to receive ServiceState entries in an
+ un-sanitized form, even if the location toggle is off. This is intended ONLY for system
+ components, such as the telephony stack, which require access to the full ServiceState for
+ tasks such as network registration. -->
+ <string-array name="config_serviceStateLocationAllowedPackages">
+ <item>"com.android.phone"</item>
+ </string-array>
+
+ <!-- Whether the wake screen on notifications feature is available. -->
+ <bool name="config_pulseOnNotificationsAvailable">true</bool>
</resources>
diff --git a/core/res/res/values/config_telephony.xml b/core/res/res/values/config_telephony.xml
index d9ac516..682ce46 100644
--- a/core/res/res/values/config_telephony.xml
+++ b/core/res/res/values/config_telephony.xml
@@ -35,7 +35,7 @@
rmem_min,rmem_def,rmem_max,wmem_min,wmem_def,wmem_max
If this is configured as an empty string, the system default will be applied.
-->
- <string name="config_tcp_buffers" translatable="false"></string>
+ <string name="config_tcp_buffers" translatable="false">2097152,6291456,16777216,512000,2097152,8388608</string>
<java-symbol type="string" name="config_tcp_buffers" />
<!-- What source to use to estimate link upstream and downstream bandwidth capacities.
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index a4be0b9..c6b60f5 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -876,9 +876,9 @@
<string name="permgroupdesc_sms">send and view SMS messages</string>
<!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
- <string name="permgrouplab_storage">Files and documents</string>
+ <string name="permgrouplab_storage">Files</string>
<!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
- <string name="permgroupdesc_storage">access files and documents on your device</string>
+ <string name="permgroupdesc_storage">access files on your device</string>
<!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=40]-->
<string name="permgrouplab_readMediaAural">Music and audio</string>
@@ -6325,5 +6325,5 @@
<string name="vdm_camera_access_denied" product="tablet">Can’t access the tablet’s camera from your <xliff:g id="device" example="Chromebook">%1$s</xliff:g></string>
<!-- Title for preference of the system default locale. [CHAR LIMIT=50]-->
- <string name="system_locale_title">System language</string>
+ <string name="system_locale_title">System default</string>
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 94d78e6..99e65f1 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3338,6 +3338,7 @@
<java-symbol type="string" name="config_dozeTapSensorType" />
<java-symbol type="array" name="config_dozeTapSensorPostureMapping" />
<java-symbol type="bool" name="config_dozePulsePickup" />
+ <java-symbol type="bool" name="config_pulseOnNotificationsAvailable" />
<!-- Used for MimeIconUtils. -->
<java-symbol type="drawable" name="ic_doc_apk" />
@@ -3426,6 +3427,9 @@
<!-- Search Selector -->
<java-symbol type="string" name="config_defaultSearchSelectorPackageName" />
+ <!-- Captive Portal Login -->
+ <java-symbol type="string" name="config_defaultCaptivePortalLoginPackageName" />
+
<!-- Optional IPsec algorithms -->
<java-symbol type="array" name="config_optionalIpSecAlgorithms" />
@@ -4158,7 +4162,7 @@
<java-symbol type="bool" name="config_disable_all_cb_messages" />
<java-symbol type="drawable" name="ic_close" />
- <java-symbol type="bool" name="config_automotiveHideNavBarForKeyboard" />
+ <java-symbol type="bool" name="config_hideNavBarForKeyboard" />
<java-symbol type="bool" name="config_showBuiltinWirelessChargingAnim" />
@@ -4385,8 +4389,11 @@
<java-symbol type="integer" name="config_letterboxBackgroundType" />
<java-symbol type="color" name="config_letterboxBackgroundColor" />
<java-symbol type="dimen" name="config_letterboxHorizontalPositionMultiplier" />
- <java-symbol type="bool" name="config_letterboxIsReachabilityEnabled" />
- <java-symbol type="integer" name="config_letterboxDefaultPositionForReachability" />
+ <java-symbol type="dimen" name="config_letterboxVerticalPositionMultiplier" />
+ <java-symbol type="bool" name="config_letterboxIsHorizontalReachabilityEnabled" />
+ <java-symbol type="bool" name="config_letterboxIsVerticalReachabilityEnabled" />
+ <java-symbol type="integer" name="config_letterboxDefaultPositionForHorizontalReachability" />
+ <java-symbol type="integer" name="config_letterboxDefaultPositionForVerticalReachability" />
<java-symbol type="bool" name="config_letterboxIsEducationEnabled" />
<java-symbol type="bool" name="config_isCameraCompatControlForStretchedIssuesEnabled" />
@@ -4715,6 +4722,7 @@
<java-symbol type="string" name="config_wearSysUiPackage"/>
<java-symbol type="string" name="config_wearSysUiMainActivity"/>
+ <java-symbol type="string" name="config_defaultQrCodeComponent"/>
<java-symbol type="dimen" name="secondary_rounded_corner_radius" />
<java-symbol type="dimen" name="secondary_rounded_corner_radius_top" />
@@ -4760,7 +4768,10 @@
<!-- For VirtualDeviceManager -->
<java-symbol type="string" name="vdm_camera_access_denied" />
- <java-symbol type="color" name="camera_privacy_light"/>
+ <java-symbol type="color" name="camera_privacy_light_day"/>
+ <java-symbol type="color" name="camera_privacy_light_night"/>
+ <java-symbol type="integer" name="config_cameraPrivacyLightAlsAveragingIntervalMillis"/>
+ <java-symbol type="integer" name="config_cameraPrivacyLightAlsNightThreshold"/>
<java-symbol type="bool" name="config_bg_current_drain_monitor_enabled" />
<java-symbol type="array" name="config_bg_current_drain_threshold_to_restricted_bucket" />
@@ -4774,13 +4785,14 @@
<java-symbol type="array" name="config_bg_current_drain_high_threshold_to_bg_restricted" />
<java-symbol type="integer" name="config_bg_current_drain_media_playback_min_duration" />
<java-symbol type="integer" name="config_bg_current_drain_location_min_duration" />
+ <java-symbol type="bool" name="config_bg_current_drain_auto_restrict_abusive_apps" />
<java-symbol type="bool" name="config_bg_prompt_fgs_with_noti_to_bg_restricted" />
<java-symbol type="bool" name="config_bg_prompt_abusive_apps_to_bg_restricted" />
<java-symbol type="integer" name="config_bg_current_drain_exempted_types" />
<java-symbol type="bool" name="config_bg_current_drain_high_threshold_by_bg_location" />
<java-symbol type="drawable" name="ic_swap_horiz" />
- <java-symbol type="bool" name="config_notificationForceUserSetOnUpgrade" />
<java-symbol type="array" name="config_deviceStatesAvailableForAppRequests" />
+ <java-symbol type="array" name="config_serviceStateLocationAllowedPackages" />
<!-- For app language picker -->
<java-symbol type="string" name="system_locale_title" />
diff --git a/core/tests/PackageInstallerSessions/Android.bp b/core/tests/PackageInstallerSessions/Android.bp
index de2a013..6f2366e 100644
--- a/core/tests/PackageInstallerSessions/Android.bp
+++ b/core/tests/PackageInstallerSessions/Android.bp
@@ -50,6 +50,6 @@
":PackageManagerTestAppVersion1",
],
- platform_apis: true,
+ sdk_version: "core_platform",
test_suites: ["device-tests"],
}
diff --git a/core/tests/bugreports/Android.bp b/core/tests/bugreports/Android.bp
index 43a9679..2b34ee2 100644
--- a/core/tests/bugreports/Android.bp
+++ b/core/tests/bugreports/Android.bp
@@ -35,7 +35,7 @@
"truth-prebuilt",
],
test_suites: ["general-tests"],
- platform_apis: true,
+ sdk_version: "test_current",
}
filegroup {
diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp
index 11f4aad..48c9df0 100644
--- a/core/tests/coretests/Android.bp
+++ b/core/tests/coretests/Android.bp
@@ -72,7 +72,7 @@
"libpowermanagertest_jni",
],
- platform_apis: true,
+ sdk_version: "core_platform",
test_suites: ["device-tests"],
certificate: "platform",
diff --git a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
index bfb2fd5..a2d4baf 100644
--- a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
+++ b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
@@ -31,7 +31,6 @@
import android.annotation.Nullable;
import android.app.Activity;
-import android.app.ActivityManager;
import android.app.ActivityThread;
import android.app.ActivityThread.ActivityClientRecord;
import android.app.IApplicationThread;
@@ -571,53 +570,6 @@
}
@Test
- public void testHandleProcessConfigurationChanged_DependOnProcessState() {
- final ActivityThread activityThread = ActivityThread.currentActivityThread();
- final Configuration origConfig = activityThread.getConfiguration();
- final int newDpi = origConfig.densityDpi + 10;
- final Configuration newConfig = new Configuration(origConfig);
- newConfig.seq++;
- newConfig.densityDpi = newDpi;
-
- activityThread.updateProcessState(ActivityManager.PROCESS_STATE_CACHED_ACTIVITY,
- false /* fromIPC */);
-
- applyProcessConfiguration(activityThread, newConfig);
- try {
- // In the cached state, the configuration is only set as pending and not applied.
- assertEquals(origConfig.densityDpi, activityThread.getConfiguration().densityDpi);
- assertTrue(activityThread.isCachedProcessState());
- } finally {
- // The foreground state is the default state of instrumentation.
- activityThread.updateProcessState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE,
- false /* fromIPC */);
- }
- InstrumentationRegistry.getInstrumentation().waitForIdleSync();
-
- try {
- // The state becomes non-cached, the pending configuration should be applied.
- assertEquals(newConfig.densityDpi, activityThread.getConfiguration().densityDpi);
- assertFalse(activityThread.isCachedProcessState());
- } finally {
- // Restore to the original configuration.
- activityThread.getConfiguration().seq = origConfig.seq - 1;
- applyProcessConfiguration(activityThread, origConfig);
- }
- }
-
- private static void applyProcessConfiguration(ActivityThread thread, Configuration config) {
- final ClientTransaction clientTransaction = newTransaction(thread,
- null /* activityToken */);
- clientTransaction.addCallback(ConfigurationChangeItem.obtain(config));
- final IApplicationThread appThread = thread.getApplicationThread();
- try {
- appThread.scheduleTransaction(clientTransaction);
- } catch (Exception ignored) {
- }
- InstrumentationRegistry.getInstrumentation().waitForIdleSync();
- }
-
- @Test
public void testResumeAfterNewIntent() {
final Activity activity = mActivityTestRule.launchActivity(new Intent());
final ActivityThread activityThread = activity.getActivityThread();
diff --git a/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java b/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java
index c9a18da..c9e02f8 100644
--- a/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java
+++ b/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java
@@ -38,8 +38,8 @@
import android.os.Parcel;
import android.platform.test.annotations.Presubmit;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
import com.android.internal.widget.PasswordValidationError;
@@ -324,9 +324,59 @@
PasswordValidationError.WEAK_CREDENTIAL_TYPE, 0);
}
+ @Test
+ public void testValidatePasswordMetrics_pinAndComplexityHigh() {
+ PasswordMetrics adminMetrics = new PasswordMetrics(CREDENTIAL_TYPE_PIN);
+ PasswordMetrics actualMetrics = new PasswordMetrics(CREDENTIAL_TYPE_PIN);
+ actualMetrics.length = 6;
+ actualMetrics.seqLength = 1;
+
+ assertValidationErrors(
+ validatePasswordMetrics(adminMetrics, PASSWORD_COMPLEXITY_HIGH, actualMetrics),
+ PasswordValidationError.TOO_SHORT, 8);
+ }
+
+ @Test
+ public void testValidatePasswordMetrics_nonAllNumberPasswordAndComplexityHigh() {
+ PasswordMetrics adminMetrics = new PasswordMetrics(CREDENTIAL_TYPE_PASSWORD);
+ PasswordMetrics actualMetrics = new PasswordMetrics(CREDENTIAL_TYPE_PASSWORD);
+ actualMetrics.length = 5;
+ actualMetrics.nonNumeric = 1;
+ actualMetrics.seqLength = 1;
+
+ assertValidationErrors(
+ validatePasswordMetrics(adminMetrics, PASSWORD_COMPLEXITY_HIGH, actualMetrics),
+ PasswordValidationError.TOO_SHORT, 6);
+ }
+
+ @Test
+ public void testValidatePasswordMetrics_allNumberPasswordAndComplexityHigh() {
+ PasswordMetrics adminMetrics = new PasswordMetrics(CREDENTIAL_TYPE_PASSWORD);
+ PasswordMetrics actualMetrics = new PasswordMetrics(CREDENTIAL_TYPE_PASSWORD);
+ actualMetrics.length = 6;
+ actualMetrics.seqLength = 1;
+
+ assertValidationErrors(
+ validatePasswordMetrics(adminMetrics, PASSWORD_COMPLEXITY_HIGH, actualMetrics),
+ PasswordValidationError.TOO_SHORT_WHEN_ALL_NUMERIC, 8);
+ }
+
+ @Test
+ public void testValidatePasswordMetrics_allNumberPasswordAndRequireNonNumeric() {
+ PasswordMetrics adminMetrics = new PasswordMetrics(CREDENTIAL_TYPE_PASSWORD);
+ adminMetrics.nonNumeric = 1;
+ PasswordMetrics actualMetrics = new PasswordMetrics(CREDENTIAL_TYPE_PASSWORD);
+ actualMetrics.length = 6;
+ actualMetrics.seqLength = 1;
+
+ assertValidationErrors(
+ validatePasswordMetrics(adminMetrics, PASSWORD_COMPLEXITY_HIGH, actualMetrics),
+ PasswordValidationError.NOT_ENOUGH_NON_DIGITS, 1);
+ }
+
/**
* @param expected sequense of validation error codes followed by requirement values, must have
- * even number of elements. Empty means no errors.
+ * even number of elements. Empty means no errors.
*/
private void assertValidationErrors(
List<PasswordValidationError> actualErrors, int... expected) {
diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
index 8276d10..0eca0a8 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
@@ -425,7 +425,7 @@
@Override
public void bindApplication(String s, ApplicationInfo applicationInfo,
- String sdkSandboxClientAppPackage,
+ String sdkSandboxClientAppVolumeUuid, String sdkSandboxClientAppPackage,
ProviderInfoList list, ComponentName componentName, ProfilerInfo profilerInfo,
Bundle bundle, IInstrumentationWatcher iInstrumentationWatcher,
IUiAutomationConnection iUiAutomationConnection, int i, boolean b, boolean b1,
diff --git a/core/tests/coretests/src/android/content/pm/AppSearchShortcutInfoTest.java b/core/tests/coretests/src/android/content/pm/AppSearchShortcutInfoTest.java
index 969357f..22feecb 100644
--- a/core/tests/coretests/src/android/content/pm/AppSearchShortcutInfoTest.java
+++ b/core/tests/coretests/src/android/content/pm/AppSearchShortcutInfoTest.java
@@ -24,7 +24,6 @@
import android.platform.test.annotations.Presubmit;
import android.util.ArraySet;
-import org.junit.Ignore;
import org.junit.Test;
import java.util.Set;
@@ -32,7 +31,6 @@
@Presubmit
public class AppSearchShortcutInfoTest {
- @Ignore("b/208375334")
@Test
public void testBuildShortcutAndGetValue() {
final String category =
@@ -51,7 +49,7 @@
final Intent shortcutIntent = new Intent(Intent.ACTION_VIEW);
final ShortcutInfo shortcut = new AppSearchShortcutInfo.Builder(/*packageName=*/"", id)
.setActivity(activity)
- .setLongLabel(id)
+ .setShortLabel(id)
.setIconResName(shortcutIconResName)
.setIntent(shortcutIntent)
.setPerson(person)
@@ -64,11 +62,13 @@
assertThat(shortcut.getId()).isEqualTo(id);
assertThat(shortcut.getShortLabel()).isEqualTo(id);
assertThat(shortcut.getIconResName()).isEqualTo(shortcutIconResName);
- assertThat(shortcut.getIntent().toString()).isEqualTo(shortcut.toString());
+ assertThat(shortcut.getIntent().toString()).isEqualTo(shortcutIntent.toString());
assertThat(shortcut.getPersons().length).isEqualTo(1);
- assertThat(shortcut.getPersons()[0]).isEqualTo(person);
+ final Person target = shortcut.getPersons()[0];
+ assertThat(target.getName()).isEqualTo(person.getName());
+ assertThat(target.isBot()).isEqualTo(person.isBot());
+ assertThat(target.isImportant()).isEqualTo(person.isImportant());
assertThat(shortcut.getCategories()).isEqualTo(categorySet);
- assertThat(shortcut.getFlags()).isEqualTo(ShortcutInfo.FLAG_LONG_LIVED);
assertThat(shortcut.getActivity()).isEqualTo(activity);
}
}
diff --git a/core/tests/coretests/src/android/view/RenderNodeAnimatorTest.java b/core/tests/coretests/src/android/view/RenderNodeAnimatorTest.java
index 786c22b..9b6bcda 100644
--- a/core/tests/coretests/src/android/view/RenderNodeAnimatorTest.java
+++ b/core/tests/coretests/src/android/view/RenderNodeAnimatorTest.java
@@ -19,17 +19,24 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
import android.app.Activity;
import android.content.Context;
+import android.widget.FrameLayout;
import androidx.test.InstrumentationRegistry;
import androidx.test.annotation.UiThreadTest;
import androidx.test.filters.MediumTest;
import androidx.test.rule.ActivityTestRule;
+import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
@MediumTest
public class RenderNodeAnimatorTest {
@Rule
@@ -57,4 +64,46 @@
anim.start(); // should initialize mTransformationInfo
assertNotNull(view.mTransformationInfo);
}
+
+ @Test
+ public void testViewDetachCancelsRenderNodeAnimator() {
+ // Start a RenderNodeAnimator with a long duration time, then detach the target view
+ // before the animation completes. Detaching of a View from a window should force cancel all
+ // RenderNodeAnimators
+ CountDownLatch latch = new CountDownLatch(1);
+
+ FrameLayout container = new FrameLayout(getContext());
+ View view = new View(getContext());
+
+ getActivity().runOnUiThread(() -> {
+ container.addView(view, new FrameLayout.LayoutParams(100, 100));
+ getActivity().setContentView(container);
+ });
+ getActivity().runOnUiThread(() -> {
+ RenderNodeAnimator anim = new RenderNodeAnimator(0, 0, 10f, 30f);
+ anim.setDuration(10000);
+ anim.setTarget(view);
+ anim.addListener(new AnimatorListenerAdapter() {
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ latch.countDown();
+ }
+ });
+
+ anim.start();
+ });
+
+ getActivity().runOnUiThread(()-> {
+ container.removeView(view);
+ });
+
+ try {
+ Assert.assertTrue("onAnimationEnd not invoked",
+ latch.await(3000, TimeUnit.MILLISECONDS));
+ } catch (InterruptedException excep) {
+ Assert.fail("Interrupted waiting for onAnimationEnd callback");
+ }
+ }
}
diff --git a/core/tests/coretests/src/com/android/internal/app/ResolverWrapperActivity.java b/core/tests/coretests/src/com/android/internal/app/ResolverWrapperActivity.java
index 0c009a0..4cf9c3f 100644
--- a/core/tests/coretests/src/com/android/internal/app/ResolverWrapperActivity.java
+++ b/core/tests/coretests/src/com/android/internal/app/ResolverWrapperActivity.java
@@ -39,6 +39,10 @@
static final OverrideData sOverrides = new OverrideData();
private UsageStatsManager mUsm;
+ public ResolverWrapperActivity() {
+ super(/* isIntentPicker= */ true);
+ }
+
@Override
public ResolverListAdapter createResolverListAdapter(Context context,
List<Intent> payloadIntents, Intent[] initialIntents, List<ResolveInfo> rList,
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
index 87c45dc..d19f9f5 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
@@ -47,6 +47,7 @@
import android.telephony.ModemActivityInfo;
import android.telephony.ServiceState;
import android.telephony.TelephonyManager;
+import android.util.MutableInt;
import android.util.SparseIntArray;
import android.util.SparseLongArray;
import android.view.Display;
@@ -1982,6 +1983,54 @@
expectedTxDurationsMs, bi, state.currentTimeMs);
}
+ @SmallTest
+ @SuppressWarnings("GuardedBy")
+ public void testProcStateSyncScheduling_mobileRadioActiveState() {
+ final MockClock clock = new MockClock(); // holds realtime and uptime in ms
+ final MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clock);
+ final MutableInt lastProcStateChangeFlags = new MutableInt(0);
+
+ MockBatteryStatsImpl.DummyExternalStatsSync externalStatsSync =
+ new MockBatteryStatsImpl.DummyExternalStatsSync() {
+ @Override
+ public void scheduleSyncDueToProcessStateChange(int flags,
+ long delayMillis) {
+ lastProcStateChangeFlags.value = flags;
+ }
+ };
+
+ bi.setDummyExternalStatsSync(externalStatsSync);
+
+ bi.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
+
+ // Note mobile radio is on.
+ long curr = 1000L * (clock.realtime = clock.uptime = 1001);
+ bi.noteMobileRadioPowerStateLocked(DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH, curr,
+ UID);
+
+ lastProcStateChangeFlags.value = 0;
+ clock.realtime = clock.uptime = 2002;
+ bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND);
+
+ final int allProcFlags = BatteryStatsImpl.ExternalStatsSync.UPDATE_ON_PROC_STATE_CHANGE;
+ assertEquals(allProcFlags, lastProcStateChangeFlags.value);
+
+ // Note mobile radio is off.
+ curr = 1000L * (clock.realtime = clock.uptime = 3003);
+ bi.noteMobileRadioPowerStateLocked(DataConnectionRealTimeInfo.DC_POWER_STATE_LOW, curr,
+ UID);
+
+ lastProcStateChangeFlags.value = 0;
+ clock.realtime = clock.uptime = 4004;
+ bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
+
+ final int noRadioProcFlags = BatteryStatsImpl.ExternalStatsSync.UPDATE_ON_PROC_STATE_CHANGE
+ & ~BatteryStatsImpl.ExternalStatsSync.UPDATE_RADIO;
+ assertEquals(
+ "An inactive radio should not be queried on proc state change",
+ noRadioProcFlags, lastProcStateChangeFlags.value);
+ }
+
private void setFgState(int uid, boolean fgOn, MockBatteryStatsImpl bi) {
// Note that noteUidProcessStateLocked uses ActivityManager process states.
if (fgOn) {
diff --git a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
index 00154a3..edeb5e9 100644
--- a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
+++ b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
@@ -212,7 +212,12 @@
return flags;
}
- private class DummyExternalStatsSync implements ExternalStatsSync {
+ public void setDummyExternalStatsSync(DummyExternalStatsSync externalStatsSync) {
+ mExternalStatsSync = externalStatsSync;
+ setExternalStatsSyncLocked(mExternalStatsSync);
+ }
+
+ public static class DummyExternalStatsSync implements ExternalStatsSync {
public int flags = 0;
@Override
@@ -257,8 +262,7 @@
}
@Override
- public Future<?> scheduleSyncDueToProcessStateChange(long delayMillis) {
- return null;
+ public void scheduleSyncDueToProcessStateChange(int flags, long delayMillis) {
}
}
}
diff --git a/data/etc/com.android.systemui.xml b/data/etc/com.android.systemui.xml
index ebf5832..f030d80 100644
--- a/data/etc/com.android.systemui.xml
+++ b/data/etc/com.android.systemui.xml
@@ -80,5 +80,6 @@
<permission name="android.permission.READ_COMPAT_CHANGE_CONFIG" />
<permission name="android.permission.READ_DEVICE_CONFIG" />
<permission name="android.permission.READ_SAFETY_CENTER_STATUS" />
+ <permission name="android.permission.SET_UNRESTRICTED_KEEP_CLEAR_AREAS" />
</privapp-permissions>
</permissions>
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 0054dc4..17f7f31 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -163,6 +163,12 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "-1941440781": {
+ "message": "Creating Pending Move-to-back: %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+ "at": "com\/android\/server\/wm\/Task.java"
+ },
"-1939861963": {
"message": "Create root task displayId=%d winMode=%d",
"level": "VERBOSE",
@@ -469,6 +475,12 @@
"group": "WM_DEBUG_ADD_REMOVE",
"at": "com\/android\/server\/wm\/ResetTargetTaskHelper.java"
},
+ "-1635750891": {
+ "message": "Received remote change for Display[%d], applied: [%dx%d, rot = %d]",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONFIGURATION",
+ "at": "com\/android\/server\/wm\/RemoteDisplayChangeController.java"
+ },
"-1633115609": {
"message": "Key dispatch not paused for screen off",
"level": "VERBOSE",
@@ -757,6 +769,12 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "-1383884640": {
+ "message": " allReady query: used=%b override=%b defer=%d states=[%s]",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+ "at": "com\/android\/server\/wm\/Transition.java"
+ },
"-1376035390": {
"message": "No task found",
"level": "DEBUG",
@@ -2497,6 +2515,12 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "323235828": {
+ "message": "Delaying app transition for recents animation to finish",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_APP_TRANSITIONS",
+ "at": "com\/android\/server\/wm\/AppTransitionController.java"
+ },
"327461496": {
"message": "Complete pause: %s",
"level": "VERBOSE",
@@ -2533,12 +2557,6 @@
"group": "WM_DEBUG_ADD_REMOVE",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
- "352982444": {
- "message": " allReady query: used=%b override=%b states=[%s]",
- "level": "VERBOSE",
- "group": "WM_DEBUG_WINDOW_TRANSITIONS",
- "at": "com\/android\/server\/wm\/Transition.java"
- },
"355720268": {
"message": "stopFreezingDisplayLocked: Unfreezing now",
"level": "DEBUG",
@@ -2917,12 +2935,6 @@
"group": "WM_DEBUG_LOCKTASK",
"at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
},
- "716528224": {
- "message": "Focused window found using wmService.getFocusedWindowLocked()",
- "level": "DEBUG",
- "group": "WM_DEBUG_BACK_PREVIEW",
- "at": "com\/android\/server\/wm\/BackNavigationController.java"
- },
"726205185": {
"message": "Moving to DESTROYED: %s (destroy skipped)",
"level": "VERBOSE",
@@ -3391,12 +3403,6 @@
"group": "WM_DEBUG_BOOT",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
- "1246035185": {
- "message": "stopFreezingDisplayLocked: Returning waitingForConfig=%b, waitingForRemoteRotation=%b, mAppsFreezingScreen=%d, mWindowsFreezingScreen=%d, mClientFreezingScreen=%b, mOpeningApps.size()=%d",
- "level": "DEBUG",
- "group": "WM_DEBUG_ORIENTATION",
- "at": "com\/android\/server\/wm\/WindowManagerService.java"
- },
"1252594551": {
"message": "Window types in WindowContext and LayoutParams.type should match! Type from LayoutParams is %d, but type from WindowContext is %d",
"level": "WARN",
@@ -3493,6 +3499,12 @@
"group": "WM_DEBUG_ORIENTATION",
"at": "com\/android\/server\/wm\/ScreenRotationAnimation.java"
},
+ "1360176455": {
+ "message": "stopFreezingDisplayLocked: Returning waitingForConfig=%b, waitingForRemoteDisplayChange=%b, mAppsFreezingScreen=%d, mWindowsFreezingScreen=%d, mClientFreezingScreen=%b, mOpeningApps.size()=%d",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_ORIENTATION",
+ "at": "com\/android\/server\/wm\/WindowManagerService.java"
+ },
"1364126018": {
"message": "Resumed activity; dropping state of: %s",
"level": "INFO",
@@ -3517,6 +3529,12 @@
"group": "WM_DEBUG_ORIENTATION",
"at": "com\/android\/server\/wm\/TaskDisplayArea.java"
},
+ "1393721079": {
+ "message": "Starting remote display change: from [rot = %d], to [%dx%d, rot = %d]",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONFIGURATION",
+ "at": "com\/android\/server\/wm\/RemoteDisplayChangeController.java"
+ },
"1396893178": {
"message": "createRootTask unknown displayId=%d",
"level": "ERROR",
@@ -3859,6 +3877,12 @@
"group": "WM_DEBUG_ORIENTATION",
"at": "com\/android\/server\/wm\/WindowStateAnimator.java"
},
+ "1764619787": {
+ "message": "Remote change for Display[%d]: timeout reached",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONFIGURATION",
+ "at": "com\/android\/server\/wm\/RemoteDisplayChangeController.java"
+ },
"1774661765": {
"message": "Devices still not ready after waiting %d milliseconds before attempting to detect safe mode.",
"level": "WARN",
diff --git a/graphics/java/android/graphics/RenderNode.java b/graphics/java/android/graphics/RenderNode.java
index 5fd53ad..dadbd8d 100644
--- a/graphics/java/android/graphics/RenderNode.java
+++ b/graphics/java/android/graphics/RenderNode.java
@@ -1611,6 +1611,11 @@
nEndAllAnimators(mNativeRenderNode);
}
+ /** @hide */
+ public void forceEndAnimators() {
+ nForceEndAnimators(mNativeRenderNode);
+ }
+
///////////////////////////////////////////////////////////////////////////
// Regular JNI methods
///////////////////////////////////////////////////////////////////////////
@@ -1633,6 +1638,8 @@
private static native void nEndAllAnimators(long renderNode);
+ private static native void nForceEndAnimators(long renderNode);
+
///////////////////////////////////////////////////////////////////////////
// @CriticalNative methods
///////////////////////////////////////////////////////////////////////////
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreBCWorkaroundProvider.java b/keystore/java/android/security/keystore2/AndroidKeyStoreBCWorkaroundProvider.java
index 9ad6f3a..6fff52a 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreBCWorkaroundProvider.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreBCWorkaroundProvider.java
@@ -206,6 +206,8 @@
putSignatureImpl("NONEwithECDSA",
PACKAGE_NAME + ".AndroidKeyStoreECDSASignatureSpi$NONE");
+ putSignatureImpl("Ed25519",
+ PACKAGE_NAME + ".AndroidKeyStoreECDSASignatureSpi$Ed25519");
putSignatureImpl("SHA1withECDSA", PACKAGE_NAME + ".AndroidKeyStoreECDSASignatureSpi$SHA1");
put("Alg.Alias.Signature.ECDSA", "SHA1withECDSA");
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreECDSASignatureSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreECDSASignatureSpi.java
index 8289671..5216a90 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreECDSASignatureSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreECDSASignatureSpi.java
@@ -29,7 +29,10 @@
import java.io.ByteArrayOutputStream;
import java.security.InvalidKeyException;
import java.security.SignatureSpi;
+import java.security.spec.NamedParameterSpec;
+import java.util.Arrays;
import java.util.List;
+import java.util.Set;
/**
* Base class for {@link SignatureSpi} providing Android KeyStore backed ECDSA signatures.
@@ -37,6 +40,10 @@
* @hide
*/
abstract class AndroidKeyStoreECDSASignatureSpi extends AndroidKeyStoreSignatureSpiBase {
+ private static final Set<String> ACCEPTED_SIGNING_SCHEMES = Set.of(
+ KeyProperties.KEY_ALGORITHM_EC.toLowerCase(),
+ NamedParameterSpec.ED25519.getName().toLowerCase(),
+ "eddsa");
public final static class NONE extends AndroidKeyStoreECDSASignatureSpi {
public NONE() {
@@ -114,6 +121,18 @@
}
}
+ public static final class Ed25519 extends AndroidKeyStoreECDSASignatureSpi {
+ public Ed25519() {
+ // Ed25519 uses an internal digest system.
+ super(KeymasterDefs.KM_DIGEST_NONE);
+ }
+
+ @Override
+ protected String getAlgorithm() {
+ return NamedParameterSpec.ED25519.getName();
+ }
+ }
+
public final static class SHA1 extends AndroidKeyStoreECDSASignatureSpi {
public SHA1() {
super(KeymasterDefs.KM_DIGEST_SHA1);
@@ -174,9 +193,10 @@
@Override
protected final void initKey(AndroidKeyStoreKey key) throws InvalidKeyException {
- if (!KeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(key.getAlgorithm())) {
+ if (!ACCEPTED_SIGNING_SCHEMES.contains(key.getAlgorithm().toLowerCase())) {
throw new InvalidKeyException("Unsupported key algorithm: " + key.getAlgorithm()
- + ". Only" + KeyProperties.KEY_ALGORITHM_EC + " supported");
+ + ". Only" + Arrays.toString(ACCEPTED_SIGNING_SCHEMES.stream().toArray())
+ + " supported");
}
long keySizeBits = -1;
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyAgreementSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyAgreementSpi.java
index fc963a8..b1338d1 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyAgreementSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyAgreementSpi.java
@@ -61,6 +61,17 @@
}
}
+ /**
+ * X25519 key agreement support.
+ *
+ * @hide
+ */
+ public static class XDH extends AndroidKeyStoreKeyAgreementSpi {
+ public XDH() {
+ super(Algorithm.EC);
+ }
+ }
+
private final int mKeymintAlgorithm;
// Fields below are populated by engineInit and should be preserved after engineDoFinal.
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
index 40659f5..cdc1085 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
@@ -712,7 +712,7 @@
case KeymasterDefs.KM_ERROR_HARDWARE_TYPE_UNAVAILABLE:
throw new StrongBoxUnavailableException("Failed to generated key pair.", e);
case ResponseCode.OUT_OF_KEYS:
- throw makeOutOfKeysException(e, securityLevel);
+ return checkIfRetryableOrThrow(e, securityLevel);
default:
ProviderException p = new ProviderException("Failed to generate key pair.", e);
if ((mSpec.getPurposes() & KeyProperties.PURPOSE_WRAP_KEY) != 0) {
@@ -740,7 +740,7 @@
// In case keystore reports OUT_OF_KEYS, call this handler in an attempt to remotely provision
// some keys.
- private ProviderException makeOutOfKeysException(KeyStoreException e, int securityLevel) {
+ GenerateKeyPairHelperResult checkIfRetryableOrThrow(KeyStoreException e, int securityLevel) {
GenerateRkpKey keyGen = new GenerateRkpKey(ActivityThread
.currentApplication());
KeyStoreException ksException;
@@ -757,8 +757,11 @@
rkpStatus = KeyStoreException.RKP_SERVER_REFUSED_ISSUANCE;
break;
case IGenerateRkpKeyService.Status.OK:
- // This will actually retry once immediately, so on "OK" go ahead and return
- // "temporarily unavailable". @see generateKeyPair
+ // Explicitly return not-OK here so we retry in generateKeyPair. All other cases
+ // should throw because a retry doesn't make sense if we didn't actually
+ // provision fresh keys.
+ return new GenerateKeyPairHelperResult(
+ KeyStoreException.RKP_TEMPORARILY_UNAVAILABLE, null);
case IGenerateRkpKeyService.Status.NETWORK_COMMUNICATION_ERROR:
case IGenerateRkpKeyService.Status.HTTP_CLIENT_ERROR:
case IGenerateRkpKeyService.Status.HTTP_SERVER_ERROR:
@@ -781,7 +784,7 @@
KeyStoreException.RKP_TEMPORARILY_UNAVAILABLE);
}
ksException.initCause(e);
- return new ProviderException("Failed to talk to RemoteProvisioner", ksException);
+ throw new ProviderException("Failed to provision new attestation keys.", ksException);
}
private void addAttestationParameters(@NonNull List<KeyParameter> params)
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
index 0355628..9947d34 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
@@ -104,6 +104,7 @@
// javax.crypto.KeyAgreement
put("KeyAgreement.ECDH", PACKAGE_NAME + ".AndroidKeyStoreKeyAgreementSpi$ECDH");
+ put("KeyAgreement.XDH", PACKAGE_NAME + ".AndroidKeyStoreKeyAgreementSpi$XDH");
// java.security.SecretKeyFactory
putSecretKeyFactoryImpl("AES");
@@ -235,8 +236,8 @@
return new AndroidKeyStoreEdECPublicKey(descriptor, metadata, ED25519_OID,
iSecurityLevel, publicKeyEncoded);
} else if (X25519_ALIAS.equalsIgnoreCase(jcaKeyAlgorithm)) {
- //TODO(b/214203951) missing classes in conscrypt
- throw new ProviderException("Curve " + X25519_ALIAS + " not supported yet");
+ return new AndroidKeyStoreXDHPublicKey(descriptor, metadata, X25519_ALIAS,
+ iSecurityLevel, publicKey.getEncoded());
} else {
throw new ProviderException("Unsupported Android Keystore public key algorithm: "
+ jcaKeyAlgorithm);
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreXDHPrivateKey.java b/keystore/java/android/security/keystore2/AndroidKeyStoreXDHPrivateKey.java
new file mode 100644
index 0000000..42589640
--- /dev/null
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreXDHPrivateKey.java
@@ -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 android.security.keystore2;
+
+import android.annotation.NonNull;
+import android.security.KeyStoreSecurityLevel;
+import android.system.keystore2.Authorization;
+import android.system.keystore2.KeyDescriptor;
+
+import java.security.PrivateKey;
+import java.security.interfaces.EdECKey;
+import java.security.spec.NamedParameterSpec;
+
+/**
+ * X25519 Private Key backed by Keystore.
+ * instance of {@link PrivateKey} and {@link EdECKey}
+ *
+ * @hide
+ */
+public class AndroidKeyStoreXDHPrivateKey extends AndroidKeyStorePrivateKey implements EdECKey {
+ public AndroidKeyStoreXDHPrivateKey(
+ @NonNull KeyDescriptor descriptor, long keyId,
+ @NonNull Authorization[] authorizations,
+ @NonNull String algorithm,
+ @NonNull KeyStoreSecurityLevel securityLevel) {
+ super(descriptor, keyId, authorizations, algorithm, securityLevel);
+ }
+
+ @Override
+ public NamedParameterSpec getParams() {
+ return NamedParameterSpec.X25519;
+ }
+}
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreXDHPublicKey.java b/keystore/java/android/security/keystore2/AndroidKeyStoreXDHPublicKey.java
new file mode 100644
index 0000000..9f3df3d
--- /dev/null
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreXDHPublicKey.java
@@ -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 android.security.keystore2;
+
+import android.annotation.NonNull;
+import android.security.KeyStoreSecurityLevel;
+import android.system.keystore2.KeyDescriptor;
+import android.system.keystore2.KeyMetadata;
+
+import java.math.BigInteger;
+import java.security.interfaces.XECPublicKey;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.NamedParameterSpec;
+import java.util.Arrays;
+
+/**
+ * {@link XECPublicKey} backed by keystore.
+ * This class re-implements Conscrypt's OpenSSLX25519PublicKey. The reason is that
+ * OpenSSLX25519PublicKey does not implement XECPublicKey and is not a part of Conscrypt's public
+ * interface so it cannot be referred to.
+ *
+ * So the functionality is duplicated here until (likely Android U) one of the things mentioned
+ * above is fixed.
+ *
+ * @hide
+ */
+public class AndroidKeyStoreXDHPublicKey extends AndroidKeyStorePublicKey implements XECPublicKey {
+ private static final byte[] X509_PREAMBLE = new byte[] {
+ 0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x6e, 0x03, 0x21, 0x00,
+ };
+
+ private static final byte[] X509_PREAMBLE_WITH_NULL = new byte[] {
+ 0x30, 0x2C, 0x30, 0x07, 0x06, 0x03, 0x2B, 0x65, 0x6E, 0x05, 0x00, 0x03, 0x21, 0x00,
+ };
+
+ private static final int X25519_KEY_SIZE_BYTES = 32;
+
+ private final byte[] mEncodedKey;
+ private final int mPreambleLength;
+
+ public AndroidKeyStoreXDHPublicKey(
+ @NonNull KeyDescriptor descriptor,
+ @NonNull KeyMetadata metadata,
+ @NonNull String algorithm,
+ @NonNull KeyStoreSecurityLevel iSecurityLevel,
+ @NonNull byte[] encodedKey) {
+ super(descriptor, metadata, encodedKey, algorithm, iSecurityLevel);
+ mEncodedKey = encodedKey;
+ if (mEncodedKey == null) {
+ throw new IllegalArgumentException("empty encoded key.");
+ }
+
+ mPreambleLength = matchesPreamble(X509_PREAMBLE, mEncodedKey) | matchesPreamble(
+ X509_PREAMBLE_WITH_NULL, mEncodedKey);
+ if (mPreambleLength == 0) {
+ throw new IllegalArgumentException("Key size is not correct size");
+ }
+ }
+
+ private static int matchesPreamble(byte[] preamble, byte[] encoded) {
+ if (encoded.length != (preamble.length + X25519_KEY_SIZE_BYTES)) {
+ return 0;
+ }
+
+ if (Arrays.compare(preamble, 0, preamble.length, encoded, 0, preamble.length) != 0) {
+ return 0;
+ }
+ return preamble.length;
+ }
+
+ @Override
+ AndroidKeyStorePrivateKey getPrivateKey() {
+ return new AndroidKeyStoreXDHPrivateKey(
+ getUserKeyDescriptor(),
+ getKeyIdDescriptor().nspace,
+ getAuthorizations(),
+ "x25519",
+ getSecurityLevel());
+ }
+
+ @Override
+ public BigInteger getU() {
+ return new BigInteger(Arrays.copyOfRange(mEncodedKey, mPreambleLength, mEncodedKey.length));
+ }
+
+ @Override
+ public byte[] getEncoded() {
+ return mEncodedKey.clone();
+ }
+
+ @Override
+ public String getAlgorithm() {
+ return "XDH";
+ }
+
+ @Override
+ public String getFormat() {
+ return "x.509";
+ }
+
+ @Override
+ public AlgorithmParameterSpec getParams() {
+ return NamedParameterSpec.X25519;
+ }
+}
+
diff --git a/libs/WindowManager/Jetpack/src/TEST_MAPPING b/libs/WindowManager/Jetpack/src/TEST_MAPPING
index eacfe25..f8f6400 100644
--- a/libs/WindowManager/Jetpack/src/TEST_MAPPING
+++ b/libs/WindowManager/Jetpack/src/TEST_MAPPING
@@ -28,5 +28,10 @@
}
]
}
+ ],
+ "imports": [
+ {
+ "path": "vendor/google_testing/integration/tests/scenarios/src/android/platform/test/scenario/sysui"
+ }
]
-}
\ No newline at end of file
+}
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 faada1a..015205c 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
@@ -32,6 +32,7 @@
import android.app.ActivityOptions;
import android.app.ActivityThread;
import android.app.Instrumentation;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
@@ -234,13 +235,45 @@
public void onActivityReparentToTask(int taskId, @NonNull Intent activityIntent,
@NonNull IBinder activityToken) {
// If the activity belongs to the current app process, we treat it as a new activity launch.
- final Activity activity = ActivityThread.currentActivityThread().getActivity(activityToken);
+ final Activity activity = getActivity(activityToken);
if (activity != null) {
- onActivityCreated(activity);
+ // We don't allow split as primary for new launch because we currently only support
+ // launching to top. We allow split as primary for activity reparent because the
+ // activity may be split as primary before it is reparented out. In that case, we want
+ // to show it as primary again when it is reparented back.
+ if (!resolveActivityToContainer(activity, true /* canSplitAsPrimary */)) {
+ // When there is no embedding rule matched, try to place it in the top container
+ // like a normal launch.
+ placeActivityInTopContainer(activity);
+ }
updateCallbackIfNecessary();
return;
}
- // TODO: handle for activity in other process.
+
+ final TaskContainer taskContainer = getTaskContainer(taskId);
+ if (taskContainer == null || taskContainer.isInPictureInPicture()) {
+ // We don't embed activity when it is in PIP.
+ return;
+ }
+
+ // If the activity belongs to a different app process, we treat it as starting new intent,
+ // since both actions might result in a new activity that should appear in an organized
+ // TaskFragment.
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+ TaskFragmentContainer targetContainer = resolveStartActivityIntent(wct, taskId,
+ activityIntent, null /* launchingActivity */);
+ if (targetContainer == null) {
+ // When there is no embedding rule matched, try to place it in the top container like a
+ // normal launch.
+ targetContainer = taskContainer.getTopTaskFragmentContainer();
+ }
+ if (targetContainer == null) {
+ return;
+ }
+ wct.reparentActivityToTaskFragment(targetContainer.getTaskFragmentToken(), activityToken);
+ mPresenter.applyTransaction(wct);
+ // Because the activity does not belong to the organizer process, we wait until
+ // onTaskFragmentAppeared to trigger updateCallbackIfNecessary().
}
/** Called on receiving {@link #onTaskFragmentVanished(TaskFragmentInfo)} for cleanup. */
@@ -316,92 +349,244 @@
return false;
}
+ @VisibleForTesting
void onActivityCreated(@NonNull Activity launchedActivity) {
- handleActivityCreated(launchedActivity);
+ // TODO(b/229680885): we don't support launching into primary yet because we want to always
+ // launch the new activity on top.
+ resolveActivityToContainer(launchedActivity, false /* canSplitAsPrimary */);
updateCallbackIfNecessary();
}
/**
- * Checks if the activity start should be routed to a particular container. It can create a new
- * container for the activity and a new split container if necessary.
+ * Checks if the new added activity should be routed to a particular container. It can create a
+ * new container for the activity and a new split container if necessary.
+ * @param launchedActivity the new launched activity.
+ * @param canSplitAsPrimary whether we can put the new launched activity into primary split.
+ * @return {@code true} if the activity was placed in TaskFragment container.
*/
- // TODO(b/190433398): Break down into smaller functions.
- void handleActivityCreated(@NonNull Activity launchedActivity) {
- if (isInPictureInPicture(launchedActivity)) {
- // We don't embed activity when it is in PIP.
- return;
- }
- final List<EmbeddingRule> splitRules = getSplitRules();
- final TaskFragmentContainer currentContainer = getContainerWithActivity(
- launchedActivity.getActivityToken());
-
- // Check if the activity is configured to always be expanded.
- if (shouldExpand(launchedActivity, null, splitRules)) {
- if (shouldContainerBeExpanded(currentContainer)) {
- // Make sure that the existing container is expanded
- mPresenter.expandTaskFragment(currentContainer.getTaskFragmentToken());
- } else {
- // Put activity into a new expanded container
- final TaskFragmentContainer newContainer = newContainer(launchedActivity,
- launchedActivity.getTaskId());
- mPresenter.expandActivity(newContainer.getTaskFragmentToken(),
- launchedActivity);
- }
- return;
+ @VisibleForTesting
+ boolean resolveActivityToContainer(@NonNull Activity launchedActivity,
+ boolean canSplitAsPrimary) {
+ if (isInPictureInPicture(launchedActivity) || launchedActivity.isFinishing()) {
+ // We don't embed activity when it is in PIP, or finishing. Return true since we don't
+ // want any extra handling.
+ return true;
}
- // Check if activity requires a placeholder
+ /*
+ * We will check the following to see if there is any embedding rule matched:
+ * 1. Whether the new launched activity should always expand.
+ * 2. Whether the new launched activity should launch a placeholder.
+ * 3. Whether the new launched activity has already been in a split with a rule matched
+ * (likely done in #onStartActivity).
+ * 4. Whether the activity below (if any) should be split with the new launched activity.
+ * 5. Whether the activity split with the activity below (if any) should be split with the
+ * new launched activity.
+ */
+
+ // 1. Whether the new launched activity should always expand.
+ if (shouldExpand(launchedActivity, null /* intent */)) {
+ expandActivity(launchedActivity);
+ return true;
+ }
+
+ // 2. Whether the new launched activity should launch a placeholder.
if (launchPlaceholderIfNecessary(launchedActivity)) {
- return;
+ return true;
}
- // TODO(b/190433398): Check if it is a placeholder and there is already another split
- // created by the primary activity. This is necessary for the case when the primary activity
- // launched another secondary in the split, but the placeholder was still launched by the
- // logic above. We didn't prevent the placeholder launcher because we didn't know that
- // another secondary activity is coming up.
+ // 3. Whether the new launched activity has already been in a split with a rule matched.
+ if (isNewActivityInSplitWithRuleMatched(launchedActivity)) {
+ return true;
+ }
- // Check if the activity should form a split with the activity below in the same task
- // fragment.
+ // 4. Whether the activity below (if any) should be split with the new launched activity.
+ final Activity activityBelow = findActivityBelow(launchedActivity);
+ if (activityBelow == null) {
+ // Can't find any activity below.
+ return false;
+ }
+ if (putActivitiesIntoSplitIfNecessary(activityBelow, launchedActivity)) {
+ // Have split rule of [ activityBelow | launchedActivity ].
+ return true;
+ }
+ if (canSplitAsPrimary
+ && putActivitiesIntoSplitIfNecessary(launchedActivity, activityBelow)) {
+ // Have split rule of [ launchedActivity | activityBelow].
+ return true;
+ }
+
+ // 5. Whether the activity split with the activity below (if any) should be split with the
+ // new launched activity.
+ final TaskFragmentContainer activityBelowContainer = getContainerWithActivity(
+ activityBelow);
+ final SplitContainer topSplit = getActiveSplitForContainer(activityBelowContainer);
+ if (topSplit == null || !isTopMostSplit(topSplit)) {
+ // Skip if it is not the topmost split.
+ return false;
+ }
+ final TaskFragmentContainer otherTopContainer =
+ topSplit.getPrimaryContainer() == activityBelowContainer
+ ? topSplit.getSecondaryContainer()
+ : topSplit.getPrimaryContainer();
+ final Activity otherTopActivity = otherTopContainer.getTopNonFinishingActivity();
+ if (otherTopActivity == null || otherTopActivity == launchedActivity) {
+ // Can't find the top activity on the other split TaskFragment.
+ return false;
+ }
+ if (putActivitiesIntoSplitIfNecessary(otherTopActivity, launchedActivity)) {
+ // Have split rule of [ otherTopActivity | launchedActivity ].
+ return true;
+ }
+ // Have split rule of [ launchedActivity | otherTopActivity].
+ return canSplitAsPrimary
+ && putActivitiesIntoSplitIfNecessary(launchedActivity, otherTopActivity);
+ }
+
+ /**
+ * Places the given activity to the top most TaskFragment in the task if there is any.
+ */
+ @VisibleForTesting
+ void placeActivityInTopContainer(@NonNull Activity activity) {
+ if (getContainerWithActivity(activity) != null) {
+ // The activity has already been put in a TaskFragment. This is likely to be done by
+ // the server when the activity is started.
+ return;
+ }
+ final int taskId = getTaskId(activity);
+ final TaskContainer taskContainer = getTaskContainer(taskId);
+ if (taskContainer == null) {
+ return;
+ }
+ final TaskFragmentContainer targetContainer = taskContainer.getTopTaskFragmentContainer();
+ if (targetContainer == null) {
+ return;
+ }
+ targetContainer.addPendingAppearedActivity(activity);
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+ wct.reparentActivityToTaskFragment(targetContainer.getTaskFragmentToken(),
+ activity.getActivityToken());
+ mPresenter.applyTransaction(wct);
+ }
+
+ /**
+ * Expands the given activity by either expanding the TaskFragment it is currently in or putting
+ * it into a new expanded TaskFragment.
+ */
+ private void expandActivity(@NonNull Activity activity) {
+ final TaskFragmentContainer container = getContainerWithActivity(activity);
+ if (shouldContainerBeExpanded(container)) {
+ // Make sure that the existing container is expanded.
+ mPresenter.expandTaskFragment(container.getTaskFragmentToken());
+ } else {
+ // Put activity into a new expanded container.
+ final TaskFragmentContainer newContainer = newContainer(activity, getTaskId(activity));
+ mPresenter.expandActivity(newContainer.getTaskFragmentToken(), activity);
+ }
+ }
+
+ /** Whether the given new launched activity is in a split with a rule matched. */
+ private boolean isNewActivityInSplitWithRuleMatched(@NonNull Activity launchedActivity) {
+ final TaskFragmentContainer container = getContainerWithActivity(launchedActivity);
+ final SplitContainer splitContainer = getActiveSplitForContainer(container);
+ if (splitContainer == null) {
+ return false;
+ }
+
+ if (container == splitContainer.getPrimaryContainer()) {
+ // The new launched can be in the primary container when it is starting a new activity
+ // onCreate, thus the secondary may still be empty.
+ final TaskFragmentContainer secondaryContainer = splitContainer.getSecondaryContainer();
+ final Activity secondaryActivity = secondaryContainer.getTopNonFinishingActivity();
+ return secondaryActivity == null
+ || getSplitRule(launchedActivity, secondaryActivity) != null;
+ }
+
+ // Check if the new launched activity is a placeholder.
+ if (splitContainer.getSplitRule() instanceof SplitPlaceholderRule) {
+ final SplitPlaceholderRule placeholderRule =
+ (SplitPlaceholderRule) splitContainer.getSplitRule();
+ final ComponentName placeholderName = placeholderRule.getPlaceholderIntent()
+ .getComponent();
+ // TODO(b/232330767): Do we have a better way to check this?
+ return placeholderName == null
+ || placeholderName.equals(launchedActivity.getComponentName())
+ || placeholderRule.getPlaceholderIntent().equals(launchedActivity.getIntent());
+ }
+
+ // Check if the new launched activity should be split with the primary top activity.
+ final Activity primaryActivity = splitContainer.getPrimaryContainer()
+ .getTopNonFinishingActivity();
+ if (primaryActivity == null) {
+ return false;
+ }
+ /* TODO(b/231845476) we should always respect clearTop.
+ final SplitPairRule curSplitRule = (SplitPairRule) splitContainer.getSplitRule();
+ final SplitPairRule splitRule = getSplitRule(primaryActivity, launchedActivity);
+ return splitRule != null && haveSamePresentation(splitRule, curSplitRule)
+ // If the new launched split rule should clear top and it is not the bottom most,
+ // it means we should create a new split pair and clear the existing secondary.
+ && (!splitRule.shouldClearTop()
+ || container.getBottomMostActivity() == launchedActivity);
+ */
+ return getSplitRule(primaryActivity, launchedActivity) != null;
+ }
+
+ /** Finds the activity below the given activity. */
+ @Nullable
+ private Activity findActivityBelow(@NonNull Activity activity) {
Activity activityBelow = null;
- if (currentContainer != null) {
- final List<Activity> containerActivities = currentContainer.collectActivities();
- final int index = containerActivities.indexOf(launchedActivity);
+ final TaskFragmentContainer container = getContainerWithActivity(activity);
+ if (container != null) {
+ final List<Activity> containerActivities = container.collectActivities();
+ final int index = containerActivities.indexOf(activity);
if (index > 0) {
activityBelow = containerActivities.get(index - 1);
}
}
if (activityBelow == null) {
- IBinder belowToken = ActivityClient.getInstance().getActivityTokenBelow(
- launchedActivity.getActivityToken());
+ final IBinder belowToken = ActivityClient.getInstance().getActivityTokenBelow(
+ activity.getActivityToken());
if (belowToken != null) {
- activityBelow = ActivityThread.currentActivityThread().getActivity(belowToken);
+ activityBelow = getActivity(belowToken);
}
}
- if (activityBelow == null) {
- return;
- }
+ return activityBelow;
+ }
- // Check if the split is already set.
- final TaskFragmentContainer activityBelowContainer = getContainerWithActivity(
- activityBelow.getActivityToken());
- if (currentContainer != null && activityBelowContainer != null) {
- final SplitContainer existingSplit = getActiveSplitForContainers(currentContainer,
- activityBelowContainer);
- if (existingSplit != null) {
- // There is already an active split with the activity below.
- return;
+ /**
+ * Checks if there is a rule to split the two activities. If there is one, puts them into split
+ * and returns {@code true}. Otherwise, returns {@code false}.
+ */
+ private boolean putActivitiesIntoSplitIfNecessary(@NonNull Activity primaryActivity,
+ @NonNull Activity secondaryActivity) {
+ final SplitPairRule splitRule = getSplitRule(primaryActivity, secondaryActivity);
+ if (splitRule == null) {
+ return false;
+ }
+ final TaskFragmentContainer primaryContainer = getContainerWithActivity(
+ primaryActivity);
+ final SplitContainer splitContainer = getActiveSplitForContainer(primaryContainer);
+ if (splitContainer != null && primaryContainer == splitContainer.getPrimaryContainer()
+ && canReuseContainer(splitRule, splitContainer.getSplitRule())) {
+ // Can launch in the existing secondary container if the rules share the same
+ // presentation.
+ final TaskFragmentContainer secondaryContainer = splitContainer.getSecondaryContainer();
+ if (secondaryContainer == getContainerWithActivity(secondaryActivity)) {
+ // The activity is already in the target TaskFragment.
+ return true;
}
+ secondaryContainer.addPendingAppearedActivity(secondaryActivity);
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+ wct.reparentActivityToTaskFragment(
+ secondaryContainer.getTaskFragmentToken(),
+ secondaryActivity.getActivityToken());
+ mPresenter.applyTransaction(wct);
+ return true;
}
-
- final SplitPairRule splitPairRule = getSplitRule(activityBelow, launchedActivity,
- splitRules);
- if (splitPairRule == null) {
- return;
- }
-
- mPresenter.createNewSplitContainer(activityBelow, launchedActivity,
- splitPairRule);
+ // Create new split pair.
+ mPresenter.createNewSplitContainer(primaryActivity, secondaryActivity, splitRule);
+ return true;
}
private void onActivityConfigurationChanged(@NonNull Activity activity) {
@@ -409,8 +594,7 @@
// We don't embed activity when it is in PIP.
return;
}
- final TaskFragmentContainer currentContainer = getContainerWithActivity(
- activity.getActivityToken());
+ final TaskFragmentContainer currentContainer = getContainerWithActivity(activity);
if (currentContainer != null) {
// Changes to activities in controllers are handled in
@@ -422,6 +606,18 @@
launchPlaceholderIfNecessary(activity);
}
+ @VisibleForTesting
+ 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);
+ }
+ // We didn't trigger the callback if there were any pending appeared activities, so check
+ // again after the pending is removed.
+ updateCallbackIfNecessary();
+ }
+
/**
* Called when we have been waiting too long for the TaskFragment to become non-empty after
* creation.
@@ -431,14 +627,149 @@
}
/**
+ * 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.
+ *
+ * @param wct {@link WindowContainerTransaction} including all the window change
+ * requests. The caller is responsible to call
+ * {@link android.window.TaskFragmentOrganizer#applyTransaction}.
+ * @param taskId The Task to start the activity in.
+ * @param intent The {@link Intent} for starting the new launched activity.
+ * @param launchingActivity The {@link Activity} that starts the new activity. We will
+ * prioritize to split the new activity with it if it is not
+ * {@code null}.
+ * @return the {@link TaskFragmentContainer} to start the new activity in. {@code null} if there
+ * is no embedding rule matched.
+ */
+ @VisibleForTesting
+ @Nullable
+ TaskFragmentContainer resolveStartActivityIntent(@NonNull WindowContainerTransaction wct,
+ int taskId, @NonNull Intent intent, @Nullable Activity launchingActivity) {
+ /*
+ * We will check the following to see if there is any embedding rule matched:
+ * 1. Whether the new activity intent should always expand.
+ * 2. Whether the launching activity (if set) should be split with the new activity intent.
+ * 3. Whether the top activity (if any) should be split with the new activity intent.
+ * 4. Whether the top activity (if any) in other split should be split with the new
+ * activity intent.
+ */
+
+ // 1. Whether the new activity intent should always expand.
+ if (shouldExpand(null /* activity */, intent)) {
+ return createEmptyExpandedContainer(wct, taskId, launchingActivity);
+ }
+
+ // 2. Whether the launching activity (if set) should be split with the new activity intent.
+ if (launchingActivity != null) {
+ final TaskFragmentContainer container = getSecondaryContainerForSplitIfAny(wct,
+ launchingActivity, intent, true /* respectClearTop */);
+ if (container != null) {
+ return container;
+ }
+ }
+
+ // 3. Whether the top activity (if any) should be split with the new activity intent.
+ final TaskContainer taskContainer = getTaskContainer(taskId);
+ if (taskContainer == null || taskContainer.getTopTaskFragmentContainer() == null) {
+ // There is no other activity in the Task to check split with.
+ return null;
+ }
+ final TaskFragmentContainer topContainer = taskContainer.getTopTaskFragmentContainer();
+ final Activity topActivity = topContainer.getTopNonFinishingActivity();
+ if (topActivity != null && topActivity != launchingActivity) {
+ final TaskFragmentContainer container = getSecondaryContainerForSplitIfAny(wct,
+ topActivity, intent, false /* respectClearTop */);
+ if (container != null) {
+ return container;
+ }
+ }
+
+ // 4. Whether the top activity (if any) in other split should be split with the new
+ // activity intent.
+ final SplitContainer topSplit = getActiveSplitForContainer(topContainer);
+ if (topSplit == null) {
+ return null;
+ }
+ final TaskFragmentContainer otherTopContainer =
+ topSplit.getPrimaryContainer() == topContainer
+ ? topSplit.getSecondaryContainer()
+ : topSplit.getPrimaryContainer();
+ final Activity otherTopActivity = otherTopContainer.getTopNonFinishingActivity();
+ if (otherTopActivity != null && otherTopActivity != launchingActivity) {
+ return getSecondaryContainerForSplitIfAny(wct, otherTopActivity, intent,
+ false /* respectClearTop */);
+ }
+ return null;
+ }
+
+ /**
+ * Returns an empty expanded {@link TaskFragmentContainer} that we can launch an activity into.
+ */
+ @Nullable
+ private TaskFragmentContainer createEmptyExpandedContainer(
+ @NonNull WindowContainerTransaction wct, int taskId,
+ @Nullable Activity launchingActivity) {
+ // We need an activity in the organizer process in the same Task to use as the owner
+ // activity, as well as to get the Task window info.
+ final Activity activityInTask;
+ if (launchingActivity != null) {
+ activityInTask = launchingActivity;
+ } else {
+ final TaskContainer taskContainer = getTaskContainer(taskId);
+ activityInTask = taskContainer != null
+ ? taskContainer.getTopNonFinishingActivity()
+ : null;
+ }
+ if (activityInTask == null) {
+ // Can't find any activity in the Task that we can use as the owner activity.
+ return null;
+ }
+ final TaskFragmentContainer expandedContainer = newContainer(null /* activity */,
+ activityInTask, taskId);
+ mPresenter.createTaskFragment(wct, expandedContainer.getTaskFragmentToken(),
+ activityInTask.getActivityToken(), new Rect(), WINDOWING_MODE_UNDEFINED);
+ return expandedContainer;
+ }
+
+ /**
+ * Returns a container for the new activity intent to launch into as splitting with the primary
+ * activity.
+ */
+ @Nullable
+ private TaskFragmentContainer getSecondaryContainerForSplitIfAny(
+ @NonNull WindowContainerTransaction wct, @NonNull Activity primaryActivity,
+ @NonNull Intent intent, boolean respectClearTop) {
+ final SplitPairRule splitRule = getSplitRule(primaryActivity, intent);
+ if (splitRule == null) {
+ return null;
+ }
+ final TaskFragmentContainer existingContainer = getContainerWithActivity(primaryActivity);
+ final SplitContainer splitContainer = getActiveSplitForContainer(existingContainer);
+ if (splitContainer != null && existingContainer == splitContainer.getPrimaryContainer()
+ && (canReuseContainer(splitRule, splitContainer.getSplitRule())
+ // TODO(b/231845476) we should always respect clearTop.
+ || !respectClearTop)) {
+ // Can launch in the existing secondary container if the rules share the same
+ // presentation.
+ return splitContainer.getSecondaryContainer();
+ }
+ // Create a new TaskFragment to split with the primary activity for the new activity.
+ return mPresenter.createNewSplitWithEmptySideContainer(wct, primaryActivity, splitRule);
+ }
+
+ /**
* Returns a container that this activity is registered with. An activity can only belong to one
* container, or no container at all.
*/
@Nullable
- TaskFragmentContainer getContainerWithActivity(@NonNull IBinder activityToken) {
+ TaskFragmentContainer getContainerWithActivity(@NonNull Activity activity) {
+ final IBinder activityToken = activity.getActivityToken();
for (int i = mTaskContainers.size() - 1; i >= 0; i--) {
final List<TaskFragmentContainer> containers = mTaskContainers.valueAt(i).mContainers;
- for (TaskFragmentContainer container : containers) {
+ // Traverse from top to bottom in case an activity is added to top pending, and hasn't
+ // received update from server yet.
+ for (int j = containers.size() - 1; j >= 0; j--) {
+ final TaskFragmentContainer container = containers.get(j);
if (container.hasActivity(activityToken)) {
return container;
}
@@ -465,12 +796,12 @@
if (activityInTask == null) {
throw new IllegalArgumentException("activityInTask must not be null,");
}
- final TaskFragmentContainer container = new TaskFragmentContainer(activity, taskId, this);
if (!mTaskContainers.contains(taskId)) {
mTaskContainers.put(taskId, new TaskContainer(taskId));
}
final TaskContainer taskContainer = mTaskContainers.get(taskId);
- taskContainer.mContainers.add(container);
+ final TaskFragmentContainer container = new TaskFragmentContainer(activity, taskContainer,
+ this);
if (!taskContainer.isTaskBoundsInitialized()) {
// Get the initial bounds before the TaskFragment has appeared.
final Rect taskBounds = SplitPresenter.getTaskBoundsFromActivity(activityInTask);
@@ -500,14 +831,13 @@
if (splitRule instanceof SplitPairRule && ((SplitPairRule) splitRule).shouldClearTop()) {
removeExistingSecondaryContainers(wct, primaryContainer);
}
- mTaskContainers.get(primaryContainer.getTaskId()).mSplitContainers.add(splitContainer);
+ primaryContainer.getTaskContainer().mSplitContainers.add(splitContainer);
}
/** Cleanups all the dependencies when the TaskFragment is entering PIP. */
private void cleanupForEnterPip(@NonNull WindowContainerTransaction wct,
@NonNull TaskFragmentContainer container) {
- final int taskId = container.getTaskId();
- final TaskContainer taskContainer = mTaskContainers.get(taskId);
+ final TaskContainer taskContainer = container.getTaskContainer();
if (taskContainer == null) {
return;
}
@@ -545,8 +875,7 @@
*/
void removeContainer(@NonNull TaskFragmentContainer container) {
// Remove all split containers that included this one
- final int taskId = container.getTaskId();
- final TaskContainer taskContainer = mTaskContainers.get(taskId);
+ final TaskContainer taskContainer = container.getTaskContainer();
if (taskContainer == null) {
return;
}
@@ -637,9 +966,7 @@
if (splitContainer == null) {
return;
}
- final List<SplitContainer> splitContainers = mTaskContainers.get(container.getTaskId())
- .mSplitContainers;
- if (splitContainer != splitContainers.get(splitContainers.size() - 1)) {
+ if (!isTopMostSplit(splitContainer)) {
// Skip position update - it isn't the topmost split.
return;
}
@@ -655,13 +982,22 @@
mPresenter.updateSplitContainer(splitContainer, container, wct);
}
+ /** Whether the given split is the topmost split in the Task. */
+ private boolean isTopMostSplit(@NonNull SplitContainer splitContainer) {
+ final List<SplitContainer> splitContainers = splitContainer.getPrimaryContainer()
+ .getTaskContainer().mSplitContainers;
+ return splitContainer == splitContainers.get(splitContainers.size() - 1);
+ }
+
/**
* Returns the top active split container that has the provided container, if available.
*/
@Nullable
- private SplitContainer getActiveSplitForContainer(@NonNull TaskFragmentContainer container) {
- final List<SplitContainer> splitContainers = mTaskContainers.get(container.getTaskId())
- .mSplitContainers;
+ private SplitContainer getActiveSplitForContainer(@Nullable TaskFragmentContainer container) {
+ if (container == null) {
+ return null;
+ }
+ final List<SplitContainer> splitContainers = container.getTaskContainer().mSplitContainers;
if (splitContainers.isEmpty()) {
return null;
}
@@ -679,15 +1015,13 @@
* Returns the active split that has the provided containers as primary and secondary or as
* secondary and primary, if available.
*/
+ @VisibleForTesting
@Nullable
- private SplitContainer getActiveSplitForContainers(
+ SplitContainer getActiveSplitForContainers(
@NonNull TaskFragmentContainer firstContainer,
@NonNull TaskFragmentContainer secondContainer) {
- final List<SplitContainer> splitContainers = mTaskContainers.get(firstContainer.getTaskId())
+ final List<SplitContainer> splitContainers = firstContainer.getTaskContainer()
.mSplitContainers;
- if (splitContainers == null) {
- return null;
- }
for (int i = splitContainers.size() - 1; i >= 0; i--) {
final SplitContainer splitContainer = splitContainers.get(i);
final TaskFragmentContainer primary = splitContainer.getPrimaryContainer();
@@ -713,15 +1047,13 @@
}
boolean launchPlaceholderIfNecessary(@NonNull Activity activity) {
- final TaskFragmentContainer container = getContainerWithActivity(
- activity.getActivityToken());
+ final TaskFragmentContainer container = getContainerWithActivity(activity);
// Don't launch placeholder if the container is occluded.
if (container != null && container != getTopActiveContainer(container.getTaskId())) {
return false;
}
- SplitContainer splitContainer = container != null ? getActiveSplitForContainer(container)
- : null;
+ final SplitContainer splitContainer = getActiveSplitForContainer(container);
if (splitContainer != null && container.equals(splitContainer.getPrimaryContainer())) {
// Don't launch placeholder in primary split container
return false;
@@ -856,18 +1188,7 @@
if (container == null) {
return false;
}
- final List<SplitContainer> splitContainers = mTaskContainers.get(container.getTaskId())
- .mSplitContainers;
- if (splitContainers == null) {
- return true;
- }
- for (SplitContainer splitContainer : splitContainers) {
- if (container.equals(splitContainer.getPrimaryContainer())
- || container.equals(splitContainer.getSecondaryContainer())) {
- return false;
- }
- }
- return true;
+ return getActiveSplitForContainer(container) == null;
}
/**
@@ -875,9 +1196,9 @@
* if available.
*/
@Nullable
- private static SplitPairRule getSplitRule(@NonNull Activity primaryActivity,
- @NonNull Intent secondaryActivityIntent, @NonNull List<EmbeddingRule> splitRules) {
- for (EmbeddingRule rule : splitRules) {
+ private SplitPairRule getSplitRule(@NonNull Activity primaryActivity,
+ @NonNull Intent secondaryActivityIntent) {
+ for (EmbeddingRule rule : mSplitRules) {
if (!(rule instanceof SplitPairRule)) {
continue;
}
@@ -893,9 +1214,9 @@
* Returns a split rule for the provided pair of primary and secondary activities if available.
*/
@Nullable
- private static SplitPairRule getSplitRule(@NonNull Activity primaryActivity,
- @NonNull Activity secondaryActivity, @NonNull List<EmbeddingRule> splitRules) {
- for (EmbeddingRule rule : splitRules) {
+ private SplitPairRule getSplitRule(@NonNull Activity primaryActivity,
+ @NonNull Activity secondaryActivity) {
+ for (EmbeddingRule rule : mSplitRules) {
if (!(rule instanceof SplitPairRule)) {
continue;
}
@@ -932,16 +1253,24 @@
return mHandler;
}
+ int getTaskId(@NonNull Activity activity) {
+ // Prefer to get the taskId from TaskFragmentContainer because Activity.getTaskId() is an
+ // IPC call.
+ final TaskFragmentContainer container = getContainerWithActivity(activity);
+ return container != null ? container.getTaskId() : activity.getTaskId();
+ }
+
+ @Nullable
+ Activity getActivity(@NonNull IBinder activityToken) {
+ return ActivityThread.currentActivityThread().getActivity(activityToken);
+ }
+
/**
* Returns {@code true} if an Activity with the provided component name should always be
* expanded to occupy full task bounds. Such activity must not be put in a split.
*/
- private static boolean shouldExpand(@Nullable Activity activity, @Nullable Intent intent,
- List<EmbeddingRule> splitRules) {
- if (splitRules == null) {
- return false;
- }
- for (EmbeddingRule rule : splitRules) {
+ private boolean shouldExpand(@Nullable Activity activity, @Nullable Intent intent) {
+ for (EmbeddingRule rule : mSplitRules) {
if (!(rule instanceof ActivityRule)) {
continue;
}
@@ -995,8 +1324,8 @@
*/
boolean shouldRetainAssociatedActivity(@NonNull TaskFragmentContainer finishingContainer,
@NonNull Activity associatedActivity) {
- TaskFragmentContainer associatedContainer = getContainerWithActivity(
- associatedActivity.getActivityToken());
+ final TaskFragmentContainer associatedContainer = getContainerWithActivity(
+ associatedActivity);
if (associatedContainer == null) {
return false;
}
@@ -1046,6 +1375,11 @@
public void onActivityConfigurationChanged(Activity activity) {
SplitController.this.onActivityConfigurationChanged(activity);
}
+
+ @Override
+ public void onActivityPostDestroyed(Activity activity) {
+ SplitController.this.onActivityDestroyed(activity);
+ }
}
/** Executor that posts on the main application thread. */
@@ -1079,130 +1413,20 @@
return super.onStartActivity(who, intent, options);
}
- if (shouldExpand(null, intent, getSplitRules())) {
- setLaunchingInExpandedContainer(launchingActivity, options);
- } else if (!splitWithLaunchingActivity(launchingActivity, intent, options)) {
- setLaunchingInSameSideContainer(launchingActivity, intent, options);
+ final int taskId = getTaskId(launchingActivity);
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+ final TaskFragmentContainer launchedInTaskFragment = resolveStartActivityIntent(wct,
+ taskId, intent, launchingActivity);
+ if (launchedInTaskFragment != null) {
+ mPresenter.applyTransaction(wct);
+ // Amend the request to let the WM know that the activity should be placed in the
+ // dedicated container.
+ options.putBinder(ActivityOptions.KEY_LAUNCH_TASK_FRAGMENT_TOKEN,
+ launchedInTaskFragment.getTaskFragmentToken());
}
return super.onStartActivity(who, intent, options);
}
-
- private void setLaunchingInExpandedContainer(Activity launchingActivity, Bundle options) {
- TaskFragmentContainer newContainer = mPresenter.createNewExpandedContainer(
- launchingActivity);
-
- // Amend the request to let the WM know that the activity should be placed in the
- // dedicated container.
- options.putBinder(ActivityOptions.KEY_LAUNCH_TASK_FRAGMENT_TOKEN,
- newContainer.getTaskFragmentToken());
- }
-
- /**
- * Returns {@code true} if the activity that is going to be started via the
- * {@code intent} should be paired with the {@code launchingActivity} and is set to be
- * launched in the side container.
- */
- private boolean splitWithLaunchingActivity(Activity launchingActivity, Intent intent,
- Bundle options) {
- final SplitPairRule splitPairRule = getSplitRule(launchingActivity, intent,
- getSplitRules());
- if (splitPairRule == null) {
- return false;
- }
-
- // Check if there is any existing side container to launch into.
- TaskFragmentContainer secondaryContainer = findSideContainerForNewLaunch(
- launchingActivity, splitPairRule);
- if (secondaryContainer == null) {
- // Create a new split with an empty side container.
- secondaryContainer = mPresenter
- .createNewSplitWithEmptySideContainer(launchingActivity, splitPairRule);
- }
-
- // Amend the request to let the WM know that the activity should be placed in the
- // dedicated container.
- options.putBinder(ActivityOptions.KEY_LAUNCH_TASK_FRAGMENT_TOKEN,
- secondaryContainer.getTaskFragmentToken());
- return true;
- }
-
- /**
- * Finds if there is an existing split side {@link TaskFragmentContainer} that can be used
- * for the new rule.
- */
- @Nullable
- private TaskFragmentContainer findSideContainerForNewLaunch(Activity launchingActivity,
- SplitPairRule splitPairRule) {
- final TaskFragmentContainer launchingContainer = getContainerWithActivity(
- launchingActivity.getActivityToken());
- if (launchingContainer == null) {
- return null;
- }
-
- // We only check if the launching activity is the primary of the split. We will check
- // if the launching activity is the secondary in #setLaunchingInSameSideContainer.
- final SplitContainer splitContainer = getActiveSplitForContainer(launchingContainer);
- if (splitContainer == null
- || splitContainer.getPrimaryContainer() != launchingContainer) {
- return null;
- }
-
- if (canReuseContainer(splitPairRule, splitContainer.getSplitRule())) {
- return splitContainer.getSecondaryContainer();
- }
- return null;
- }
-
- /**
- * Checks if the activity that is going to be started via the {@code intent} should be
- * paired with the existing top activity which is currently paired with the
- * {@code launchingActivity}. If so, set the activity to be launched in the same side
- * container of the {@code launchingActivity}.
- */
- private void setLaunchingInSameSideContainer(Activity launchingActivity, Intent intent,
- Bundle options) {
- final TaskFragmentContainer launchingContainer = getContainerWithActivity(
- launchingActivity.getActivityToken());
- if (launchingContainer == null) {
- return;
- }
-
- final SplitContainer splitContainer = getActiveSplitForContainer(launchingContainer);
- if (splitContainer == null) {
- return;
- }
-
- if (splitContainer.getSecondaryContainer() != launchingContainer) {
- return;
- }
-
- // The launching activity is on the secondary container. Retrieve the primary
- // activity from the other container.
- Activity primaryActivity =
- splitContainer.getPrimaryContainer().getTopNonFinishingActivity();
- if (primaryActivity == null) {
- return;
- }
-
- final SplitPairRule splitPairRule = getSplitRule(primaryActivity, intent,
- getSplitRules());
- if (splitPairRule == null) {
- return;
- }
-
- // Can only launch in the same container if the rules share the same presentation.
- if (!canReuseContainer(splitPairRule, splitContainer.getSplitRule())) {
- return;
- }
-
- // Amend the request to let the WM know that the activity should be placed in the
- // dedicated container. This is necessary for the case that the activity is started
- // into a new Task, or new Task will be escaped from the current host Task and be
- // displayed in fullscreen.
- options.putBinder(ActivityOptions.KEY_LAUNCH_TASK_FRAGMENT_TOKEN,
- launchingContainer.getTaskFragmentToken());
- }
}
/**
@@ -1222,8 +1446,18 @@
if (!isContainerReusableRule(rule1) || !isContainerReusableRule(rule2)) {
return false;
}
+ return haveSamePresentation((SplitPairRule) rule1, (SplitPairRule) rule2);
+ }
+
+ /** Whether the two rules have the same presentation. */
+ private static boolean haveSamePresentation(SplitPairRule rule1, SplitPairRule rule2) {
+ // TODO(b/231655482): add util method to do the comparison in SplitPairRule.
return rule1.getSplitRatio() == rule2.getSplitRatio()
- && rule1.getLayoutDirection() == rule2.getLayoutDirection();
+ && rule1.getLayoutDirection() == rule2.getLayoutDirection()
+ && rule1.getFinishPrimaryWithSecondary()
+ == rule2.getFinishPrimaryWithSecondary()
+ && rule1.getFinishSecondaryWithPrimary()
+ == rule2.getFinishSecondaryWithPrimary();
}
/**
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
index 06c1d4e..43d0402 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
@@ -16,8 +16,6 @@
package androidx.window.extensions.embedding;
-import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
-
import android.app.Activity;
import android.app.WindowConfiguration;
import android.app.WindowConfiguration.WindowingMode;
@@ -100,10 +98,10 @@
* Creates a new split with the primary activity and an empty secondary container.
* @return The newly created secondary container.
*/
- TaskFragmentContainer createNewSplitWithEmptySideContainer(@NonNull Activity primaryActivity,
+ @NonNull
+ TaskFragmentContainer createNewSplitWithEmptySideContainer(
+ @NonNull WindowContainerTransaction wct, @NonNull Activity primaryActivity,
@NonNull SplitPairRule rule) {
- final WindowContainerTransaction wct = new WindowContainerTransaction();
-
final Rect parentBounds = getParentContainerBounds(primaryActivity);
final Rect primaryRectBounds = getBoundsForPosition(POSITION_START, parentBounds, rule,
isLtr(primaryActivity, rule));
@@ -127,8 +125,6 @@
mController.registerSplit(wct, primaryContainer, primaryActivity, secondaryContainer, rule);
- applyTransaction(wct);
-
return secondaryContainer;
}
@@ -155,8 +151,15 @@
final Rect secondaryRectBounds = getBoundsForPosition(POSITION_END, parentBounds, rule,
isLtr(primaryActivity, rule));
+ final TaskFragmentContainer curSecondaryContainer = mController.getContainerWithActivity(
+ secondaryActivity);
+ TaskFragmentContainer containerToAvoid = primaryContainer;
+ if (rule.shouldClearTop() && curSecondaryContainer != null) {
+ // Do not reuse the current TaskFragment if the rule is to clear top.
+ containerToAvoid = curSecondaryContainer;
+ }
final TaskFragmentContainer secondaryContainer = prepareContainerForActivity(wct,
- secondaryActivity, secondaryRectBounds, primaryContainer);
+ secondaryActivity, secondaryRectBounds, containerToAvoid);
// Set adjacent to each other so that the containers below will be invisible.
setAdjacentTaskFragments(wct, primaryContainer, secondaryContainer, rule);
@@ -167,21 +170,6 @@
}
/**
- * Creates a new expanded container.
- */
- TaskFragmentContainer createNewExpandedContainer(@NonNull Activity launchingActivity) {
- final TaskFragmentContainer newContainer = mController.newContainer(null /* activity */,
- launchingActivity, launchingActivity.getTaskId());
-
- final WindowContainerTransaction wct = new WindowContainerTransaction();
- createTaskFragment(wct, newContainer.getTaskFragmentToken(),
- launchingActivity.getActivityToken(), new Rect(), WINDOWING_MODE_UNDEFINED);
-
- applyTransaction(wct);
- return newContainer;
- }
-
- /**
* Creates a new container or resizes an existing container for activity to the provided bounds.
* @param activity The activity to be re-parented to the container if necessary.
* @param containerToAvoid Re-parent from this container if an activity is already in it.
@@ -189,8 +177,7 @@
private TaskFragmentContainer prepareContainerForActivity(
@NonNull WindowContainerTransaction wct, @NonNull Activity activity,
@NonNull Rect bounds, @Nullable TaskFragmentContainer containerToAvoid) {
- TaskFragmentContainer container = mController.getContainerWithActivity(
- activity.getActivityToken());
+ TaskFragmentContainer container = mController.getContainerWithActivity(activity);
final int taskId = container != null ? container.getTaskId() : activity.getTaskId();
if (container == null || container == containerToAvoid) {
container = mController.newContainer(activity, taskId);
@@ -230,7 +217,7 @@
isLtr(launchingActivity, rule));
TaskFragmentContainer primaryContainer = mController.getContainerWithActivity(
- launchingActivity.getActivityToken());
+ launchingActivity);
if (primaryContainer == null) {
primaryContainer = mController.newContainer(launchingActivity,
launchingActivity.getTaskId());
@@ -291,8 +278,7 @@
// When placeholder is shown in split, we should keep the focus on the primary.
wct.requestFocusOnTaskFragment(primaryContainer.getTaskFragmentToken());
}
- final TaskContainer taskContainer = mController.getTaskContainer(
- updatedContainer.getTaskId());
+ final TaskContainer taskContainer = updatedContainer.getTaskContainer();
final int windowingMode = taskContainer.getWindowingModeForSplitTaskFragment(
primaryRectBounds);
updateTaskFragmentWindowingModeIfRegistered(wct, primaryContainer, windowingMode);
@@ -456,18 +442,12 @@
@NonNull
Rect getParentContainerBounds(@NonNull TaskFragmentContainer container) {
- final int taskId = container.getTaskId();
- final TaskContainer taskContainer = mController.getTaskContainer(taskId);
- if (taskContainer == null) {
- throw new IllegalStateException("Can't find TaskContainer taskId=" + taskId);
- }
- return taskContainer.getTaskBounds();
+ return container.getTaskContainer().getTaskBounds();
}
@NonNull
Rect getParentContainerBounds(@NonNull Activity activity) {
- final TaskFragmentContainer container = mController.getContainerWithActivity(
- activity.getActivityToken());
+ final TaskFragmentContainer container = mController.getContainerWithActivity(activity);
if (container != null) {
return getParentContainerBounds(container);
}
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 5762843..0ea5603 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
@@ -16,12 +16,14 @@
package androidx.window.extensions.embedding;
+import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.Activity;
import android.app.WindowConfiguration;
import android.app.WindowConfiguration.WindowingMode;
import android.graphics.Rect;
@@ -62,6 +64,9 @@
final Set<IBinder> mFinishedContainer = new ArraySet<>();
TaskContainer(int taskId) {
+ if (taskId == INVALID_TASK_ID) {
+ throw new IllegalArgumentException("Invalid Task id");
+ }
mTaskId = taskId;
}
@@ -130,4 +135,30 @@
boolean isEmpty() {
return mContainers.isEmpty() && mFinishedContainer.isEmpty();
}
+
+ /** Removes the pending appeared activity from all TaskFragments in this Task. */
+ void cleanupPendingAppearedActivity(@NonNull Activity pendingAppearedActivity) {
+ for (TaskFragmentContainer container : mContainers) {
+ container.removePendingAppearedActivity(pendingAppearedActivity);
+ }
+ }
+
+ @Nullable
+ TaskFragmentContainer getTopTaskFragmentContainer() {
+ if (mContainers.isEmpty()) {
+ return null;
+ }
+ return mContainers.get(mContainers.size() - 1);
+ }
+
+ @Nullable
+ Activity getTopNonFinishingActivity() {
+ for (int i = mContainers.size() - 1; i >= 0; i--) {
+ final Activity activity = mContainers.get(i).getTopNonFinishingActivity();
+ if (activity != null) {
+ return activity;
+ }
+ }
+ return null;
+ }
}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationAdapter.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationAdapter.java
index b3becad..cdee9e3 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationAdapter.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationAdapter.java
@@ -17,6 +17,8 @@
package androidx.window.extensions.embedding;
import static android.graphics.Matrix.MSCALE_X;
+import static android.graphics.Matrix.MTRANS_X;
+import static android.graphics.Matrix.MTRANS_Y;
import android.graphics.Rect;
import android.view.Choreographer;
@@ -96,22 +98,20 @@
mTarget.localBounds.left, mTarget.localBounds.top);
t.setMatrix(mLeash, mTransformation.getMatrix(), mMatrix);
t.setAlpha(mLeash, mTransformation.getAlpha());
-
- // Open/close animation may scale up the surface. Apply an inverse scale to the window crop
- // so that it will not be covering other windows.
- mVecs[1] = mVecs[2] = 0;
- mVecs[0] = mVecs[3] = 1;
- mTransformation.getMatrix().mapVectors(mVecs);
- mVecs[0] = 1.f / mVecs[0];
- mVecs[3] = 1.f / mVecs[3];
- final Rect clipRect = mTarget.localBounds;
- mRect.left = (int) (clipRect.left * mVecs[0] + 0.5f);
- mRect.right = (int) (clipRect.right * mVecs[0] + 0.5f);
- mRect.top = (int) (clipRect.top * mVecs[3] + 0.5f);
- mRect.bottom = (int) (clipRect.bottom * mVecs[3] + 0.5f);
- mRect.offsetTo(Math.round(mTarget.localBounds.width() * (1 - mVecs[0]) / 2.f),
- Math.round(mTarget.localBounds.height() * (1 - mVecs[3]) / 2.f));
- t.setWindowCrop(mLeash, mRect);
+ // Get current animation position.
+ final int positionX = Math.round(mMatrix[MTRANS_X]);
+ final int positionY = Math.round(mMatrix[MTRANS_Y]);
+ // The exiting surface starts at position: mTarget.localBounds and moves with
+ // positionX varying. Offset our crop region by the amount we have slided so crop
+ // regions stays exactly on the original container in split.
+ final int cropOffsetX = mTarget.localBounds.left - positionX;
+ final int cropOffsetY = mTarget.localBounds.top - positionY;
+ final Rect cropRect = new Rect();
+ cropRect.set(mTarget.localBounds);
+ // Because window crop uses absolute position.
+ cropRect.offsetTo(0, 0);
+ cropRect.offset(cropOffsetX, cropOffsetY);
+ t.setCrop(mLeash, cropRect);
}
/** Called after animation finished. */
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 26bbcbb..26ddae4 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
@@ -16,13 +16,11 @@
package androidx.window.extensions.embedding;
-import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Activity;
-import android.app.ActivityThread;
import android.app.WindowConfiguration.WindowingMode;
import android.graphics.Rect;
import android.os.Binder;
@@ -52,8 +50,9 @@
@NonNull
private final IBinder mToken;
- /** Parent leaf Task id. */
- private final int mTaskId;
+ /** Parent leaf Task. */
+ @NonNull
+ private final TaskContainer mTaskContainer;
/**
* Server-provided task fragment information.
@@ -100,14 +99,12 @@
* Creates a container with an existing activity that will be re-parented to it in a window
* container transaction.
*/
- TaskFragmentContainer(@Nullable Activity activity, int taskId,
+ TaskFragmentContainer(@Nullable Activity activity, @NonNull TaskContainer taskContainer,
@NonNull SplitController controller) {
mController = controller;
mToken = new Binder("TaskFragmentContainer");
- if (taskId == INVALID_TASK_ID) {
- throw new IllegalArgumentException("Invalid Task id");
- }
- mTaskId = taskId;
+ mTaskContainer = taskContainer;
+ taskContainer.mContainers.add(this);
if (activity != null) {
addPendingAppearedActivity(activity);
}
@@ -124,21 +121,24 @@
/** List of activities that belong to this container and live in this process. */
@NonNull
List<Activity> collectActivities() {
+ final List<Activity> allActivities = new ArrayList<>();
+ if (mInfo != null) {
+ // Add activities reported from the server.
+ for (IBinder token : mInfo.getActivities()) {
+ final Activity activity = mController.getActivity(token);
+ if (activity != null && !activity.isFinishing()) {
+ allActivities.add(activity);
+ }
+ }
+ }
+
// Add the re-parenting activity, in case the server has not yet reported the task
// fragment info update with it placed in this container. We still want to apply rules
// in this intermediate state.
- List<Activity> allActivities = new ArrayList<>();
- if (!mPendingAppearedActivities.isEmpty()) {
- allActivities.addAll(mPendingAppearedActivities);
- }
- // Add activities reported from the server.
- if (mInfo == null) {
- return allActivities;
- }
- ActivityThread activityThread = ActivityThread.currentActivityThread();
- for (IBinder token : mInfo.getActivities()) {
- Activity activity = activityThread.getActivity(token);
- if (activity != null && !activity.isFinishing() && !allActivities.contains(activity)) {
+ // Place those on top of the list since they will be on the top after reported from the
+ // server.
+ for (Activity activity : mPendingAppearedActivities) {
+ if (!activity.isFinishing()) {
allActivities.add(activity);
}
}
@@ -162,9 +162,18 @@
}
void addPendingAppearedActivity(@NonNull Activity pendingAppearedActivity) {
+ if (hasActivity(pendingAppearedActivity.getActivityToken())) {
+ return;
+ }
+ // Remove the pending activity from other TaskFragments.
+ mTaskContainer.cleanupPendingAppearedActivity(pendingAppearedActivity);
mPendingAppearedActivities.add(pendingAppearedActivity);
}
+ void removePendingAppearedActivity(@NonNull Activity pendingAppearedActivity) {
+ mPendingAppearedActivities.remove(pendingAppearedActivity);
+ }
+
boolean hasActivity(@NonNull IBinder token) {
if (mInfo != null && mInfo.getActivities().contains(token)) {
return true;
@@ -236,6 +245,12 @@
return i >= 0 ? activities.get(i) : null;
}
+ @Nullable
+ Activity getBottomMostActivity() {
+ final List<Activity> activities = collectActivities();
+ return activities.isEmpty() ? null : activities.get(0);
+ }
+
boolean isEmpty() {
return mPendingAppearedActivities.isEmpty() && (mInfo == null || mInfo.isEmpty());
}
@@ -376,7 +391,13 @@
/** Gets the parent leaf Task id. */
int getTaskId() {
- return mTaskId;
+ return mTaskContainer.getTaskId();
+ }
+
+ /** Gets the parent Task. */
+ @NonNull
+ TaskContainer getTaskContainer() {
+ return mTaskContainer;
}
@Override
@@ -392,6 +413,7 @@
*/
private String toString(boolean includeContainersToFinishOnExit) {
return "TaskFragmentContainer{"
+ + " parentTaskId=" + getTaskId()
+ " token=" + mToken
+ " topNonFinishingActivity=" + getTopNonFinishingActivity()
+ " runningActivityCount=" + getRunningActivityCount()
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java
index 7aa47ef..792a531 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java
@@ -113,8 +113,9 @@
@Test
public void testExpandTaskFragment() {
+ final TaskContainer taskContainer = new TaskContainer(TASK_ID);
final TaskFragmentContainer container = new TaskFragmentContainer(null /* activity */,
- TASK_ID, mSplitController);
+ taskContainer, mSplitController);
final TaskFragmentInfo info = createMockInfo(container);
mOrganizer.mFragmentInfos.put(container.getTaskFragmentToken(), info);
container.setInfo(info);
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 983208c..353c7df 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
@@ -16,28 +16,46 @@
package androidx.window.extensions.embedding;
+import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.google.common.truth.Truth.assertWithMessage;
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.assertThrows;
+import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
+import android.annotation.NonNull;
import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Intent;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.graphics.Point;
import android.graphics.Rect;
+import android.os.Binder;
import android.os.Handler;
+import android.os.IBinder;
import android.platform.test.annotations.Presubmit;
+import android.util.Pair;
import android.window.TaskFragmentInfo;
+import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -50,6 +68,7 @@
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
/**
@@ -64,8 +83,10 @@
public class SplitControllerTest {
private static final int TASK_ID = 10;
private static final Rect TASK_BOUNDS = new Rect(0, 0, 600, 1200);
+ private static final float SPLIT_RATIO = 0.5f;
+ private static final Intent PLACEHOLDER_INTENT = new Intent().setComponent(
+ new ComponentName("test", "placeholder"));
- @Mock
private Activity mActivity;
@Mock
private Resources mActivityResources;
@@ -86,30 +107,29 @@
mSplitPresenter = mSplitController.mPresenter;
spyOn(mSplitController);
spyOn(mSplitPresenter);
+ doNothing().when(mSplitPresenter).applyTransaction(any());
final Configuration activityConfig = new Configuration();
activityConfig.windowConfiguration.setBounds(TASK_BOUNDS);
activityConfig.windowConfiguration.setMaxBounds(TASK_BOUNDS);
- doReturn(mActivityResources).when(mActivity).getResources();
doReturn(activityConfig).when(mActivityResources).getConfiguration();
doReturn(mHandler).when(mSplitController).getHandler();
+ mActivity = createMockActivity();
}
@Test
public void testGetTopActiveContainer() {
- TaskContainer taskContainer = new TaskContainer(TASK_ID);
+ final TaskContainer taskContainer = new TaskContainer(TASK_ID);
+ // tf1 has no running activity so is not active.
+ final TaskFragmentContainer tf1 = new TaskFragmentContainer(null /* activity */,
+ taskContainer, mSplitController);
+ // tf2 has running activity so is active.
+ final TaskFragmentContainer tf2 = mock(TaskFragmentContainer.class);
+ doReturn(1).when(tf2).getRunningActivityCount();
+ taskContainer.mContainers.add(tf2);
// tf3 is finished so is not active.
- TaskFragmentContainer tf3 = mock(TaskFragmentContainer.class);
+ final TaskFragmentContainer tf3 = mock(TaskFragmentContainer.class);
doReturn(true).when(tf3).isFinished();
doReturn(false).when(tf3).isWaitingActivityAppear();
- // tf2 has running activity so is active.
- TaskFragmentContainer tf2 = mock(TaskFragmentContainer.class);
- doReturn(1).when(tf2).getRunningActivityCount();
- // tf1 has no running activity so is not active.
- TaskFragmentContainer tf1 = new TaskFragmentContainer(null /* activity */, TASK_ID,
- mSplitController);
-
- taskContainer.mContainers.add(tf1);
- taskContainer.mContainers.add(tf2);
taskContainer.mContainers.add(tf3);
mSplitController.mTaskContainers.put(TASK_ID, taskContainer);
@@ -164,6 +184,18 @@
}
@Test
+ public void testOnActivityDestroyed() {
+ doReturn(new Binder()).when(mActivity).getActivityToken();
+ final TaskFragmentContainer tf = mSplitController.newContainer(mActivity, TASK_ID);
+
+ assertTrue(tf.hasActivity(mActivity.getActivityToken()));
+
+ mSplitController.onActivityDestroyed(mActivity);
+
+ assertFalse(tf.hasActivity(mActivity.getActivityToken()));
+ }
+
+ @Test
public void testNewContainer() {
// Must pass in a valid activity.
assertThrows(IllegalArgumentException.class, () ->
@@ -247,6 +279,622 @@
mSplitController.updateContainer(mTransaction, tf);
- verify(mSplitPresenter).updateSplitContainer(eq(splitContainer), eq(tf), eq(mTransaction));
+ verify(mSplitPresenter).updateSplitContainer(splitContainer, tf, mTransaction);
+ }
+
+ @Test
+ public void testOnActivityCreated() {
+ mSplitController.onActivityCreated(mActivity);
+
+ // Disallow to split as primary because we want the new launch to be always on top.
+ verify(mSplitController).resolveActivityToContainer(mActivity,
+ false /* canSplitAsPrimary */);
+ }
+
+ @Test
+ public void testOnActivityReparentToTask_sameProcess() {
+ mSplitController.onActivityReparentToTask(TASK_ID, new Intent(),
+ mActivity.getActivityToken());
+
+ // Treated as on activity created, but allow to split as primary.
+ verify(mSplitController).resolveActivityToContainer(mActivity,
+ true /* canSplitAsPrimary */);
+ // Try to place the activity to the top TaskFragment when there is no matched rule.
+ verify(mSplitController).placeActivityInTopContainer(mActivity);
+ }
+
+ @Test
+ public void testOnActivityReparentToTask_diffProcess() {
+ // Create an empty TaskFragment to initialize for the Task.
+ mSplitController.newContainer(null, mActivity, TASK_ID);
+ final IBinder activityToken = new Binder();
+ final Intent intent = new Intent();
+
+ mSplitController.onActivityReparentToTask(TASK_ID, intent, activityToken);
+
+ // Treated as starting new intent
+ verify(mSplitController, never()).resolveActivityToContainer(any(), anyBoolean());
+ verify(mSplitController).resolveStartActivityIntent(any(), eq(TASK_ID), eq(intent),
+ isNull());
+ }
+
+ @Test
+ public void testResolveStartActivityIntent_withoutLaunchingActivity() {
+ final Intent intent = new Intent();
+ final ActivityRule expandRule = new ActivityRule.Builder(r -> false, i -> i == intent)
+ .setShouldAlwaysExpand(true)
+ .build();
+ mSplitController.setEmbeddingRules(Collections.singleton(expandRule));
+
+ // No other activity available in the Task.
+ TaskFragmentContainer container = mSplitController.resolveStartActivityIntent(mTransaction,
+ TASK_ID, intent, null /* launchingActivity */);
+ assertNull(container);
+
+ // Task contains another activity that can be used as owner activity.
+ createMockTaskFragmentContainer(mActivity);
+ container = mSplitController.resolveStartActivityIntent(mTransaction,
+ TASK_ID, intent, null /* launchingActivity */);
+ assertNotNull(container);
+ }
+
+ @Test
+ public void testResolveStartActivityIntent_shouldExpand() {
+ final Intent intent = new Intent();
+ setupExpandRule(intent);
+ final TaskFragmentContainer container = mSplitController.resolveStartActivityIntent(
+ mTransaction, TASK_ID, intent, mActivity);
+
+ assertNotNull(container);
+ assertTrue(container.areLastRequestedBoundsEqual(null));
+ assertTrue(container.isLastRequestedWindowingModeEqual(WINDOWING_MODE_UNDEFINED));
+ assertFalse(container.hasActivity(mActivity.getActivityToken()));
+ verify(mSplitPresenter).createTaskFragment(mTransaction, container.getTaskFragmentToken(),
+ mActivity.getActivityToken(), new Rect(), WINDOWING_MODE_UNDEFINED);
+ }
+
+ @Test
+ public void testResolveStartActivityIntent_shouldSplitWithLaunchingActivity() {
+ final Intent intent = new Intent();
+ setupSplitRule(mActivity, intent);
+
+ final TaskFragmentContainer container = mSplitController.resolveStartActivityIntent(
+ mTransaction, TASK_ID, intent, mActivity);
+ final TaskFragmentContainer primaryContainer = mSplitController.getContainerWithActivity(
+ mActivity);
+
+ assertSplitPair(primaryContainer, container);
+ }
+
+ @Test
+ public void testResolveStartActivityIntent_shouldSplitWithTopExpandActivity() {
+ final Intent intent = new Intent();
+ setupSplitRule(mActivity, intent);
+ createMockTaskFragmentContainer(mActivity);
+
+ final TaskFragmentContainer container = mSplitController.resolveStartActivityIntent(
+ mTransaction, TASK_ID, intent, null /* launchingActivity */);
+ final TaskFragmentContainer primaryContainer = mSplitController.getContainerWithActivity(
+ mActivity);
+
+ assertSplitPair(primaryContainer, container);
+ }
+
+ @Test
+ public void testResolveStartActivityIntent_shouldSplitWithTopSecondaryActivity() {
+ final Intent intent = new Intent();
+ setupSplitRule(mActivity, intent);
+ final Activity primaryActivity = createMockActivity();
+ addSplitTaskFragments(primaryActivity, mActivity);
+
+ final TaskFragmentContainer container = mSplitController.resolveStartActivityIntent(
+ mTransaction, TASK_ID, intent, null /* launchingActivity */);
+ final TaskFragmentContainer primaryContainer = mSplitController.getContainerWithActivity(
+ mActivity);
+
+ assertSplitPair(primaryContainer, container);
+ }
+
+ @Test
+ public void testResolveStartActivityIntent_shouldSplitWithTopPrimaryActivity() {
+ final Intent intent = new Intent();
+ setupSplitRule(mActivity, intent);
+ final Activity secondaryActivity = createMockActivity();
+ addSplitTaskFragments(mActivity, secondaryActivity);
+
+ final TaskFragmentContainer container = mSplitController.resolveStartActivityIntent(
+ mTransaction, TASK_ID, intent, null /* launchingActivity */);
+ final TaskFragmentContainer primaryContainer = mSplitController.getContainerWithActivity(
+ mActivity);
+
+ assertSplitPair(primaryContainer, container);
+ }
+
+ @Test
+ public void testPlaceActivityInTopContainer() {
+ mSplitController.placeActivityInTopContainer(mActivity);
+
+ verify(mSplitPresenter, never()).applyTransaction(any());
+
+ mSplitController.newContainer(null /* activity */, mActivity, TASK_ID);
+ mSplitController.placeActivityInTopContainer(mActivity);
+
+ verify(mSplitPresenter).applyTransaction(any());
+
+ // Not reparent if activity is in a TaskFragment.
+ clearInvocations(mSplitPresenter);
+ mSplitController.newContainer(mActivity, TASK_ID);
+ mSplitController.placeActivityInTopContainer(mActivity);
+
+ verify(mSplitPresenter, never()).applyTransaction(any());
+ }
+
+ @Test
+ public void testResolveActivityToContainer_noRuleMatched() {
+ final boolean result = mSplitController.resolveActivityToContainer(mActivity,
+ false /* canSplitAsPrimary */);
+
+ assertFalse(result);
+ verify(mSplitController, never()).newContainer(any(), any(), anyInt());
+ }
+
+ @Test
+ public void testResolveActivityToContainer_expandRule_notInTaskFragment() {
+ setupExpandRule(mActivity);
+
+ // When the activity is not in any TaskFragment, create a new expanded TaskFragment for it.
+ final boolean result = mSplitController.resolveActivityToContainer(mActivity,
+ false /* canSplitAsPrimary */);
+ final TaskFragmentContainer container = mSplitController.getContainerWithActivity(
+ mActivity);
+
+ assertTrue(result);
+ assertNotNull(container);
+ verify(mSplitController).newContainer(mActivity, TASK_ID);
+ verify(mSplitPresenter).expandActivity(container.getTaskFragmentToken(), mActivity);
+ }
+
+ @Test
+ public void testResolveActivityToContainer_expandRule_inSingleTaskFragment() {
+ setupExpandRule(mActivity);
+
+ // When the activity is not in any TaskFragment, create a new expanded TaskFragment for it.
+ final TaskFragmentContainer container = mSplitController.newContainer(mActivity, TASK_ID);
+ final boolean result = mSplitController.resolveActivityToContainer(mActivity,
+ false /* canSplitAsPrimary */);
+
+ assertTrue(result);
+ verify(mSplitPresenter).expandTaskFragment(container.getTaskFragmentToken());
+ }
+
+ @Test
+ public void testResolveActivityToContainer_expandRule_inSplitTaskFragment() {
+ setupExpandRule(mActivity);
+
+ // When the activity is not in any TaskFragment, create a new expanded TaskFragment for it.
+ final Activity activity = createMockActivity();
+ addSplitTaskFragments(activity, mActivity);
+ final boolean result = mSplitController.resolveActivityToContainer(mActivity,
+ false /* canSplitAsPrimary */);
+ final TaskFragmentContainer container = mSplitController.getContainerWithActivity(
+ mActivity);
+
+ assertTrue(result);
+ assertNotNull(container);
+ verify(mSplitPresenter).expandActivity(container.getTaskFragmentToken(), mActivity);
+ }
+
+ @Test
+ public void testResolveActivityToContainer_placeholderRule_notInTaskFragment() {
+ setupPlaceholderRule(mActivity);
+ final SplitPlaceholderRule placeholderRule =
+ (SplitPlaceholderRule) mSplitController.getSplitRules().get(0);
+
+ // Launch placeholder if the activity is not in any TaskFragment.
+ final boolean result = mSplitController.resolveActivityToContainer(mActivity,
+ false /* canSplitAsPrimary */);
+
+ assertTrue(result);
+ verify(mSplitPresenter).startActivityToSide(mActivity, PLACEHOLDER_INTENT,
+ null /* activityOptions */, placeholderRule, true /* isPlaceholder */);
+ }
+
+ @Test
+ public void testResolveActivityToContainer_placeholderRule_inOccludedTaskFragment() {
+ setupPlaceholderRule(mActivity);
+
+ // Don't launch placeholder if the activity is not in the topmost active TaskFragment.
+ final Activity activity = createMockActivity();
+ mSplitController.newContainer(mActivity, TASK_ID);
+ mSplitController.newContainer(activity, TASK_ID);
+ final boolean result = mSplitController.resolveActivityToContainer(mActivity,
+ false /* canSplitAsPrimary */);
+
+ assertFalse(result);
+ verify(mSplitPresenter, never()).startActivityToSide(any(), any(), any(), any(),
+ anyBoolean());
+ }
+
+ @Test
+ public void testResolveActivityToContainer_placeholderRule_inTopMostTaskFragment() {
+ setupPlaceholderRule(mActivity);
+ final SplitPlaceholderRule placeholderRule =
+ (SplitPlaceholderRule) mSplitController.getSplitRules().get(0);
+
+ // Launch placeholder if the activity is in the topmost expanded TaskFragment.
+ mSplitController.newContainer(mActivity, TASK_ID);
+ final boolean result = mSplitController.resolveActivityToContainer(mActivity,
+ false /* canSplitAsPrimary */);
+
+ assertTrue(result);
+ verify(mSplitPresenter).startActivityToSide(mActivity, PLACEHOLDER_INTENT,
+ null /* activityOptions */, placeholderRule, true /* isPlaceholder */);
+ }
+
+ @Test
+ public void testResolveActivityToContainer_placeholderRule_inPrimarySplit() {
+ setupPlaceholderRule(mActivity);
+
+ // Don't launch placeholder if the activity is in primary split.
+ final Activity secondaryActivity = createMockActivity();
+ addSplitTaskFragments(mActivity, secondaryActivity);
+ final boolean result = mSplitController.resolveActivityToContainer(mActivity,
+ false /* canSplitAsPrimary */);
+
+ assertFalse(result);
+ verify(mSplitPresenter, never()).startActivityToSide(any(), any(), any(), any(),
+ anyBoolean());
+ }
+
+ @Test
+ public void testResolveActivityToContainer_placeholderRule_inSecondarySplit() {
+ setupPlaceholderRule(mActivity);
+ final SplitPlaceholderRule placeholderRule =
+ (SplitPlaceholderRule) mSplitController.getSplitRules().get(0);
+
+ // Launch placeholder if the activity is in secondary split.
+ final Activity primaryActivity = createMockActivity();
+ addSplitTaskFragments(primaryActivity, mActivity);
+ final boolean result = mSplitController.resolveActivityToContainer(mActivity,
+ false /* canSplitAsPrimary */);
+
+ assertTrue(result);
+ verify(mSplitPresenter).startActivityToSide(mActivity, PLACEHOLDER_INTENT,
+ null /* activityOptions */, placeholderRule, true /* isPlaceholder */);
+ }
+
+ @Test
+ public void testResolveActivityToContainer_splitRule_inPrimarySplitWithRuleMatched() {
+ final Intent secondaryIntent = new Intent();
+ setupSplitRule(mActivity, secondaryIntent);
+ final SplitPairRule splitRule = (SplitPairRule) mSplitController.getSplitRules().get(0);
+
+ // Activity is already in primary split, no need to create new split.
+ final TaskFragmentContainer primaryContainer = mSplitController.newContainer(mActivity,
+ TASK_ID);
+ final TaskFragmentContainer secondaryContainer = mSplitController.newContainer(
+ null /* activity */, mActivity, TASK_ID);
+ mSplitController.registerSplit(
+ mTransaction,
+ primaryContainer,
+ mActivity,
+ secondaryContainer,
+ splitRule);
+ clearInvocations(mSplitController);
+ final boolean result = mSplitController.resolveActivityToContainer(mActivity,
+ false /* canSplitAsPrimary */);
+
+ assertTrue(result);
+ verify(mSplitController, never()).newContainer(any(), any(), anyInt());
+ verify(mSplitController, never()).registerSplit(any(), any(), any(), any(), any());
+ }
+
+ @Test
+ public void testResolveActivityToContainer_splitRule_inSecondarySplitWithRuleMatched() {
+ final Activity primaryActivity = createMockActivity();
+ setupSplitRule(primaryActivity, mActivity);
+
+ // Activity is already in secondary split, no need to create new split.
+ addSplitTaskFragments(primaryActivity, mActivity);
+ clearInvocations(mSplitController);
+ final boolean result = mSplitController.resolveActivityToContainer(mActivity,
+ false /* canSplitAsPrimary */);
+
+ assertTrue(result);
+ verify(mSplitController, never()).newContainer(any(), any(), anyInt());
+ verify(mSplitController, never()).registerSplit(any(), any(), any(), any(), any());
+ }
+
+ @Test
+ public void testResolveActivityToContainer_splitRule_inSecondarySplitWithNoRuleMatched() {
+ final Activity primaryActivity = createMockActivity();
+ final Activity secondaryActivity = createMockActivity();
+ setupSplitRule(primaryActivity, secondaryActivity);
+
+ // Activity is in secondary split, but there is no rule to split it with primary.
+ addSplitTaskFragments(primaryActivity, secondaryActivity);
+ mSplitController.getContainerWithActivity(secondaryActivity)
+ .addPendingAppearedActivity(mActivity);
+ final boolean result = mSplitController.resolveActivityToContainer(mActivity,
+ false /* canSplitAsPrimary */);
+
+ assertFalse(result);
+ }
+
+ @Test
+ public void testResolveActivityToContainer_placeholderRule_isPlaceholderWithRuleMatched() {
+ final Activity primaryActivity = createMockActivity();
+ setupPlaceholderRule(primaryActivity);
+ final SplitPlaceholderRule placeholderRule =
+ (SplitPlaceholderRule) mSplitController.getSplitRules().get(0);
+ doReturn(PLACEHOLDER_INTENT).when(mActivity).getIntent();
+
+ // Activity is a placeholder.
+ final TaskFragmentContainer primaryContainer = mSplitController.newContainer(
+ primaryActivity, TASK_ID);
+ final TaskFragmentContainer secondaryContainer = mSplitController.newContainer(mActivity,
+ TASK_ID);
+ mSplitController.registerSplit(
+ mTransaction,
+ primaryContainer,
+ mActivity,
+ secondaryContainer,
+ placeholderRule);
+ final boolean result = mSplitController.resolveActivityToContainer(mActivity,
+ false /* canSplitAsPrimary */);
+
+ assertTrue(result);
+ }
+
+ @Test
+ public void testResolveActivityToContainer_splitRule_splitWithActivityBelowAsSecondary() {
+ final Activity activityBelow = createMockActivity();
+ setupSplitRule(activityBelow, mActivity);
+
+ final TaskFragmentContainer container = mSplitController.newContainer(activityBelow,
+ TASK_ID);
+ container.addPendingAppearedActivity(mActivity);
+ final boolean result = mSplitController.resolveActivityToContainer(mActivity,
+ false /* canSplitAsPrimary */);
+
+ assertTrue(result);
+ assertSplitPair(activityBelow, mActivity);
+ }
+
+ @Test
+ public void testResolveActivityToContainer_splitRule_splitWithActivityBelowAsPrimary() {
+ final Activity activityBelow = createMockActivity();
+ setupSplitRule(mActivity, activityBelow);
+
+ // Disallow to split as primary.
+ final TaskFragmentContainer container = mSplitController.newContainer(activityBelow,
+ TASK_ID);
+ container.addPendingAppearedActivity(mActivity);
+ boolean result = mSplitController.resolveActivityToContainer(mActivity,
+ false /* canSplitAsPrimary */);
+
+ assertFalse(result);
+ assertEquals(container, mSplitController.getContainerWithActivity(mActivity));
+
+ // Allow to split as primary.
+ result = mSplitController.resolveActivityToContainer(mActivity,
+ true /* canSplitAsPrimary */);
+
+ assertTrue(result);
+ assertSplitPair(mActivity, activityBelow);
+ }
+
+ @Test
+ public void testResolveActivityToContainer_splitRule_splitWithCurrentPrimaryAsSecondary() {
+ final Activity primaryActivity = createMockActivity();
+ setupSplitRule(primaryActivity, mActivity);
+
+ final Activity activityBelow = createMockActivity();
+ addSplitTaskFragments(primaryActivity, activityBelow);
+ final TaskFragmentContainer primaryContainer = mSplitController.getContainerWithActivity(
+ primaryActivity);
+ final TaskFragmentContainer secondaryContainer = mSplitController.getContainerWithActivity(
+ activityBelow);
+ secondaryContainer.addPendingAppearedActivity(mActivity);
+ final boolean result = mSplitController.resolveActivityToContainer(mActivity,
+ false /* canSplitAsPrimary */);
+ final TaskFragmentContainer container = mSplitController.getContainerWithActivity(
+ mActivity);
+
+ assertTrue(result);
+ // TODO(b/231845476) we should always respect clearTop.
+ // assertNotEquals(secondaryContainer, container);
+ assertSplitPair(primaryContainer, container);
+ }
+
+ @Test
+ public void testResolveActivityToContainer_splitRule_splitWithCurrentPrimaryAsPrimary() {
+ final Activity primaryActivity = createMockActivity();
+ setupSplitRule(mActivity, primaryActivity);
+
+ final Activity activityBelow = createMockActivity();
+ addSplitTaskFragments(primaryActivity, activityBelow);
+ final TaskFragmentContainer primaryContainer = mSplitController.getContainerWithActivity(
+ primaryActivity);
+ primaryContainer.addPendingAppearedActivity(mActivity);
+ boolean result = mSplitController.resolveActivityToContainer(mActivity,
+ false /* canSplitAsPrimary */);
+
+ assertFalse(result);
+ assertEquals(primaryContainer, mSplitController.getContainerWithActivity(mActivity));
+
+
+ result = mSplitController.resolveActivityToContainer(mActivity,
+ true /* canSplitAsPrimary */);
+
+ assertTrue(result);
+ assertSplitPair(mActivity, primaryActivity);
+ }
+
+ /** Creates a mock activity in the organizer process. */
+ private Activity createMockActivity() {
+ final Activity activity = mock(Activity.class);
+ doReturn(mActivityResources).when(activity).getResources();
+ final IBinder activityToken = new Binder();
+ doReturn(activityToken).when(activity).getActivityToken();
+ doReturn(activity).when(mSplitController).getActivity(activityToken);
+ doReturn(TASK_ID).when(activity).getTaskId();
+ return activity;
+ }
+
+ /** Creates a mock TaskFragmentInfo for the given TaskFragment. */
+ private TaskFragmentInfo createMockTaskFragmentInfo(@NonNull TaskFragmentContainer container,
+ @NonNull Activity activity) {
+ return new TaskFragmentInfo(container.getTaskFragmentToken(),
+ mock(WindowContainerToken.class),
+ new Configuration(),
+ 1,
+ true /* isVisible */,
+ Collections.singletonList(activity.getActivityToken()),
+ new Point(),
+ false /* isTaskClearedForReuse */,
+ false /* isTaskFragmentClearedForPip */);
+ }
+
+ /** Creates a mock TaskFragment that has been registered and appeared in the organizer. */
+ private TaskFragmentContainer createMockTaskFragmentContainer(@NonNull Activity activity) {
+ final TaskFragmentContainer container = mSplitController.newContainer(activity, TASK_ID);
+ setupTaskFragmentInfo(container, activity);
+ return container;
+ }
+
+ /** Setups the given TaskFragment as it has appeared in the server. */
+ private void setupTaskFragmentInfo(@NonNull TaskFragmentContainer container,
+ @NonNull Activity activity) {
+ final TaskFragmentInfo info = createMockTaskFragmentInfo(container, activity);
+ container.setInfo(info);
+ mSplitPresenter.mFragmentInfos.put(container.getTaskFragmentToken(), info);
+ }
+
+ /** Setups a rule to always expand the given intent. */
+ private void setupExpandRule(@NonNull Intent expandIntent) {
+ final ActivityRule expandRule = new ActivityRule.Builder(r -> false, expandIntent::equals)
+ .setShouldAlwaysExpand(true)
+ .build();
+ mSplitController.setEmbeddingRules(Collections.singleton(expandRule));
+ }
+
+ /** Setups a rule to always expand the given activity. */
+ private void setupExpandRule(@NonNull Activity expandActivity) {
+ final ActivityRule expandRule = new ActivityRule.Builder(expandActivity::equals, i -> false)
+ .setShouldAlwaysExpand(true)
+ .build();
+ mSplitController.setEmbeddingRules(Collections.singleton(expandRule));
+ }
+
+ /** Setups a rule to launch placeholder for the given activity. */
+ private void setupPlaceholderRule(@NonNull Activity primaryActivity) {
+ final SplitRule placeholderRule = new SplitPlaceholderRule.Builder(PLACEHOLDER_INTENT,
+ primaryActivity::equals, i -> false, w -> true)
+ .setSplitRatio(SPLIT_RATIO)
+ .build();
+ mSplitController.setEmbeddingRules(Collections.singleton(placeholderRule));
+ }
+
+ /** Setups a rule to always split the given activities. */
+ private void setupSplitRule(@NonNull Activity primaryActivity,
+ @NonNull Intent secondaryIntent) {
+ final SplitRule splitRule = createSplitRule(primaryActivity, secondaryIntent);
+ mSplitController.setEmbeddingRules(Collections.singleton(splitRule));
+ }
+
+ /** Setups a rule to always split the given activities. */
+ private void setupSplitRule(@NonNull Activity primaryActivity,
+ @NonNull Activity secondaryActivity) {
+ final SplitRule splitRule = createSplitRule(primaryActivity, secondaryActivity);
+ mSplitController.setEmbeddingRules(Collections.singleton(splitRule));
+ }
+
+ /** Creates a rule to always split the given activity and the given intent. */
+ private SplitRule createSplitRule(@NonNull Activity primaryActivity,
+ @NonNull Intent secondaryIntent) {
+ final Pair<Activity, Intent> targetPair = new Pair<>(primaryActivity, secondaryIntent);
+ return new SplitPairRule.Builder(
+ activityPair -> false,
+ targetPair::equals,
+ w -> true)
+ .setSplitRatio(SPLIT_RATIO)
+ .setShouldClearTop(true)
+ .build();
+ }
+
+ /** Creates a rule to always split the given activities. */
+ private SplitRule createSplitRule(@NonNull Activity primaryActivity,
+ @NonNull Activity secondaryActivity) {
+ final Pair<Activity, Activity> targetPair = new Pair<>(primaryActivity, secondaryActivity);
+ return new SplitPairRule.Builder(
+ targetPair::equals,
+ activityIntentPair -> false,
+ w -> true)
+ .setSplitRatio(SPLIT_RATIO)
+ .setShouldClearTop(true)
+ .build();
+ }
+
+ /** Adds a pair of TaskFragments as split for the given activities. */
+ private void addSplitTaskFragments(@NonNull Activity primaryActivity,
+ @NonNull Activity secondaryActivity) {
+ final TaskFragmentContainer primaryContainer = createMockTaskFragmentContainer(
+ primaryActivity);
+ final TaskFragmentContainer secondaryContainer = createMockTaskFragmentContainer(
+ secondaryActivity);
+ mSplitController.registerSplit(
+ mock(WindowContainerTransaction.class),
+ primaryContainer,
+ primaryActivity,
+ secondaryContainer,
+ createSplitRule(primaryActivity, secondaryActivity));
+
+ // We need to set those in case we are not respecting clear top.
+ // TODO(b/231845476) we should always respect clearTop.
+ final int windowingMode = mSplitController.getTaskContainer(TASK_ID)
+ .getWindowingModeForSplitTaskFragment(TASK_BOUNDS);
+ primaryContainer.setLastRequestedWindowingMode(windowingMode);
+ secondaryContainer.setLastRequestedWindowingMode(windowingMode);
+ primaryContainer.setLastRequestedBounds(getSplitBounds(true /* isPrimary */));
+ secondaryContainer.setLastRequestedBounds(getSplitBounds(false /* isPrimary */));
+ }
+
+ /** Gets the bounds of a TaskFragment that is in split. */
+ private Rect getSplitBounds(boolean isPrimary) {
+ final int width = (int) (TASK_BOUNDS.width() * SPLIT_RATIO);
+ return isPrimary
+ ? new Rect(TASK_BOUNDS.left, TASK_BOUNDS.top, TASK_BOUNDS.left + width,
+ TASK_BOUNDS.bottom)
+ : new Rect(TASK_BOUNDS.left + width, TASK_BOUNDS.top, TASK_BOUNDS.right,
+ TASK_BOUNDS.bottom);
+ }
+
+ /** Asserts that the two given activities are in split. */
+ private void assertSplitPair(@NonNull Activity primaryActivity,
+ @NonNull Activity secondaryActivity) {
+ assertSplitPair(mSplitController.getContainerWithActivity(primaryActivity),
+ mSplitController.getContainerWithActivity(secondaryActivity));
+ }
+
+ /** Asserts that the two given TaskFragments are in split. */
+ private void assertSplitPair(@NonNull TaskFragmentContainer primaryContainer,
+ @NonNull TaskFragmentContainer secondaryContainer) {
+ assertNotNull(primaryContainer);
+ assertNotNull(secondaryContainer);
+ assertNotNull(mSplitController.getActiveSplitForContainers(primaryContainer,
+ secondaryContainer));
+ if (primaryContainer.mInfo != null) {
+ assertTrue(primaryContainer.areLastRequestedBoundsEqual(
+ getSplitBounds(true /* isPrimary */)));
+ assertTrue(primaryContainer.isLastRequestedWindowingModeEqual(
+ WINDOWING_MODE_MULTI_WINDOW));
+ }
+ if (secondaryContainer.mInfo != null) {
+ assertTrue(secondaryContainer.areLastRequestedBoundsEqual(
+ getSplitBounds(false /* isPrimary */)));
+ assertTrue(secondaryContainer.isLastRequestedWindowingModeEqual(
+ WINDOWING_MODE_MULTI_WINDOW));
+ }
}
}
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java
index c40bab8..f1042ab 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java
@@ -24,8 +24,12 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import android.app.Activity;
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
@@ -137,9 +141,8 @@
assertTrue(taskContainer.isEmpty());
- final TaskFragmentContainer tf = new TaskFragmentContainer(null /* activity */, TASK_ID,
- mController);
- taskContainer.mContainers.add(tf);
+ final TaskFragmentContainer tf = new TaskFragmentContainer(null /* activity */,
+ taskContainer, mController);
assertFalse(taskContainer.isEmpty());
@@ -148,4 +151,38 @@
assertFalse(taskContainer.isEmpty());
}
+
+ @Test
+ public void testGetTopTaskFragmentContainer() {
+ final TaskContainer taskContainer = new TaskContainer(TASK_ID);
+ assertNull(taskContainer.getTopTaskFragmentContainer());
+
+ final TaskFragmentContainer tf0 = new TaskFragmentContainer(null /* activity */,
+ taskContainer, mController);
+ assertEquals(tf0, taskContainer.getTopTaskFragmentContainer());
+
+ final TaskFragmentContainer tf1 = new TaskFragmentContainer(null /* activity */,
+ taskContainer, mController);
+ assertEquals(tf1, taskContainer.getTopTaskFragmentContainer());
+ }
+
+ @Test
+ public void testGetTopNonFinishingActivity() {
+ final TaskContainer taskContainer = new TaskContainer(TASK_ID);
+ assertNull(taskContainer.getTopNonFinishingActivity());
+
+ final TaskFragmentContainer tf0 = mock(TaskFragmentContainer.class);
+ taskContainer.mContainers.add(tf0);
+ final Activity activity0 = mock(Activity.class);
+ doReturn(activity0).when(tf0).getTopNonFinishingActivity();
+ assertEquals(activity0, taskContainer.getTopNonFinishingActivity());
+
+ final TaskFragmentContainer tf1 = mock(TaskFragmentContainer.class);
+ taskContainer.mContainers.add(tf1);
+ assertEquals(activity0, taskContainer.getTopNonFinishingActivity());
+
+ final Activity activity1 = mock(Activity.class);
+ doReturn(activity1).when(tf1).getTopNonFinishingActivity();
+ assertEquals(activity1, taskContainer.getTopNonFinishingActivity());
+ }
}
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 d80f2b9..587878f 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
@@ -18,6 +18,7 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
@@ -29,7 +30,9 @@
import static org.mockito.Mockito.never;
import android.app.Activity;
+import android.os.Binder;
import android.os.Handler;
+import android.os.IBinder;
import android.platform.test.annotations.Presubmit;
import android.window.TaskFragmentInfo;
import android.window.WindowContainerTransaction;
@@ -37,6 +40,8 @@
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
+import com.google.android.collect.Lists;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -44,6 +49,7 @@
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
+import java.util.List;
/**
* Test class for {@link TaskFragmentContainer}.
@@ -62,21 +68,22 @@
@Mock
private SplitController mController;
@Mock
- private Activity mActivity;
- @Mock
private TaskFragmentInfo mInfo;
@Mock
private Handler mHandler;
+ private Activity mActivity;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
doReturn(mHandler).when(mController).getHandler();
+ mActivity = createMockActivity();
}
@Test
public void testFinish() {
- final TaskFragmentContainer container = new TaskFragmentContainer(mActivity, TASK_ID,
+ final TaskContainer taskContainer = new TaskContainer(TASK_ID);
+ final TaskFragmentContainer container = new TaskFragmentContainer(mActivity, taskContainer,
mController);
final WindowContainerTransaction wct = new WindowContainerTransaction();
@@ -107,8 +114,9 @@
@Test
public void testIsWaitingActivityAppear() {
+ final TaskContainer taskContainer = new TaskContainer(TASK_ID);
final TaskFragmentContainer container = new TaskFragmentContainer(null /* activity */,
- TASK_ID, mController);
+ taskContainer, mController);
assertTrue(container.isWaitingActivityAppear());
@@ -127,8 +135,9 @@
@Test
public void testAppearEmptyTimeout() {
+ final TaskContainer taskContainer = new TaskContainer(TASK_ID);
final TaskFragmentContainer container = new TaskFragmentContainer(null /* activity */,
- TASK_ID, mController);
+ taskContainer, mController);
assertNull(container.mAppearEmptyTimeout);
@@ -162,4 +171,72 @@
assertNull(container.mAppearEmptyTimeout);
verify(mController).onTaskFragmentAppearEmptyTimeout(container);
}
+
+ @Test
+ public void testCollectActivities() {
+ final TaskContainer taskContainer = new TaskContainer(TASK_ID);
+ final TaskFragmentContainer container = new TaskFragmentContainer(null /* activity */,
+ taskContainer, mController);
+ List<Activity> activities = container.collectActivities();
+
+ assertTrue(activities.isEmpty());
+
+ container.addPendingAppearedActivity(mActivity);
+ activities = container.collectActivities();
+
+ assertEquals(1, activities.size());
+
+ final Activity activity0 = createMockActivity();
+ final Activity activity1 = createMockActivity();
+ final List<IBinder> runningActivities = Lists.newArrayList(activity0.getActivityToken(),
+ activity1.getActivityToken());
+ doReturn(runningActivities).when(mInfo).getActivities();
+ container.setInfo(mInfo);
+ activities = container.collectActivities();
+
+ assertEquals(3, activities.size());
+ assertEquals(activity0, activities.get(0));
+ assertEquals(activity1, activities.get(1));
+ assertEquals(mActivity, activities.get(2));
+ }
+
+ @Test
+ public void testAddPendingActivity() {
+ final TaskContainer taskContainer = new TaskContainer(TASK_ID);
+ final TaskFragmentContainer container = new TaskFragmentContainer(null /* activity */,
+ taskContainer, mController);
+ container.addPendingAppearedActivity(mActivity);
+
+ assertEquals(1, container.collectActivities().size());
+
+ container.addPendingAppearedActivity(mActivity);
+
+ assertEquals(1, container.collectActivities().size());
+ }
+
+ @Test
+ public void testGetBottomMostActivity() {
+ final TaskContainer taskContainer = new TaskContainer(TASK_ID);
+ final TaskFragmentContainer container = new TaskFragmentContainer(null /* activity */,
+ taskContainer, mController);
+ container.addPendingAppearedActivity(mActivity);
+
+ assertEquals(mActivity, container.getBottomMostActivity());
+
+ final Activity activity = createMockActivity();
+ final List<IBinder> runningActivities = Lists.newArrayList(activity.getActivityToken());
+ doReturn(runningActivities).when(mInfo).getActivities();
+ container.setInfo(mInfo);
+
+ assertEquals(activity, container.getBottomMostActivity());
+ }
+
+ /** Creates a mock activity in the organizer process. */
+ private Activity createMockActivity() {
+ final Activity activity = mock(Activity.class);
+ final IBinder activityToken = new Binder();
+ doReturn(activityToken).when(activity).getActivityToken();
+ doReturn(activity).when(mController).getActivity(activityToken);
+ return activity;
+ }
}
diff --git a/libs/WindowManager/Shell/res/values-eu/strings.xml b/libs/WindowManager/Shell/res/values-eu/strings.xml
index caa335a..67b9a43 100644
--- a/libs/WindowManager/Shell/res/values-eu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-eu/strings.xml
@@ -23,7 +23,7 @@
<string name="pip_phone_enter_split" msgid="7042877263880641911">"Sartu pantaila zatituan"</string>
<string name="pip_menu_title" msgid="5393619322111827096">"Menua"</string>
<string name="pip_notification_title" msgid="1347104727641353453">"Pantaila txiki gainjarrian dago <xliff:g id="NAME">%s</xliff:g>"</string>
- <string name="pip_notification_message" msgid="8854051911700302620">"Ez baduzu nahi <xliff:g id="NAME">%s</xliff:g> zerbitzuak eginbide hori erabiltzea, sakatu hau ezarpenak ireki eta aukera desaktibatzeko."</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"<xliff:g id="NAME">%s</xliff:g> zerbitzuak eginbide hori erabiltzea nahi ez baduzu, sakatu hau ezarpenak ireki eta aukera desaktibatzeko."</string>
<string name="pip_play" msgid="3496151081459417097">"Erreproduzitu"</string>
<string name="pip_pause" msgid="690688849510295232">"Pausatu"</string>
<string name="pip_skip_to_next" msgid="8403429188794867653">"Joan hurrengora"</string>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java
index 06f4367..c5f7c19 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java
@@ -18,11 +18,9 @@
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
-import com.android.wm.shell.apppairs.AppPairsController;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.hidedisplaycutout.HideDisplayCutoutController;
import com.android.wm.shell.kidsmode.KidsModeTaskOrganizer;
-import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController;
import com.android.wm.shell.onehanded.OneHandedController;
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.recents.RecentTasksController;
@@ -39,12 +37,10 @@
public final class ShellCommandHandlerImpl {
private static final String TAG = ShellCommandHandlerImpl.class.getSimpleName();
- private final Optional<LegacySplitScreenController> mLegacySplitScreenOptional;
private final Optional<SplitScreenController> mSplitScreenOptional;
private final Optional<Pip> mPipOptional;
private final Optional<OneHandedController> mOneHandedOptional;
private final Optional<HideDisplayCutoutController> mHideDisplayCutout;
- private final Optional<AppPairsController> mAppPairsOptional;
private final Optional<RecentTasksController> mRecentTasks;
private final ShellTaskOrganizer mShellTaskOrganizer;
private final KidsModeTaskOrganizer mKidsModeTaskOrganizer;
@@ -54,23 +50,19 @@
public ShellCommandHandlerImpl(
ShellTaskOrganizer shellTaskOrganizer,
KidsModeTaskOrganizer kidsModeTaskOrganizer,
- Optional<LegacySplitScreenController> legacySplitScreenOptional,
Optional<SplitScreenController> splitScreenOptional,
Optional<Pip> pipOptional,
Optional<OneHandedController> oneHandedOptional,
Optional<HideDisplayCutoutController> hideDisplayCutout,
- Optional<AppPairsController> appPairsOptional,
Optional<RecentTasksController> recentTasks,
ShellExecutor mainExecutor) {
mShellTaskOrganizer = shellTaskOrganizer;
mKidsModeTaskOrganizer = kidsModeTaskOrganizer;
mRecentTasks = recentTasks;
- mLegacySplitScreenOptional = legacySplitScreenOptional;
mSplitScreenOptional = splitScreenOptional;
mPipOptional = pipOptional;
mOneHandedOptional = oneHandedOptional;
mHideDisplayCutout = hideDisplayCutout;
- mAppPairsOptional = appPairsOptional;
mMainExecutor = mainExecutor;
}
@@ -84,14 +76,10 @@
pw.println();
pw.println();
mPipOptional.ifPresent(pip -> pip.dump(pw));
- mLegacySplitScreenOptional.ifPresent(splitScreen -> splitScreen.dump(pw));
mOneHandedOptional.ifPresent(oneHanded -> oneHanded.dump(pw));
mHideDisplayCutout.ifPresent(hideDisplayCutout -> hideDisplayCutout.dump(pw));
pw.println();
pw.println();
- mAppPairsOptional.ifPresent(appPairs -> appPairs.dump(pw, ""));
- pw.println();
- pw.println();
mSplitScreenOptional.ifPresent(splitScreen -> splitScreen.dump(pw, ""));
pw.println();
pw.println();
@@ -109,10 +97,6 @@
return false;
}
switch (args[1]) {
- case "pair":
- return runPair(args, pw);
- case "unpair":
- return runUnpair(args, pw);
case "moveToSideStage":
return runMoveToSideStage(args, pw);
case "removeFromSideStage":
@@ -126,29 +110,6 @@
}
}
- private boolean runPair(String[] args, PrintWriter pw) {
- if (args.length < 4) {
- // First two arguments are "WMShell" and command name.
- pw.println("Error: two task ids should be provided as arguments");
- return false;
- }
- final int taskId1 = new Integer(args[2]);
- final int taskId2 = new Integer(args[3]);
- mAppPairsOptional.ifPresent(appPairs -> appPairs.pair(taskId1, taskId2));
- return true;
- }
-
- private boolean runUnpair(String[] args, PrintWriter pw) {
- if (args.length < 3) {
- // First two arguments are "WMShell" and command name.
- pw.println("Error: task id should be provided as an argument");
- return false;
- }
- final int taskId = new Integer(args[2]);
- mAppPairsOptional.ifPresent(appPairs -> appPairs.unpair(taskId));
- return true;
- }
-
private boolean runMoveToSideStage(String[] args, PrintWriter pw) {
if (args.length < 3) {
// First arguments are "WMShell" and command name.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java
index ecdccd7..f6a3e7f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java
@@ -18,7 +18,6 @@
import static com.android.wm.shell.ShellTaskOrganizer.TASK_LISTENER_TYPE_FULLSCREEN;
-import com.android.wm.shell.apppairs.AppPairsController;
import com.android.wm.shell.bubbles.BubbleController;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayImeController;
@@ -54,7 +53,6 @@
private final KidsModeTaskOrganizer mKidsModeTaskOrganizer;
private final Optional<BubbleController> mBubblesOptional;
private final Optional<SplitScreenController> mSplitScreenOptional;
- private final Optional<AppPairsController> mAppPairsOptional;
private final Optional<PipTouchHandler> mPipTouchHandlerOptional;
private final FullscreenTaskListener mFullscreenTaskListener;
private final Optional<FullscreenUnfoldController> mFullscreenUnfoldController;
@@ -76,7 +74,6 @@
KidsModeTaskOrganizer kidsModeTaskOrganizer,
Optional<BubbleController> bubblesOptional,
Optional<SplitScreenController> splitScreenOptional,
- Optional<AppPairsController> appPairsOptional,
Optional<PipTouchHandler> pipTouchHandlerOptional,
FullscreenTaskListener fullscreenTaskListener,
Optional<FullscreenUnfoldController> fullscreenUnfoldTransitionController,
@@ -94,7 +91,6 @@
mKidsModeTaskOrganizer = kidsModeTaskOrganizer;
mBubblesOptional = bubblesOptional;
mSplitScreenOptional = splitScreenOptional;
- mAppPairsOptional = appPairsOptional;
mFullscreenTaskListener = fullscreenTaskListener;
mPipTouchHandlerOptional = pipTouchHandlerOptional;
mFullscreenUnfoldController = fullscreenUnfoldTransitionController;
@@ -122,7 +118,6 @@
mShellTaskOrganizer.initStartingWindow(mStartingWindow);
mShellTaskOrganizer.registerOrganizer();
- mAppPairsOptional.ifPresent(AppPairsController::onOrganizerRegistered);
mSplitScreenOptional.ifPresent(SplitScreenController::onOrganizerRegistered);
mBubblesOptional.ifPresent(BubbleController::initialize);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java
index 2aead93..a0dde6a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java
@@ -53,6 +53,19 @@
public static final Interpolator LINEAR_OUT_SLOW_IN = new PathInterpolator(0f, 0f, 0.2f, 1f);
/**
+ * The accelerated emphasized interpolator. Used for hero / emphasized movement of content that
+ * is disappearing e.g. when moving off screen.
+ */
+ public static final Interpolator EMPHASIZED_ACCELERATE = new PathInterpolator(
+ 0.3f, 0f, 0.8f, 0.15f);
+
+ /**
+ * The decelerating emphasized interpolator. Used for hero / emphasized movement of content that
+ * is appearing e.g. when coming from off screen
+ */
+ public static final Interpolator EMPHASIZED_DECELERATE = new PathInterpolator(
+ 0.05f, 0.7f, 0.1f, 1f);
+ /**
* Interpolator to be used when animating a move based on a click. Pair with enough duration.
*/
public static final Interpolator TOUCH_RESPONSE = new PathInterpolator(0.3f, 0f, 0.1f, 1f);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java
deleted file mode 100644
index 3f0b01b..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java
+++ /dev/null
@@ -1,357 +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.wm.shell.apppairs;
-
-import static android.app.ActivityTaskManager.INVALID_TASK_ID;
-import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
-import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
-
-import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
-import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_TASK_ORG;
-
-import android.app.ActivityManager;
-import android.view.SurfaceControl;
-import android.view.SurfaceSession;
-import android.window.WindowContainerToken;
-import android.window.WindowContainerTransaction;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import com.android.internal.protolog.common.ProtoLog;
-import com.android.wm.shell.ShellTaskOrganizer;
-import com.android.wm.shell.common.DisplayController;
-import com.android.wm.shell.common.DisplayImeController;
-import com.android.wm.shell.common.DisplayInsetsController;
-import com.android.wm.shell.common.SurfaceUtils;
-import com.android.wm.shell.common.SyncTransactionQueue;
-import com.android.wm.shell.common.split.SplitLayout;
-import com.android.wm.shell.common.split.SplitWindowManager;
-
-import java.io.PrintWriter;
-
-/**
- * An app-pairs consisting of {@link #mRootTaskInfo} that acts as the hierarchy parent of
- * {@link #mTaskInfo1} and {@link #mTaskInfo2} in the pair.
- * Also includes all UI for managing the pair like the divider.
- */
-class AppPair implements ShellTaskOrganizer.TaskListener, SplitLayout.SplitLayoutHandler {
- private static final String TAG = AppPair.class.getSimpleName();
-
- private ActivityManager.RunningTaskInfo mRootTaskInfo;
- private SurfaceControl mRootTaskLeash;
- private ActivityManager.RunningTaskInfo mTaskInfo1;
- private SurfaceControl mTaskLeash1;
- private ActivityManager.RunningTaskInfo mTaskInfo2;
- private SurfaceControl mTaskLeash2;
- private SurfaceControl mDimLayer1;
- private SurfaceControl mDimLayer2;
- private final SurfaceSession mSurfaceSession = new SurfaceSession();
-
- private final AppPairsController mController;
- private final SyncTransactionQueue mSyncQueue;
- private final DisplayController mDisplayController;
- private final DisplayImeController mDisplayImeController;
- private final DisplayInsetsController mDisplayInsetsController;
- private SplitLayout mSplitLayout;
-
- private final SplitWindowManager.ParentContainerCallbacks mParentContainerCallbacks =
- new SplitWindowManager.ParentContainerCallbacks() {
- @Override
- public void attachToParentSurface(SurfaceControl.Builder b) {
- b.setParent(mRootTaskLeash);
- }
-
- @Override
- public void onLeashReady(SurfaceControl leash) {
- mSyncQueue.runInSync(t -> t
- .show(leash)
- .setLayer(leash, Integer.MAX_VALUE)
- .setPosition(leash,
- mSplitLayout.getDividerBounds().left,
- mSplitLayout.getDividerBounds().top));
- }
- };
-
- AppPair(AppPairsController controller) {
- mController = controller;
- mSyncQueue = controller.getSyncTransactionQueue();
- mDisplayController = controller.getDisplayController();
- mDisplayImeController = controller.getDisplayImeController();
- mDisplayInsetsController = controller.getDisplayInsetsController();
- }
-
- int getRootTaskId() {
- return mRootTaskInfo != null ? mRootTaskInfo.taskId : INVALID_TASK_ID;
- }
-
- private int getTaskId1() {
- return mTaskInfo1 != null ? mTaskInfo1.taskId : INVALID_TASK_ID;
- }
-
- private int getTaskId2() {
- return mTaskInfo2 != null ? mTaskInfo2.taskId : INVALID_TASK_ID;
- }
-
- boolean contains(int taskId) {
- return taskId == getRootTaskId() || taskId == getTaskId1() || taskId == getTaskId2();
- }
-
- boolean pair(ActivityManager.RunningTaskInfo task1, ActivityManager.RunningTaskInfo task2) {
- ProtoLog.v(WM_SHELL_TASK_ORG, "pair task1=%d task2=%d in AppPair=%s",
- task1.taskId, task2.taskId, this);
-
- if (!task1.supportsMultiWindow || !task2.supportsMultiWindow) {
- ProtoLog.e(WM_SHELL_TASK_ORG,
- "Can't pair tasks that doesn't support multi window, "
- + "task1.supportsMultiWindow=%b, task2.supportsMultiWindow=%b",
- task1.supportsMultiWindow, task2.supportsMultiWindow);
- return false;
- }
-
- mTaskInfo1 = task1;
- mTaskInfo2 = task2;
- mSplitLayout = new SplitLayout(TAG + "SplitDivider",
- mDisplayController.getDisplayContext(mRootTaskInfo.displayId),
- mRootTaskInfo.configuration, this /* layoutChangeListener */,
- mParentContainerCallbacks, mDisplayImeController, mController.getTaskOrganizer(),
- SplitLayout.PARALLAX_DISMISSING);
- mDisplayInsetsController.addInsetsChangedListener(mRootTaskInfo.displayId, mSplitLayout);
-
- final WindowContainerToken token1 = task1.token;
- final WindowContainerToken token2 = task2.token;
- final WindowContainerTransaction wct = new WindowContainerTransaction();
-
- wct.setHidden(mRootTaskInfo.token, false)
- .reparent(token1, mRootTaskInfo.token, true /* onTop */)
- .reparent(token2, mRootTaskInfo.token, true /* onTop */)
- .setWindowingMode(token1, WINDOWING_MODE_MULTI_WINDOW)
- .setWindowingMode(token2, WINDOWING_MODE_MULTI_WINDOW)
- .setBounds(token1, mSplitLayout.getBounds1())
- .setBounds(token2, mSplitLayout.getBounds2())
- // Moving the root task to top after the child tasks were repareted , or the root
- // task cannot be visible and focused.
- .reorder(mRootTaskInfo.token, true);
- mController.getTaskOrganizer().applyTransaction(wct);
- return true;
- }
-
- void unpair() {
- unpair(null /* toTopToken */);
- }
-
- private void unpair(@Nullable WindowContainerToken toTopToken) {
- final WindowContainerToken token1 = mTaskInfo1.token;
- final WindowContainerToken token2 = mTaskInfo2.token;
- final WindowContainerTransaction wct = new WindowContainerTransaction();
-
- // Reparent out of this container and reset windowing mode.
- wct.setHidden(mRootTaskInfo.token, true)
- .reorder(mRootTaskInfo.token, false)
- .reparent(token1, null, token1 == toTopToken /* onTop */)
- .reparent(token2, null, token2 == toTopToken /* onTop */)
- .setWindowingMode(token1, WINDOWING_MODE_UNDEFINED)
- .setWindowingMode(token2, WINDOWING_MODE_UNDEFINED);
- mController.getTaskOrganizer().applyTransaction(wct);
-
- mTaskInfo1 = null;
- mTaskInfo2 = null;
- mSplitLayout.release();
- mSplitLayout = null;
- }
-
- @Override
- public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash) {
- if (mRootTaskInfo == null || taskInfo.taskId == mRootTaskInfo.taskId) {
- mRootTaskInfo = taskInfo;
- mRootTaskLeash = leash;
- } else if (taskInfo.taskId == getTaskId1()) {
- mTaskInfo1 = taskInfo;
- mTaskLeash1 = leash;
- mSyncQueue.runInSync(t -> mDimLayer1 =
- SurfaceUtils.makeDimLayer(t, mTaskLeash1, "Dim layer", mSurfaceSession));
- } else if (taskInfo.taskId == getTaskId2()) {
- mTaskInfo2 = taskInfo;
- mTaskLeash2 = leash;
- mSyncQueue.runInSync(t -> mDimLayer2 =
- SurfaceUtils.makeDimLayer(t, mTaskLeash2, "Dim layer", mSurfaceSession));
- } else {
- throw new IllegalStateException("Unknown task=" + taskInfo.taskId);
- }
-
- if (mTaskLeash1 == null || mTaskLeash2 == null) return;
-
- mSplitLayout.init();
-
- mSyncQueue.runInSync(t -> t
- .show(mRootTaskLeash)
- .show(mTaskLeash1)
- .show(mTaskLeash2)
- .setPosition(mTaskLeash1,
- mTaskInfo1.positionInParent.x,
- mTaskInfo1.positionInParent.y)
- .setPosition(mTaskLeash2,
- mTaskInfo2.positionInParent.x,
- mTaskInfo2.positionInParent.y));
- }
-
- @Override
- public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) {
- if (!taskInfo.supportsMultiWindow) {
- // Dismiss AppPair if the task no longer supports multi window.
- mController.unpair(mRootTaskInfo.taskId);
- return;
- }
- if (taskInfo.taskId == getRootTaskId()) {
- if (mRootTaskInfo.isVisible != taskInfo.isVisible) {
- mSyncQueue.runInSync(t -> {
- if (taskInfo.isVisible) {
- t.show(mRootTaskLeash);
- } else {
- t.hide(mRootTaskLeash);
- }
- });
- }
- mRootTaskInfo = taskInfo;
-
- if (mSplitLayout != null
- && mSplitLayout.updateConfiguration(mRootTaskInfo.configuration)) {
- onLayoutSizeChanged(mSplitLayout);
- }
- } else if (taskInfo.taskId == getTaskId1()) {
- mTaskInfo1 = taskInfo;
- } else if (taskInfo.taskId == getTaskId2()) {
- mTaskInfo2 = taskInfo;
- } else {
- throw new IllegalStateException("Unknown task=" + taskInfo.taskId);
- }
- }
-
- @Override
- public int getSplitItemPosition(WindowContainerToken token) {
- if (token == null) {
- return SPLIT_POSITION_UNDEFINED;
- }
-
- if (token.equals(mTaskInfo1.getToken())) {
- return SPLIT_POSITION_TOP_OR_LEFT;
- } else if (token.equals(mTaskInfo2.getToken())) {
- return SPLIT_POSITION_BOTTOM_OR_RIGHT;
- }
-
- return SPLIT_POSITION_UNDEFINED;
- }
-
- @Override
- public void onTaskVanished(ActivityManager.RunningTaskInfo taskInfo) {
- if (taskInfo.taskId == getRootTaskId()) {
- // We don't want to release this object back to the pool since the root task went away.
- mController.unpair(mRootTaskInfo.taskId, false /* releaseToPool */);
- } else if (taskInfo.taskId == getTaskId1()) {
- mController.unpair(mRootTaskInfo.taskId);
- mSyncQueue.runInSync(t -> t.remove(mDimLayer1));
- } else if (taskInfo.taskId == getTaskId2()) {
- mController.unpair(mRootTaskInfo.taskId);
- mSyncQueue.runInSync(t -> t.remove(mDimLayer2));
- }
- }
-
- @Override
- public void attachChildSurfaceToTask(int taskId, SurfaceControl.Builder b) {
- b.setParent(findTaskSurface(taskId));
- }
-
- @Override
- public void reparentChildSurfaceToTask(int taskId, SurfaceControl sc,
- SurfaceControl.Transaction t) {
- t.reparent(sc, findTaskSurface(taskId));
- }
-
- private SurfaceControl findTaskSurface(int taskId) {
- if (getRootTaskId() == taskId) {
- return mRootTaskLeash;
- } else if (getTaskId1() == taskId) {
- return mTaskLeash1;
- } else if (getTaskId2() == taskId) {
- return mTaskLeash2;
- } else {
- throw new IllegalArgumentException("There is no surface for taskId=" + taskId);
- }
- }
-
- @Override
- public void dump(@NonNull PrintWriter pw, String prefix) {
- final String innerPrefix = prefix + " ";
- final String childPrefix = innerPrefix + " ";
- pw.println(prefix + this);
- if (mRootTaskInfo != null) {
- pw.println(innerPrefix + "Root taskId=" + mRootTaskInfo.taskId
- + " winMode=" + mRootTaskInfo.getWindowingMode());
- }
- if (mTaskInfo1 != null) {
- pw.println(innerPrefix + "1 taskId=" + mTaskInfo1.taskId
- + " winMode=" + mTaskInfo1.getWindowingMode());
- }
- if (mTaskInfo2 != null) {
- pw.println(innerPrefix + "2 taskId=" + mTaskInfo2.taskId
- + " winMode=" + mTaskInfo2.getWindowingMode());
- }
- }
-
- @Override
- public String toString() {
- return TAG + "#" + getRootTaskId();
- }
-
- @Override
- public void onSnappedToDismiss(boolean snappedToEnd) {
- unpair(snappedToEnd ? mTaskInfo1.token : mTaskInfo2.token /* toTopToken */);
- }
-
- @Override
- public void onLayoutPositionChanging(SplitLayout layout) {
- mSyncQueue.runInSync(t ->
- layout.applySurfaceChanges(t, mTaskLeash1, mTaskLeash2, mDimLayer1, mDimLayer2,
- true /* applyResizingOffset */));
- }
-
- @Override
- public void onLayoutSizeChanging(SplitLayout layout) {
- mSyncQueue.runInSync(t ->
- layout.applySurfaceChanges(t, mTaskLeash1, mTaskLeash2, mDimLayer1, mDimLayer2,
- true /* applyResizingOffset */));
- }
-
- @Override
- public void onLayoutSizeChanged(SplitLayout layout) {
- final WindowContainerTransaction wct = new WindowContainerTransaction();
- layout.applyTaskChanges(wct, mTaskInfo1, mTaskInfo2);
- mSyncQueue.queue(wct);
- mSyncQueue.runInSync(t ->
- layout.applySurfaceChanges(t, mTaskLeash1, mTaskLeash2, mDimLayer1, mDimLayer2,
- false /* applyResizingOffset */));
- }
-
- @Override
- public void setLayoutOffsetTarget(int offsetX, int offsetY, SplitLayout layout) {
- final WindowContainerTransaction wct = new WindowContainerTransaction();
- layout.applyLayoutOffsetTarget(wct, offsetX, offsetY, mTaskInfo1, mTaskInfo2);
- mController.getTaskOrganizer().applyTransaction(wct);
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairs.java b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairs.java
deleted file mode 100644
index a9b1dbc..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairs.java
+++ /dev/null
@@ -1,38 +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.wm.shell.apppairs;
-
-import android.app.ActivityManager;
-
-import androidx.annotation.NonNull;
-
-import com.android.wm.shell.common.annotations.ExternalThread;
-
-import java.io.PrintWriter;
-
-/**
- * Interface to engage app pairs feature.
- */
-@ExternalThread
-public interface AppPairs {
- /** Pairs indicated tasks. */
- boolean pair(int task1, int task2);
- /** Pairs indicated tasks. */
- boolean pair(ActivityManager.RunningTaskInfo task1, ActivityManager.RunningTaskInfo task2);
- /** Unpairs any app-pair containing this task id. */
- void unpair(int taskId);
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairsController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairsController.java
deleted file mode 100644
index 53234ab..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairsController.java
+++ /dev/null
@@ -1,213 +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.wm.shell.apppairs;
-
-import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_TASK_ORG;
-
-import android.app.ActivityManager;
-import android.util.Slog;
-import android.util.SparseArray;
-
-import androidx.annotation.NonNull;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
-import com.android.wm.shell.ShellTaskOrganizer;
-import com.android.wm.shell.common.DisplayController;
-import com.android.wm.shell.common.DisplayImeController;
-import com.android.wm.shell.common.DisplayInsetsController;
-import com.android.wm.shell.common.ShellExecutor;
-import com.android.wm.shell.common.SyncTransactionQueue;
-
-import java.io.PrintWriter;
-
-/**
- * Class manages app-pairs multitasking mode and implements the main interface {@link AppPairs}.
- */
-public class AppPairsController {
- private static final String TAG = AppPairsController.class.getSimpleName();
-
- private final ShellTaskOrganizer mTaskOrganizer;
- private final SyncTransactionQueue mSyncQueue;
- private final ShellExecutor mMainExecutor;
- private final AppPairsImpl mImpl = new AppPairsImpl();
-
- private AppPairsPool mPairsPool;
- // Active app-pairs mapped by root task id key.
- private final SparseArray<AppPair> mActiveAppPairs = new SparseArray<>();
- private final DisplayController mDisplayController;
- private final DisplayImeController mDisplayImeController;
- private final DisplayInsetsController mDisplayInsetsController;
-
- public AppPairsController(ShellTaskOrganizer organizer, SyncTransactionQueue syncQueue,
- DisplayController displayController, ShellExecutor mainExecutor,
- DisplayImeController displayImeController,
- DisplayInsetsController displayInsetsController) {
- mTaskOrganizer = organizer;
- mSyncQueue = syncQueue;
- mDisplayController = displayController;
- mDisplayImeController = displayImeController;
- mDisplayInsetsController = displayInsetsController;
- mMainExecutor = mainExecutor;
- }
-
- public AppPairs asAppPairs() {
- return mImpl;
- }
-
- public void onOrganizerRegistered() {
- if (mPairsPool == null) {
- setPairsPool(new AppPairsPool(this));
- }
- }
-
- @VisibleForTesting
- public void setPairsPool(AppPairsPool pool) {
- mPairsPool = pool;
- }
-
- public boolean pair(int taskId1, int taskId2) {
- final ActivityManager.RunningTaskInfo task1 = mTaskOrganizer.getRunningTaskInfo(taskId1);
- final ActivityManager.RunningTaskInfo task2 = mTaskOrganizer.getRunningTaskInfo(taskId2);
- if (task1 == null || task2 == null) {
- return false;
- }
- return pair(task1, task2);
- }
-
- public boolean pair(ActivityManager.RunningTaskInfo task1,
- ActivityManager.RunningTaskInfo task2) {
- return pairInner(task1, task2) != null;
- }
-
- @VisibleForTesting
- public AppPair pairInner(
- @NonNull ActivityManager.RunningTaskInfo task1,
- @NonNull ActivityManager.RunningTaskInfo task2) {
- final AppPair pair = mPairsPool.acquire();
- if (!pair.pair(task1, task2)) {
- mPairsPool.release(pair);
- return null;
- }
-
- mActiveAppPairs.put(pair.getRootTaskId(), pair);
- return pair;
- }
-
- public void unpair(int taskId) {
- unpair(taskId, true /* releaseToPool */);
- }
-
- public void unpair(int taskId, boolean releaseToPool) {
- AppPair pair = mActiveAppPairs.get(taskId);
- if (pair == null) {
- for (int i = mActiveAppPairs.size() - 1; i >= 0; --i) {
- final AppPair candidate = mActiveAppPairs.valueAt(i);
- if (candidate.contains(taskId)) {
- pair = candidate;
- break;
- }
- }
- }
- if (pair == null) {
- ProtoLog.v(WM_SHELL_TASK_ORG, "taskId %d isn't isn't in an app-pair.", taskId);
- return;
- }
-
- ProtoLog.v(WM_SHELL_TASK_ORG, "unpair taskId=%d pair=%s", taskId, pair);
- mActiveAppPairs.remove(pair.getRootTaskId());
- pair.unpair();
- if (releaseToPool) {
- mPairsPool.release(pair);
- }
- }
-
- ShellTaskOrganizer getTaskOrganizer() {
- return mTaskOrganizer;
- }
-
- SyncTransactionQueue getSyncTransactionQueue() {
- return mSyncQueue;
- }
-
- DisplayController getDisplayController() {
- return mDisplayController;
- }
-
- DisplayImeController getDisplayImeController() {
- return mDisplayImeController;
- }
-
- DisplayInsetsController getDisplayInsetsController() {
- return mDisplayInsetsController;
- }
-
- public void dump(@NonNull PrintWriter pw, String prefix) {
- final String innerPrefix = prefix + " ";
- final String childPrefix = innerPrefix + " ";
- pw.println(prefix + this);
-
- for (int i = mActiveAppPairs.size() - 1; i >= 0; --i) {
- mActiveAppPairs.valueAt(i).dump(pw, childPrefix);
- }
-
- if (mPairsPool != null) {
- mPairsPool.dump(pw, prefix);
- }
- }
-
- @Override
- public String toString() {
- return TAG + "#" + mActiveAppPairs.size();
- }
-
- private class AppPairsImpl implements AppPairs {
- @Override
- public boolean pair(int task1, int task2) {
- boolean[] result = new boolean[1];
- try {
- mMainExecutor.executeBlocking(() -> {
- result[0] = AppPairsController.this.pair(task1, task2);
- });
- } catch (InterruptedException e) {
- Slog.e(TAG, "Failed to pair tasks: " + task1 + ", " + task2);
- }
- return result[0];
- }
-
- @Override
- public boolean pair(ActivityManager.RunningTaskInfo task1,
- ActivityManager.RunningTaskInfo task2) {
- boolean[] result = new boolean[1];
- try {
- mMainExecutor.executeBlocking(() -> {
- result[0] = AppPairsController.this.pair(task1, task2);
- });
- } catch (InterruptedException e) {
- Slog.e(TAG, "Failed to pair tasks: " + task1 + ", " + task2);
- }
- return result[0];
- }
-
- @Override
- public void unpair(int taskId) {
- mMainExecutor.execute(() -> {
- AppPairsController.this.unpair(taskId);
- });
- }
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairsPool.java b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairsPool.java
deleted file mode 100644
index 5c6037e..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairsPool.java
+++ /dev/null
@@ -1,93 +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.wm.shell.apppairs;
-
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-import static android.view.Display.DEFAULT_DISPLAY;
-
-import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_TASK_ORG;
-
-import androidx.annotation.NonNull;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
-
-import java.io.PrintWriter;
-import java.util.ArrayList;
-
-/**
- * Class that manager pool of {@link AppPair} objects. Helps reduce the need to call system_server
- * to create a root task for the app-pair when needed since we always have one ready to go.
- */
-class AppPairsPool {
- private static final String TAG = AppPairsPool.class.getSimpleName();
-
- @VisibleForTesting
- final AppPairsController mController;
- // The pool
- private final ArrayList<AppPair> mPool = new ArrayList();
-
- AppPairsPool(AppPairsController controller) {
- mController = controller;
- incrementPool();
- }
-
- AppPair acquire() {
- final AppPair entry = mPool.remove(mPool.size() - 1);
- ProtoLog.v(WM_SHELL_TASK_ORG, "acquire entry.taskId=%s listener=%s size=%d",
- entry.getRootTaskId(), entry, mPool.size());
- if (mPool.size() == 0) {
- incrementPool();
- }
- return entry;
- }
-
- void release(AppPair entry) {
- mPool.add(entry);
- ProtoLog.v(WM_SHELL_TASK_ORG, "release entry.taskId=%s listener=%s size=%d",
- entry.getRootTaskId(), entry, mPool.size());
- }
-
- @VisibleForTesting
- void incrementPool() {
- ProtoLog.v(WM_SHELL_TASK_ORG, "incrementPool size=%d", mPool.size());
- final AppPair entry = new AppPair(mController);
- // TODO: multi-display...
- mController.getTaskOrganizer().createRootTask(
- DEFAULT_DISPLAY, WINDOWING_MODE_FULLSCREEN, entry);
- mPool.add(entry);
- }
-
- @VisibleForTesting
- int poolSize() {
- return mPool.size();
- }
-
- public void dump(@NonNull PrintWriter pw, String prefix) {
- final String innerPrefix = prefix + " ";
- final String childPrefix = innerPrefix + " ";
- pw.println(prefix + this);
- for (int i = mPool.size() - 1; i >= 0; --i) {
- mPool.get(i).dump(pw, childPrefix);
- }
- }
-
- @Override
- public String toString() {
- return TAG + "#" + mPool.size();
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/OWNERS b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/OWNERS
deleted file mode 100644
index 4d9b520..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# WM shell sub-modules apppair owner
-chenghsiuchang@google.com
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
index af9317a..14714a6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
@@ -58,6 +58,11 @@
@VisibleForTesting
boolean mEnableAnimations = SystemProperties.getInt(
"persist.wm.debug.predictive_back_anim", 0) != 0;
+ /**
+ * Max duration to wait for a transition to finish before accepting another gesture start
+ * request.
+ */
+ private static final long MAX_TRANSITION_DURATION = 2000;
/**
* Location of the initial touch event of the back gesture.
@@ -73,6 +78,8 @@
/** True when a back gesture is ongoing */
private boolean mBackGestureStarted = false;
+ /** Tracks if an uninterruptible transition is in progress */
+ private boolean mTransitionInProgress = false;
/** @see #setTriggerBack(boolean) */
private boolean mTriggerBack;
@@ -85,6 +92,12 @@
private IOnBackInvokedCallback mBackToLauncherCallback;
private float mTriggerThreshold;
private float mProgressThreshold;
+ private final Runnable mResetTransitionRunnable = () -> {
+ finishAnimation();
+ mTransitionInProgress = false;
+ ProtoLog.w(WM_SHELL_BACK_PREVIEW, "Transition didn't finish in %d ms. Resetting...",
+ MAX_TRANSITION_DURATION);
+ };
public BackAnimationController(
@ShellMainThread ShellExecutor shellExecutor,
@@ -189,7 +202,8 @@
mBackToLauncherCallback = null;
}
- private void onBackToLauncherAnimationFinished() {
+ @VisibleForTesting
+ void onBackToLauncherAnimationFinished() {
if (mBackNavigationInfo != null) {
IOnBackInvokedCallback callback = mBackNavigationInfo.getOnBackInvokedCallback();
if (mTriggerBack) {
@@ -206,6 +220,9 @@
* {@link BackAnimationController}
*/
public void onMotionEvent(MotionEvent event, int action, @BackEvent.SwipeEdge int swipeEdge) {
+ if (mTransitionInProgress) {
+ return;
+ }
if (action == MotionEvent.ACTION_MOVE) {
if (!mBackGestureStarted) {
// Let the animation initialized here to make sure the onPointerDownOutsideFocus
@@ -330,6 +347,9 @@
IOnBackInvokedCallback targetCallback = shouldDispatchToLauncher
? mBackToLauncherCallback
: mBackNavigationInfo.getOnBackInvokedCallback();
+ if (shouldDispatchToLauncher) {
+ startTransition();
+ }
if (mTriggerBack) {
dispatchOnBackInvoked(targetCallback);
} else {
@@ -401,6 +421,9 @@
* Sets to true when the back gesture has passed the triggering threshold, false otherwise.
*/
public void setTriggerBack(boolean triggerBack) {
+ if (mTransitionInProgress) {
+ return;
+ }
mTriggerBack = triggerBack;
}
@@ -432,6 +455,23 @@
mTransaction.remove(screenshotSurface);
}
mTransaction.apply();
+ stopTransition();
backNavigationInfo.onBackNavigationFinished(triggerBack);
}
+
+ private void startTransition() {
+ if (mTransitionInProgress) {
+ return;
+ }
+ mTransitionInProgress = true;
+ mShellExecutor.executeDelayed(mResetTransitionRunnable, MAX_TRANSITION_DURATION);
+ }
+
+ private void stopTransition() {
+ if (!mTransitionInProgress) {
+ return;
+ }
+ mShellExecutor.removeCallbacks(mResetTransitionRunnable);
+ mTransitionInProgress = false;
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java
index 3876533..f1ee8fa 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java
@@ -19,6 +19,7 @@
import android.annotation.Nullable;
import android.content.Context;
import android.content.res.TypedArray;
+import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Outline;
import android.graphics.Path;
@@ -182,7 +183,7 @@
getDrawingRect(mTempBounds);
- mDrawParams.color = mDotColor;
+ mDrawParams.dotColor = mDotColor;
mDrawParams.iconBounds = mTempBounds;
mDrawParams.leftAlign = mOnLeft;
mDrawParams.scale = mDotScale;
@@ -350,16 +351,19 @@
}
void showBadge() {
- if (mBubble.getAppBadge() == null) {
+ Bitmap appBadgeBitmap = mBubble.getAppBadge();
+ if (appBadgeBitmap == null) {
mAppIcon.setVisibility(GONE);
return;
}
+
int translationX;
if (mOnLeft) {
- translationX = -(mBubbleIcon.getWidth() - mAppIcon.getWidth());
+ translationX = -(mBubble.getBubbleIcon().getWidth() - appBadgeBitmap.getWidth());
} else {
translationX = 0;
}
+
mAppIcon.setTranslationX(translationX);
mAppIcon.setVisibility(VISIBLE);
}
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 f407bdc..ea3712b 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
@@ -25,6 +25,7 @@
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_CONTROLLER;
+import static com.android.wm.shell.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_GESTURE;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.wm.shell.bubbles.BubblePositioner.TASKBAR_POSITION_BOTTOM;
@@ -66,6 +67,7 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
+import android.os.UserManager;
import android.service.notification.NotificationListenerService;
import android.service.notification.NotificationListenerService.RankingMap;
import android.util.ArraySet;
@@ -78,7 +80,6 @@
import android.view.ViewGroup;
import android.view.WindowInsets;
import android.view.WindowManager;
-import android.window.WindowContainerTransaction;
import androidx.annotation.MainThread;
import androidx.annotation.Nullable;
@@ -89,13 +90,14 @@
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.TaskViewTransitions;
import com.android.wm.shell.WindowManagerShellWrapper;
-import com.android.wm.shell.common.DisplayChangeController;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.FloatingContentCoordinator;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.TaskStackListenerCallback;
import com.android.wm.shell.common.TaskStackListenerImpl;
+import com.android.wm.shell.common.annotations.ShellBackgroundThread;
+import com.android.wm.shell.common.annotations.ShellMainThread;
import com.android.wm.shell.draganddrop.DragAndDropController;
import com.android.wm.shell.onehanded.OneHandedController;
import com.android.wm.shell.onehanded.OneHandedTransitionCallback;
@@ -145,6 +147,7 @@
private final FloatingContentCoordinator mFloatingContentCoordinator;
private final BubbleDataRepository mDataRepository;
private final WindowManagerShellWrapper mWindowManagerShellWrapper;
+ private final UserManager mUserManager;
private final LauncherApps mLauncherApps;
private final IStatusBarService mBarService;
private final WindowManager mWindowManager;
@@ -158,6 +161,8 @@
private final ShellExecutor mMainExecutor;
private final Handler mMainHandler;
+ private final ShellExecutor mBackgroundExecutor;
+
private BubbleLogger mLogger;
private BubbleData mBubbleData;
@Nullable private BubbleStackView mStackView;
@@ -227,6 +232,7 @@
@Nullable IStatusBarService statusBarService,
WindowManager windowManager,
WindowManagerShellWrapper windowManagerShellWrapper,
+ UserManager userManager,
LauncherApps launcherApps,
TaskStackListenerImpl taskStackListener,
UiEventLogger uiEventLogger,
@@ -234,8 +240,9 @@
DisplayController displayController,
Optional<OneHandedController> oneHandedOptional,
DragAndDropController dragAndDropController,
- ShellExecutor mainExecutor,
- Handler mainHandler,
+ @ShellMainThread ShellExecutor mainExecutor,
+ @ShellMainThread Handler mainHandler,
+ @ShellBackgroundThread ShellExecutor bgExecutor,
TaskViewTransitions taskViewTransitions,
SyncTransactionQueue syncQueue) {
BubbleLogger logger = new BubbleLogger(uiEventLogger);
@@ -243,9 +250,9 @@
BubbleData data = new BubbleData(context, logger, positioner, mainExecutor);
return new BubbleController(context, data, synchronizer, floatingContentCoordinator,
new BubbleDataRepository(context, launcherApps, mainExecutor),
- statusBarService, windowManager, windowManagerShellWrapper, launcherApps,
- logger, taskStackListener, organizer, positioner, displayController,
- oneHandedOptional, dragAndDropController, mainExecutor, mainHandler,
+ statusBarService, windowManager, windowManagerShellWrapper, userManager,
+ launcherApps, logger, taskStackListener, organizer, positioner, displayController,
+ oneHandedOptional, dragAndDropController, mainExecutor, mainHandler, bgExecutor,
taskViewTransitions, syncQueue);
}
@@ -261,6 +268,7 @@
@Nullable IStatusBarService statusBarService,
WindowManager windowManager,
WindowManagerShellWrapper windowManagerShellWrapper,
+ UserManager userManager,
LauncherApps launcherApps,
BubbleLogger bubbleLogger,
TaskStackListenerImpl taskStackListener,
@@ -269,8 +277,9 @@
DisplayController displayController,
Optional<OneHandedController> oneHandedOptional,
DragAndDropController dragAndDropController,
- ShellExecutor mainExecutor,
- Handler mainHandler,
+ @ShellMainThread ShellExecutor mainExecutor,
+ @ShellMainThread Handler mainHandler,
+ @ShellBackgroundThread ShellExecutor bgExecutor,
TaskViewTransitions taskViewTransitions,
SyncTransactionQueue syncQueue) {
mContext = context;
@@ -281,11 +290,13 @@
: statusBarService;
mWindowManager = windowManager;
mWindowManagerShellWrapper = windowManagerShellWrapper;
+ mUserManager = userManager;
mFloatingContentCoordinator = floatingContentCoordinator;
mDataRepository = dataRepository;
mLogger = bubbleLogger;
mMainExecutor = mainExecutor;
mMainHandler = mainHandler;
+ mBackgroundExecutor = bgExecutor;
mTaskStackListener = taskStackListener;
mTaskOrganizer = organizer;
mSurfaceSynchronizer = synchronizer;
@@ -423,23 +434,23 @@
});
mDisplayController.addDisplayChangingController(
- new DisplayChangeController.OnDisplayChangingListener() {
- @Override
- public void onRotateDisplay(int displayId, int fromRotation, int toRotation,
- WindowContainerTransaction t) {
- // This is triggered right before the rotation is applied
- if (fromRotation != toRotation) {
- if (mStackView != null) {
- // Layout listener set on stackView will update the positioner
- // once the rotation is applied
- mStackView.onOrientationChanged();
- }
+ (displayId, fromRotation, toRotation, newDisplayAreaInfo, t) -> {
+ // This is triggered right before the rotation is applied
+ if (fromRotation != toRotation) {
+ if (mStackView != null) {
+ // Layout listener set on stackView will update the positioner
+ // once the rotation is applied
+ mStackView.onOrientationChanged();
}
}
});
mOneHandedOptional.ifPresent(this::registerOneHandedState);
mDragAndDropController.addListener(this::collapseStack);
+
+ // Clear out any persisted bubbles on disk that no longer have a valid user.
+ List<UserInfo> users = mUserManager.getAliveUsers();
+ mDataRepository.sanitizeBubbles(users);
}
@VisibleForTesting
@@ -583,6 +594,17 @@
mCurrentProfiles = currentProfiles;
}
+ /** Called when a user is removed from the device, including work profiles. */
+ public void onUserRemoved(int removedUserId) {
+ UserInfo parent = mUserManager.getProfileParent(removedUserId);
+ int parentUserId = parent != null ? parent.getUserHandle().getIdentifier() : -1;
+ mBubbleData.removeBubblesForUser(removedUserId);
+ // Typically calls from BubbleData would remove bubbles from the DataRepository as well,
+ // however, this gets complicated when users are removed (mCurrentUserId won't necessarily
+ // be correct for this) so we update the repo directly.
+ mDataRepository.removeBubblesForUser(removedUserId, parentUserId);
+ }
+
/** Whether this userId belongs to the current user. */
private boolean isCurrentProfile(int userId) {
return userId == UserHandle.USER_ALL
@@ -725,7 +747,8 @@
try {
mAddedToWindowManager = false;
- mContext.unregisterReceiver(mBroadcastReceiver);
+ // Put on background for this binder call, was causing jank
+ mBackgroundExecutor.execute(() -> mContext.unregisterReceiver(mBroadcastReceiver));
if (mStackView != null) {
mWindowManager.removeView(mStackView);
mBubbleData.getOverflow().cleanUpExpandedState();
@@ -857,6 +880,19 @@
}
}
+ private void onNotificationPanelExpandedChanged(boolean expanded) {
+ if (DEBUG_BUBBLE_GESTURE) {
+ Log.d(TAG, "onNotificationPanelExpandedChanged: expanded=" + expanded);
+ }
+ if (mStackView != null && mStackView.isExpanded()) {
+ if (expanded) {
+ mStackView.stopMonitoringSwipeUpGesture();
+ } else {
+ mStackView.startMonitoringSwipeUpGesture();
+ }
+ }
+ }
+
private void setSysuiProxy(Bubbles.SysuiProxy proxy) {
mSysuiProxy = proxy;
}
@@ -1440,6 +1476,18 @@
}
/**
+ * Check if notification panel is in an expanded state.
+ * Makes a call to System UI process and delivers the result via {@code callback} on the
+ * WM Shell main thread.
+ *
+ * @param callback callback that has the result of notification panel expanded state
+ */
+ public void isNotificationPanelExpanded(Consumer<Boolean> callback) {
+ mSysuiProxy.isNotificationPanelExpand(expanded ->
+ mMainExecutor.execute(() -> callback.accept(expanded)));
+ }
+
+ /**
* Description of current bubble state.
*/
private void dump(PrintWriter pw, String[] args) {
@@ -1518,7 +1566,7 @@
public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {
mBubblePositioner.setImeVisible(imeVisible, imeHeight);
if (mStackView != null) {
- mStackView.animateForIme(imeVisible);
+ mStackView.setImeVisible(imeVisible);
}
}
}
@@ -1801,6 +1849,13 @@
}
@Override
+ public void onUserRemoved(int removedUserId) {
+ mMainExecutor.execute(() -> {
+ BubbleController.this.onUserRemoved(removedUserId);
+ });
+ }
+
+ @Override
public void onConfigChanged(Configuration newConfig) {
mMainExecutor.execute(() -> {
BubbleController.this.onConfigChanged(newConfig);
@@ -1808,6 +1863,12 @@
}
@Override
+ public void onNotificationPanelExpandedChanged(boolean expanded) {
+ mMainExecutor.execute(
+ () -> BubbleController.this.onNotificationPanelExpandedChanged(expanded));
+ }
+
+ @Override
public void dump(PrintWriter pw, String[] args) {
try {
mMainExecutor.executeBlocking(() -> {
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 e4a0fd0..fa86c84 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
@@ -465,7 +465,7 @@
getOverflowBubbles(), invalidBubblesFromPackage, removeBubble);
}
- /** Dismisses all bubbles from the given package. */
+ /** Removes all bubbles from the given package. */
public void removeBubblesWithPackageName(String packageName, int reason) {
final Predicate<Bubble> bubbleMatchesPackage = bubble ->
bubble.getPackageName().equals(packageName);
@@ -477,6 +477,18 @@
performActionOnBubblesMatching(getOverflowBubbles(), bubbleMatchesPackage, removeBubble);
}
+ /** Removes all bubbles for the given user. */
+ public void removeBubblesForUser(int userId) {
+ List<Bubble> removedBubbles = filterAllBubbles(bubble ->
+ userId == bubble.getUser().getIdentifier());
+ for (Bubble b : removedBubbles) {
+ doRemove(b.getKey(), Bubbles.DISMISS_USER_REMOVED);
+ }
+ if (!removedBubbles.isEmpty()) {
+ dispatchPendingChanges();
+ }
+ }
+
private void doAdd(Bubble bubble) {
if (DEBUG_BUBBLE_DATA) {
Log.d(TAG, "doAdd: " + bubble);
@@ -552,7 +564,8 @@
|| reason == Bubbles.DISMISS_BLOCKED
|| reason == Bubbles.DISMISS_SHORTCUT_REMOVED
|| reason == Bubbles.DISMISS_PACKAGE_REMOVED
- || reason == Bubbles.DISMISS_USER_CHANGED;
+ || reason == Bubbles.DISMISS_USER_CHANGED
+ || reason == Bubbles.DISMISS_USER_REMOVED;
int indexToRemove = indexForKey(key);
if (indexToRemove == -1) {
@@ -1073,6 +1086,35 @@
return null;
}
+ /**
+ * Returns a list of bubbles that match the provided predicate. This checks all types of
+ * bubbles (i.e. pending, suppressed, active, and overflowed).
+ */
+ private List<Bubble> filterAllBubbles(Predicate<Bubble> predicate) {
+ ArrayList<Bubble> matchingBubbles = new ArrayList<>();
+ for (Bubble b : mPendingBubbles.values()) {
+ if (predicate.test(b)) {
+ matchingBubbles.add(b);
+ }
+ }
+ for (Bubble b : mSuppressedBubbles.values()) {
+ if (predicate.test(b)) {
+ matchingBubbles.add(b);
+ }
+ }
+ for (Bubble b : mBubbles) {
+ if (predicate.test(b)) {
+ matchingBubbles.add(b);
+ }
+ }
+ for (Bubble b : mOverflowBubbles) {
+ if (predicate.test(b)) {
+ matchingBubbles.add(b);
+ }
+ }
+ return matchingBubbles;
+ }
+
@VisibleForTesting(visibility = PRIVATE)
void setTimeSource(TimeSource timeSource) {
mTimeSource = timeSource;
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 9d9e442..97560f4 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
@@ -22,6 +22,7 @@
import android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_CACHED
import android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_DYNAMIC
import android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_PINNED_BY_ANY_LAUNCHER
+import android.content.pm.UserInfo
import android.os.UserHandle
import android.util.Log
import com.android.wm.shell.bubbles.storage.BubbleEntity
@@ -73,6 +74,22 @@
if (entities.isNotEmpty()) persistToDisk()
}
+ /**
+ * Removes all the bubbles associated with the provided user from memory. Then persists the
+ * snapshot to disk asynchronously.
+ */
+ fun removeBubblesForUser(@UserIdInt userId: Int, @UserIdInt parentId: Int) {
+ if (volatileRepository.removeBubblesForUser(userId, parentId)) persistToDisk()
+ }
+
+ /**
+ * Remove any bubbles that don't have a user id from the provided list of users.
+ */
+ fun sanitizeBubbles(users: List<UserInfo>) {
+ val userIds = users.map { u -> u.id }
+ if (volatileRepository.sanitizeBubbles(userIds)) persistToDisk()
+ }
+
private fun transform(bubbles: List<Bubble>): List<BubbleEntity> {
return bubbles.mapNotNull { b ->
BubbleEntity(
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDebugConfig.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDebugConfig.java
index dc2ace9..dce6b56 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDebugConfig.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDebugConfig.java
@@ -46,6 +46,9 @@
static final boolean DEBUG_OVERFLOW = false;
static final boolean DEBUG_USER_EDUCATION = false;
static final boolean DEBUG_POSITIONER = false;
+ public static final boolean DEBUG_COLLAPSE_ANIMATOR = false;
+ static final boolean DEBUG_BUBBLE_GESTURE = false;
+ public static boolean DEBUG_EXPANDED_VIEW_DRAGGING = false;
private static final boolean FORCE_SHOW_USER_EDUCATION = false;
private static final String FORCE_SHOW_USER_EDUCATION_SETTING =
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
index a089585..1eb6f73 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
@@ -43,10 +43,13 @@
import android.graphics.Outline;
import android.graphics.Paint;
import android.graphics.Picture;
+import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.drawable.ShapeDrawable;
import android.os.RemoteException;
import android.util.AttributeSet;
+import android.util.FloatProperty;
+import android.util.IntProperty;
import android.util.Log;
import android.util.TypedValue;
import android.view.LayoutInflater;
@@ -75,6 +78,48 @@
public class BubbleExpandedView extends LinearLayout {
private static final String TAG = TAG_WITH_CLASS_NAME ? "BubbleExpandedView" : TAG_BUBBLES;
+ /** {@link IntProperty} for updating bottom clip */
+ public static final IntProperty<BubbleExpandedView> BOTTOM_CLIP_PROPERTY =
+ new IntProperty<BubbleExpandedView>("bottomClip") {
+ @Override
+ public void setValue(BubbleExpandedView expandedView, int value) {
+ expandedView.setBottomClip(value);
+ }
+
+ @Override
+ public Integer get(BubbleExpandedView expandedView) {
+ return expandedView.mBottomClip;
+ }
+ };
+
+ /** {@link FloatProperty} for updating taskView or overflow alpha */
+ public static final FloatProperty<BubbleExpandedView> CONTENT_ALPHA =
+ new FloatProperty<BubbleExpandedView>("contentAlpha") {
+ @Override
+ public void setValue(BubbleExpandedView expandedView, float value) {
+ expandedView.setContentAlpha(value);
+ }
+
+ @Override
+ public Float get(BubbleExpandedView expandedView) {
+ return expandedView.getContentAlpha();
+ }
+ };
+
+ /** {@link FloatProperty} for updating manage button alpha */
+ public static final FloatProperty<BubbleExpandedView> MANAGE_BUTTON_ALPHA =
+ new FloatProperty<BubbleExpandedView>("manageButtonAlpha") {
+ @Override
+ public void setValue(BubbleExpandedView expandedView, float value) {
+ expandedView.mManageButton.setAlpha(value);
+ }
+
+ @Override
+ public Float get(BubbleExpandedView expandedView) {
+ return expandedView.mManageButton.getAlpha();
+ }
+ };
+
// The triangle pointing to the expanded view
private View mPointerView;
@Nullable private int[] mExpandedViewContainerLocation;
@@ -90,7 +135,7 @@
/**
* Whether we want the {@code TaskView}'s content to be visible (alpha = 1f). If
- * {@link #mIsAlphaAnimating} is true, this may not reflect the {@code TaskView}'s actual alpha
+ * {@link #mIsAnimating} is true, this may not reflect the {@code TaskView}'s actual alpha
* value until the animation ends.
*/
private boolean mIsContentVisible = false;
@@ -99,12 +144,13 @@
* Whether we're animating the {@code TaskView}'s alpha value. If so, we will hold off on
* applying alpha changes from {@link #setContentVisibility} until the animation ends.
*/
- private boolean mIsAlphaAnimating = false;
+ private boolean mIsAnimating = false;
private int mPointerWidth;
private int mPointerHeight;
private float mPointerRadius;
private float mPointerOverlap;
+ private final PointF mPointerPos = new PointF();
private CornerPathEffect mPointerEffect;
private ShapeDrawable mCurrentPointer;
private ShapeDrawable mTopPointer;
@@ -113,11 +159,13 @@
private float mCornerRadius = 0f;
private int mBackgroundColorFloating;
private boolean mUsingMaxHeight;
-
+ private int mTopClip = 0;
+ private int mBottomClip = 0;
@Nullable private Bubble mBubble;
private PendingIntent mPendingIntent;
// TODO(b/170891664): Don't use a flag, set the BubbleOverflow object instead
private boolean mIsOverflow;
+ private boolean mIsClipping;
private BubbleController mController;
private BubbleStackView mStackView;
@@ -268,7 +316,8 @@
mExpandedViewContainer.setOutlineProvider(new ViewOutlineProvider() {
@Override
public void getOutline(View view, Outline outline) {
- outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), mCornerRadius);
+ Rect clip = new Rect(0, mTopClip, view.getWidth(), view.getHeight() - mBottomClip);
+ outline.setRoundRect(clip, mCornerRadius);
}
});
mExpandedViewContainer.setClipToOutline(true);
@@ -300,9 +349,9 @@
// they should not collapse the stack (which all other touches on areas around the AV
// would do).
if (motionEvent.getRawY() >= avBounds.top
- && motionEvent.getRawY() <= avBounds.bottom
- && (motionEvent.getRawX() < avBounds.left
- || motionEvent.getRawX() > avBounds.right)) {
+ && motionEvent.getRawY() <= avBounds.bottom
+ && (motionEvent.getRawX() < avBounds.left
+ || motionEvent.getRawX() > avBounds.right)) {
return true;
}
@@ -384,7 +433,7 @@
}
void applyThemeAttrs() {
- final TypedArray ta = mContext.obtainStyledAttributes(new int[] {
+ final TypedArray ta = mContext.obtainStyledAttributes(new int[]{
android.R.attr.dialogCornerRadius,
android.R.attr.colorBackgroundFloating});
boolean supportsRoundedCorners = ScreenDecorationsUtils.supportsRoundedCornersOnWindows(
@@ -429,7 +478,7 @@
* ordering surfaces during animations. When content is drawn on top of the app (e.g. bubble
* being dragged out, the manage menu) this is set to false, otherwise it should be true.
*/
- void setSurfaceZOrderedOnTop(boolean onTop) {
+ public void setSurfaceZOrderedOnTop(boolean onTop) {
if (mTaskView == null) {
return;
}
@@ -510,12 +559,12 @@
}
/**
- * Whether we are currently animating the {@code TaskView}'s alpha value. If this is set to
+ * Whether we are currently animating the {@code TaskView}. If this is set to
* true, calls to {@link #setContentVisibility} will not be applied until this is set to false
* again.
*/
- void setAlphaAnimating(boolean animating) {
- mIsAlphaAnimating = animating;
+ public void setAnimating(boolean animating) {
+ mIsAnimating = animating;
// If we're done animating, apply the correct
if (!animating) {
@@ -524,15 +573,128 @@
}
/**
- * Sets the alpha of the underlying {@code TaskView}, since changing the expanded view's alpha
- * does not affect the {@code TaskView} since it uses a Surface.
+ * Get alpha from underlying {@code TaskView} if this view is for a bubble.
+ * Or get alpha for the overflow view if this view is for overflow.
+ *
+ * @return alpha for the content being shown
*/
- void setTaskViewAlpha(float alpha) {
+ public float getContentAlpha() {
+ if (mIsOverflow) {
+ return mOverflowView.getAlpha();
+ }
if (mTaskView != null) {
+ return mTaskView.getAlpha();
+ }
+ return 1f;
+ }
+
+ /**
+ * Set alpha of the underlying {@code TaskView} if this view is for a bubble.
+ * Or set alpha for the overflow view if this view is for overflow.
+ *
+ * Changing expanded view's alpha does not affect the {@code TaskView} since it uses a Surface.
+ */
+ public void setContentAlpha(float alpha) {
+ if (mIsOverflow) {
+ mOverflowView.setAlpha(alpha);
+ } else if (mTaskView != null) {
mTaskView.setAlpha(alpha);
}
- mPointerView.setAlpha(alpha);
- setAlpha(alpha);
+ }
+
+ /**
+ * Set translation Y for the expanded view content.
+ * Excludes manage button and pointer.
+ */
+ public void setContentTranslationY(float translationY) {
+ mExpandedViewContainer.setTranslationY(translationY);
+
+ // Left or right pointer can become detached when moving the view up
+ if (translationY <= 0 && (isShowingLeftPointer() || isShowingRightPointer())) {
+ // Y coordinate where the pointer would start to get detached from the expanded view.
+ // Takes into account bottom clipping and rounded corners
+ float detachPoint =
+ mExpandedViewContainer.getBottom() - mBottomClip - mCornerRadius + translationY;
+ float pointerBottom = mPointerPos.y + mPointerHeight;
+ // If pointer bottom is past detach point, move it in by that many pixels
+ float horizontalShift = 0;
+ if (pointerBottom > detachPoint) {
+ horizontalShift = pointerBottom - detachPoint;
+ }
+ if (isShowingLeftPointer()) {
+ // Move left pointer right
+ movePointerBy(horizontalShift, 0);
+ } else {
+ // Move right pointer left
+ movePointerBy(-horizontalShift, 0);
+ }
+ // Hide pointer if it is moved by entire width
+ mPointerView.setVisibility(
+ horizontalShift > mPointerWidth ? View.INVISIBLE : View.VISIBLE);
+ }
+ }
+
+ /**
+ * Update alpha value for the manage button
+ */
+ public void setManageButtonAlpha(float alpha) {
+ mManageButton.setAlpha(alpha);
+ }
+
+ /**
+ * Set {@link #setTranslationY(float) translationY} for the manage button
+ */
+ public void setManageButtonTranslationY(float translationY) {
+ mManageButton.setTranslationY(translationY);
+ }
+
+ /**
+ * Set top clipping for the view
+ */
+ public void setTopClip(int clip) {
+ mTopClip = clip;
+ onContainerClipUpdate();
+ }
+
+ /**
+ * Set bottom clipping for the view
+ */
+ public void setBottomClip(int clip) {
+ mBottomClip = clip;
+ onContainerClipUpdate();
+ }
+
+ private void onContainerClipUpdate() {
+ if (mTopClip == 0 && mBottomClip == 0) {
+ if (mIsClipping) {
+ mIsClipping = false;
+ if (mTaskView != null) {
+ mTaskView.setClipBounds(null);
+ mTaskView.setEnableSurfaceClipping(false);
+ }
+ mExpandedViewContainer.invalidateOutline();
+ }
+ } else {
+ if (!mIsClipping) {
+ mIsClipping = true;
+ if (mTaskView != null) {
+ mTaskView.setEnableSurfaceClipping(true);
+ }
+ }
+ mExpandedViewContainer.invalidateOutline();
+ if (mTaskView != null) {
+ mTaskView.setClipBounds(new Rect(0, mTopClip, mTaskView.getWidth(),
+ mTaskView.getHeight() - mBottomClip));
+ }
+ }
+ }
+
+ /**
+ * Move pointer from base position
+ */
+ public void movePointerBy(float x, float y) {
+ mPointerView.setTranslationX(mPointerPos.x + x);
+ mPointerView.setTranslationY(mPointerPos.y + y);
}
/**
@@ -543,13 +705,13 @@
* Note that this contents visibility doesn't affect visibility at {@link android.view.View},
* and setting {@code false} actually means rendering the contents in transparent.
*/
- void setContentVisibility(boolean visibility) {
+ public void setContentVisibility(boolean visibility) {
if (DEBUG_BUBBLE_EXPANDED_VIEW) {
Log.d(TAG, "setContentVisibility: visibility=" + visibility
+ " bubble=" + getBubbleKey());
}
mIsContentVisible = visibility;
- if (mTaskView != null && !mIsAlphaAnimating) {
+ if (mTaskView != null && !mIsAnimating) {
mTaskView.setAlpha(visibility ? 1f : 0f);
mPointerView.setAlpha(visibility ? 1f : 0f);
}
@@ -560,6 +722,44 @@
return mTaskView;
}
+ @VisibleForTesting
+ public BubbleOverflowContainerView getOverflow() {
+ return mOverflowView;
+ }
+
+
+ /**
+ * Return content height: taskView or overflow.
+ * Takes into account clippings set by {@link #setTopClip(int)} and {@link #setBottomClip(int)}
+ *
+ * @return if bubble is for overflow, return overflow height, otherwise return taskView height
+ */
+ public int getContentHeight() {
+ if (mIsOverflow) {
+ return mOverflowView.getHeight() - mTopClip - mBottomClip;
+ }
+ if (mTaskView != null) {
+ return mTaskView.getHeight() - mTopClip - mBottomClip;
+ }
+ return 0;
+ }
+
+ /**
+ * Return bottom position of the content on screen
+ *
+ * @return if bubble is for overflow, return value for overflow, otherwise taskView
+ */
+ public int getContentBottomOnScreen() {
+ Rect out = new Rect();
+ if (mIsOverflow) {
+ mOverflowView.getBoundsOnScreen(out);
+ }
+ if (mTaskView != null) {
+ mTaskView.getBoundsOnScreen(out);
+ }
+ return out.bottom;
+ }
+
int getTaskId() {
return mTaskId;
}
@@ -728,28 +928,48 @@
post(() -> {
mCurrentPointer = showVertically ? onLeft ? mLeftPointer : mRightPointer : mTopPointer;
updatePointerView();
- float pointerY;
- float pointerX;
if (showVertically) {
- pointerY = bubbleCenter - (mPointerWidth / 2f);
- pointerX = onLeft
+ mPointerPos.y = bubbleCenter - (mPointerWidth / 2f);
+ mPointerPos.x = onLeft
? -mPointerHeight + mPointerOverlap
: getWidth() - mPaddingRight - mPointerOverlap;
} else {
- pointerY = mPointerOverlap;
- pointerX = bubbleCenter - (mPointerWidth / 2f);
+ mPointerPos.y = mPointerOverlap;
+ mPointerPos.x = bubbleCenter - (mPointerWidth / 2f);
}
if (animate) {
- mPointerView.animate().translationX(pointerX).translationY(pointerY).start();
+ mPointerView.animate().translationX(mPointerPos.x).translationY(
+ mPointerPos.y).start();
} else {
- mPointerView.setTranslationY(pointerY);
- mPointerView.setTranslationX(pointerX);
+ mPointerView.setTranslationY(mPointerPos.y);
+ mPointerView.setTranslationX(mPointerPos.x);
mPointerView.setVisibility(VISIBLE);
}
});
}
/**
+ * Return true if pointer is shown on the left
+ */
+ public boolean isShowingLeftPointer() {
+ return mCurrentPointer == mLeftPointer;
+ }
+
+ /**
+ * Return true if pointer is shown on the right
+ */
+ public boolean isShowingRightPointer() {
+ return mCurrentPointer == mRightPointer;
+ }
+
+ /**
+ * Return width of the current pointer
+ */
+ public int getPointerWidth() {
+ return mPointerWidth;
+ }
+
+ /**
* Position of the manage button displayed in the expanded view. Used for placing user
* education about the manage button.
*/
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
index 7cfacbc..7d60114 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
@@ -344,6 +344,14 @@
return mImeVisible ? mImeHeight : 0;
}
+ /** Return top position of the IME if it's visible */
+ public int getImeTop() {
+ if (mImeVisible) {
+ return getScreenRect().bottom - getImeHeight() - getInsets().bottom;
+ }
+ return 0;
+ }
+
/** Sets whether the IME is visible. **/
public void setImeVisible(boolean visible, int height) {
mImeVisible = visible;
@@ -706,4 +714,21 @@
public void setPinnedLocation(PointF point) {
mPinLocation = point;
}
+
+ /**
+ * Navigation bar has an area where system gestures can be started from.
+ *
+ * @return {@link Rect} for system navigation bar gesture zone
+ */
+ public Rect getNavBarGestureZone() {
+ // Gesture zone height from the bottom
+ int gestureZoneHeight = mContext.getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.navigation_bar_gesture_height);
+ Rect screen = getScreenRect();
+ return new Rect(
+ screen.left,
+ screen.bottom - gestureZoneHeight,
+ screen.right,
+ screen.bottom);
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
index b7c5eb0..828ad63 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
@@ -21,6 +21,7 @@
import static com.android.wm.shell.animation.Interpolators.ALPHA_IN;
import static com.android.wm.shell.animation.Interpolators.ALPHA_OUT;
+import static com.android.wm.shell.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_GESTURE;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_STACK_VIEW;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
@@ -44,6 +45,7 @@
import android.graphics.RectF;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
+import android.os.SystemProperties;
import android.provider.Settings;
import android.util.Log;
import android.view.Choreographer;
@@ -56,6 +58,7 @@
import android.view.ViewGroup;
import android.view.ViewOutlineProvider;
import android.view.ViewTreeObserver;
+import android.view.WindowManagerPolicyConstants;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
import android.widget.FrameLayout;
@@ -75,8 +78,12 @@
import com.android.wm.shell.R;
import com.android.wm.shell.animation.Interpolators;
import com.android.wm.shell.animation.PhysicsAnimator;
+import com.android.wm.shell.bubbles.BubblesNavBarMotionEventHandler.MotionEventListener;
import com.android.wm.shell.bubbles.animation.AnimatableScaleMatrix;
import com.android.wm.shell.bubbles.animation.ExpandedAnimationController;
+import com.android.wm.shell.bubbles.animation.ExpandedViewAnimationController;
+import com.android.wm.shell.bubbles.animation.ExpandedViewAnimationControllerImpl;
+import com.android.wm.shell.bubbles.animation.ExpandedViewAnimationControllerStub;
import com.android.wm.shell.bubbles.animation.PhysicsAnimationLayout;
import com.android.wm.shell.bubbles.animation.StackAnimationController;
import com.android.wm.shell.common.FloatingContentCoordinator;
@@ -97,6 +104,12 @@
*/
public class BubbleStackView extends FrameLayout
implements ViewTreeObserver.OnComputeInternalInsetsListener {
+ /**
+ * Set to {@code true} to enable home gesture handling in bubbles
+ */
+ public static final boolean HOME_GESTURE_ENABLED =
+ SystemProperties.getBoolean("persist.wm.debug.bubbles_home_gesture", false);
+
private static final String TAG = TAG_WITH_CLASS_NAME ? "BubbleStackView" : TAG_BUBBLES;
/** How far the flyout needs to be dragged before it's dismissed regardless of velocity. */
@@ -148,7 +161,7 @@
* Handler to use for all delayed animations - this way, we can easily cancel them before
* starting a new animation.
*/
- private final ShellExecutor mDelayedAnimationExecutor;
+ private final ShellExecutor mMainExecutor;
private Runnable mDelayedAnimation;
/**
@@ -197,6 +210,7 @@
private PhysicsAnimationLayout mBubbleContainer;
private StackAnimationController mStackAnimationController;
private ExpandedAnimationController mExpandedAnimationController;
+ private ExpandedViewAnimationController mExpandedViewAnimationController;
private View mScrim;
private View mManageMenuScrim;
@@ -276,6 +290,9 @@
*/
private int mPointerIndexDown = -1;
+ @Nullable
+ private BubblesNavBarGestureTracker mBubblesNavBarGestureTracker;
+
/** Description of current animation controller state. */
public void dump(PrintWriter pw, String[] args) {
pw.println("Stack view state:");
@@ -693,6 +710,67 @@
}
};
+ /** Touch listener set on the whole view that forwards event to the swipe up listener. */
+ private final RelativeTouchListener mContainerSwipeListener = new RelativeTouchListener() {
+ @Override
+ public boolean onDown(@NonNull View v, @NonNull MotionEvent ev) {
+ // Pass move event on to swipe listener
+ mSwipeUpListener.onDown(ev.getX(), ev.getY());
+ return true;
+ }
+
+ @Override
+ public void onMove(@NonNull View v, @NonNull MotionEvent ev, float viewInitialX,
+ float viewInitialY, float dx, float dy) {
+ // Pass move event on to swipe listener
+ mSwipeUpListener.onMove(dx, dy);
+ }
+
+ @Override
+ public void onUp(@NonNull View v, @NonNull MotionEvent ev, float viewInitialX,
+ float viewInitialY, float dx, float dy, float velX, float velY) {
+ // Pass up even on to swipe listener
+ mSwipeUpListener.onUp(velX, velY);
+ }
+ };
+
+ /** MotionEventListener that listens from home gesture swipe event. */
+ private final MotionEventListener mSwipeUpListener = new MotionEventListener() {
+ @Override
+ public void onDown(float x, float y) {}
+
+ @Override
+ public void onMove(float dx, float dy) {
+ if ((mManageEduView != null && mManageEduView.getVisibility() == VISIBLE)
+ || isStackEduShowing()) {
+ return;
+ }
+
+ if (mShowingManage) {
+ showManageMenu(false /* show */);
+ }
+ // Only allow up
+ float collapsed = Math.min(dy, 0);
+ mExpandedViewAnimationController.updateDrag((int) -collapsed);
+ }
+
+ @Override
+ public void onCancel() {
+ mExpandedViewAnimationController.animateBackToExpanded();
+ }
+
+ @Override
+ public void onUp(float velX, float velY) {
+ mExpandedViewAnimationController.setSwipeVelocity(velY);
+ if (mExpandedViewAnimationController.shouldCollapse()) {
+ // Update data first and start the animation when we are processing change
+ mBubbleData.setExpanded(false);
+ } else {
+ mExpandedViewAnimationController.animateBackToExpanded();
+ }
+ }
+ };
+
/** Click listener set on the flyout, which expands the stack when the flyout is tapped. */
private OnClickListener mFlyoutClickListener = new OnClickListener() {
@Override
@@ -766,7 +844,7 @@
ShellExecutor mainExecutor) {
super(context);
- mDelayedAnimationExecutor = mainExecutor;
+ mMainExecutor = mainExecutor;
mBubbleController = bubbleController;
mBubbleData = data;
@@ -796,6 +874,14 @@
mExpandedAnimationController = new ExpandedAnimationController(mPositioner,
onBubbleAnimatedOut, this);
+
+ if (HOME_GESTURE_ENABLED) {
+ mExpandedViewAnimationController =
+ new ExpandedViewAnimationControllerImpl(context, mPositioner);
+ } else {
+ mExpandedViewAnimationController = new ExpandedViewAnimationControllerStub();
+ }
+
mSurfaceSynchronizer = synchronizer != null ? synchronizer : DEFAULT_SURFACE_SYNCHRONIZER;
// Force LTR by default since most of the Bubbles UI is positioned manually by the user, or
@@ -971,7 +1057,7 @@
if (mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) {
// We need to be Z ordered on top in order for alpha animations to work.
mExpandedBubble.getExpandedView().setSurfaceZOrderedOnTop(true);
- mExpandedBubble.getExpandedView().setAlphaAnimating(true);
+ mExpandedBubble.getExpandedView().setAnimating(true);
}
}
@@ -985,14 +1071,15 @@
// = 0f remains in effect.
&& !mExpandedViewTemporarilyHidden) {
mExpandedBubble.getExpandedView().setSurfaceZOrderedOnTop(false);
- mExpandedBubble.getExpandedView().setAlphaAnimating(false);
+ mExpandedBubble.getExpandedView().setAnimating(false);
}
}
});
mExpandedViewAlphaAnimator.addUpdateListener(valueAnimator -> {
if (mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) {
- mExpandedBubble.getExpandedView().setTaskViewAlpha(
- (float) valueAnimator.getAnimatedValue());
+ float alpha = (float) valueAnimator.getAnimatedValue();
+ mExpandedBubble.getExpandedView().setContentAlpha(alpha);
+ mExpandedBubble.getExpandedView().setAlpha(alpha);
}
});
@@ -1795,6 +1882,7 @@
private void showNewlySelectedBubble(BubbleViewProvider bubbleToSelect) {
final BubbleViewProvider previouslySelected = mExpandedBubble;
mExpandedBubble = bubbleToSelect;
+ mExpandedViewAnimationController.setExpandedView(mExpandedBubble.getExpandedView());
if (mIsExpanded) {
hideCurrentInputMethod();
@@ -1843,12 +1931,19 @@
return;
}
+ boolean wasExpanded = mIsExpanded;
+
hideCurrentInputMethod();
mBubbleController.getSysuiProxy().onStackExpandChanged(shouldExpand);
- if (mIsExpanded) {
- animateCollapse();
+ if (wasExpanded) {
+ stopMonitoringSwipeUpGesture();
+ if (HOME_GESTURE_ENABLED) {
+ animateCollapse();
+ } else {
+ animateCollapseWithScale();
+ }
logBubbleEvent(mExpandedBubble, FrameworkStatsLog.BUBBLE_UICHANGED__ACTION__COLLAPSED);
} else {
animateExpansion();
@@ -1856,11 +1951,58 @@
logBubbleEvent(mExpandedBubble, FrameworkStatsLog.BUBBLE_UICHANGED__ACTION__EXPANDED);
logBubbleEvent(mExpandedBubble,
FrameworkStatsLog.BUBBLE_UICHANGED__ACTION__STACK_EXPANDED);
+ if (HOME_GESTURE_ENABLED) {
+ mBubbleController.isNotificationPanelExpanded(notifPanelExpanded -> {
+ if (!notifPanelExpanded && mIsExpanded) {
+ startMonitoringSwipeUpGesture();
+ }
+ });
+ }
}
notifyExpansionChanged(mExpandedBubble, mIsExpanded);
}
/**
+ * Monitor for swipe up gesture that is used to collapse expanded view
+ */
+ void startMonitoringSwipeUpGesture() {
+ if (DEBUG_BUBBLE_GESTURE) {
+ Log.d(TAG, "startMonitoringSwipeUpGesture");
+ }
+ stopMonitoringSwipeUpGestureInternal();
+
+ if (isGestureNavEnabled()) {
+ mBubblesNavBarGestureTracker = new BubblesNavBarGestureTracker(mContext, mPositioner);
+ mBubblesNavBarGestureTracker.start(mSwipeUpListener);
+ setOnTouchListener(mContainerSwipeListener);
+ }
+ }
+
+ private boolean isGestureNavEnabled() {
+ return mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_navBarInteractionMode)
+ == WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL;
+ }
+
+ /**
+ * Stop monitoring for swipe up gesture
+ */
+ void stopMonitoringSwipeUpGesture() {
+ if (DEBUG_BUBBLE_GESTURE) {
+ Log.d(TAG, "stopMonitoringSwipeUpGesture");
+ }
+ stopMonitoringSwipeUpGestureInternal();
+ }
+
+ private void stopMonitoringSwipeUpGestureInternal() {
+ if (mBubblesNavBarGestureTracker != null) {
+ mBubblesNavBarGestureTracker.stop();
+ mBubblesNavBarGestureTracker = null;
+ setOnTouchListener(null);
+ }
+ }
+
+ /**
* Called when back press occurs while bubbles are expanded.
*/
public void onBackPressed() {
@@ -2072,11 +2214,12 @@
mExpandedViewContainer.setAnimationMatrix(mExpandedViewContainerMatrix);
if (mExpandedBubble.getExpandedView() != null) {
- mExpandedBubble.getExpandedView().setTaskViewAlpha(0f);
+ mExpandedBubble.getExpandedView().setContentAlpha(0f);
+ mExpandedBubble.getExpandedView().setAlpha(0f);
// We'll be starting the alpha animation after a slight delay, so set this flag early
// here.
- mExpandedBubble.getExpandedView().setAlphaAnimating(true);
+ mExpandedBubble.getExpandedView().setAnimating(true);
}
mDelayedAnimation = () -> {
@@ -2114,10 +2257,10 @@
})
.start();
};
- mDelayedAnimationExecutor.executeDelayed(mDelayedAnimation, startDelay);
+ mMainExecutor.executeDelayed(mDelayedAnimation, startDelay);
}
- private void animateCollapse() {
+ private void animateCollapseWithScale() {
cancelDelayedExpandCollapseSwitchAnimations();
if (mManageEduView != null && mManageEduView.getVisibility() == VISIBLE) {
@@ -2217,6 +2360,68 @@
.start();
}
+ private void animateCollapse() {
+ cancelDelayedExpandCollapseSwitchAnimations();
+
+ if (mManageEduView != null && mManageEduView.getVisibility() == VISIBLE) {
+ mManageEduView.hide();
+ }
+
+ mIsExpanded = false;
+ mIsExpansionAnimating = true;
+
+ showScrim(false);
+
+ mBubbleContainer.cancelAllAnimations();
+
+ // If we were in the middle of swapping, the animating-out surface would have been scaling
+ // to zero - finish it off.
+ PhysicsAnimator.getInstance(mAnimatingOutSurfaceContainer).cancel();
+ mAnimatingOutSurfaceContainer.setScaleX(0f);
+ mAnimatingOutSurfaceContainer.setScaleY(0f);
+
+ // Let the expanded animation controller know that it shouldn't animate child adds/reorders
+ // since we're about to animate collapsed.
+ mExpandedAnimationController.notifyPreparingToCollapse();
+
+ final Runnable collapseBackToStack = () -> mExpandedAnimationController.collapseBackToStack(
+ mStackAnimationController
+ .getStackPositionAlongNearestHorizontalEdge()
+ /* collapseTo */,
+ () -> mBubbleContainer.setActiveController(mStackAnimationController));
+
+ final Runnable after = () -> {
+ final BubbleViewProvider previouslySelected = mExpandedBubble;
+ // TODO(b/231350255): investigate why this call is needed here
+ beforeExpandedViewAnimation();
+ if (mManageEduView != null) {
+ mManageEduView.hide();
+ }
+
+ if (DEBUG_BUBBLE_STACK_VIEW) {
+ Log.d(TAG, "animateCollapse");
+ Log.d(TAG, BubbleDebugConfig.formatBubblesString(getBubblesOnScreen(),
+ mExpandedBubble));
+ }
+ updateOverflowVisibility();
+ updateZOrder();
+ updateBadges(true /* setBadgeForCollapsedStack */);
+ afterExpandedViewAnimation();
+ if (previouslySelected != null) {
+ previouslySelected.setTaskViewVisibility(false);
+ }
+ mExpandedViewAnimationController.reset();
+ };
+ mExpandedViewAnimationController.animateCollapse(collapseBackToStack, after);
+ if (mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) {
+ // When the animation completes, we should no longer be showing the content.
+ // This won't actually update content visibility immediately, if we are currently
+ // animating. But updates the internal state for the content to be hidden after
+ // animation completes.
+ mExpandedBubble.getExpandedView().setContentVisibility(false);
+ }
+ }
+
private void animateSwitchBubbles() {
// If we're no longer expanded, this is meaningless.
if (!mIsExpanded) {
@@ -2278,7 +2483,7 @@
mExpandedViewContainer.setAnimationMatrix(mExpandedViewContainerMatrix);
- mDelayedAnimationExecutor.executeDelayed(() -> {
+ mMainExecutor.executeDelayed(() -> {
if (!mIsExpanded) {
mIsBubbleSwitchAnimating = false;
return;
@@ -2309,7 +2514,7 @@
* animating flags for those animations.
*/
private void cancelDelayedExpandCollapseSwitchAnimations() {
- mDelayedAnimationExecutor.removeCallbacks(mDelayedAnimation);
+ mMainExecutor.removeCallbacks(mDelayedAnimation);
mIsExpansionAnimating = false;
mIsBubbleSwitchAnimating = false;
@@ -2333,9 +2538,18 @@
/**
* Updates the stack based for IME changes. When collapsed it'll move the stack if it
* overlaps where they IME would be. When expanded it'll shift the expanded bubbles
- * if they might overlap with the IME (this only happens for large screens).
+ * if they might overlap with the IME (this only happens for large screens)
+ * and clip the expanded view.
*/
- public void animateForIme(boolean visible) {
+ public void setImeVisible(boolean visible) {
+ if (HOME_GESTURE_ENABLED) {
+ setImeVisibleInternal(visible);
+ } else {
+ setImeVisibleWithoutClipping(visible);
+ }
+ }
+
+ private void setImeVisibleWithoutClipping(boolean visible) {
if ((mIsExpansionAnimating || mIsBubbleSwitchAnimating) && mIsExpanded) {
// This will update the animation so the bubbles move to position for the IME
mExpandedAnimationController.expandFromStack(() -> {
@@ -2386,6 +2600,62 @@
}
}
+ private void setImeVisibleInternal(boolean visible) {
+ if ((mIsExpansionAnimating || mIsBubbleSwitchAnimating) && mIsExpanded) {
+ // This will update the animation so the bubbles move to position for the IME
+ mExpandedAnimationController.expandFromStack(() -> {
+ updatePointerPosition(false /* forIme */);
+ afterExpandedViewAnimation();
+ mExpandedViewAnimationController.animateForImeVisibilityChange(visible);
+ } /* after */);
+ return;
+ }
+
+ if (!mIsExpanded && getBubbleCount() > 0) {
+ final float stackDestinationY =
+ mStackAnimationController.animateForImeVisibility(visible);
+
+ // How far the stack is animating due to IME, we'll just animate the flyout by that
+ // much too.
+ final float stackDy =
+ stackDestinationY - mStackAnimationController.getStackPosition().y;
+
+ // If the flyout is visible, translate it along with the bubble stack.
+ if (mFlyout.getVisibility() == VISIBLE) {
+ PhysicsAnimator.getInstance(mFlyout)
+ .spring(DynamicAnimation.TRANSLATION_Y,
+ mFlyout.getTranslationY() + stackDy,
+ FLYOUT_IME_ANIMATION_SPRING_CONFIG)
+ .start();
+ }
+ }
+
+ if (mIsExpanded) {
+ mExpandedViewAnimationController.animateForImeVisibilityChange(visible);
+ if (mPositioner.showBubblesVertically()
+ && mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) {
+ float selectedY = mPositioner.getExpandedBubbleXY(getState().selectedIndex,
+ getState()).y;
+ float newExpandedViewTop = mPositioner.getExpandedViewY(mExpandedBubble, selectedY);
+ mExpandedBubble.getExpandedView().setImeVisible(visible);
+ if (!mExpandedBubble.getExpandedView().isUsingMaxHeight()) {
+ mExpandedViewContainer.animate().translationY(newExpandedViewTop);
+ }
+ List<Animator> animList = new ArrayList();
+ for (int i = 0; i < mBubbleContainer.getChildCount(); i++) {
+ View child = mBubbleContainer.getChildAt(i);
+ float transY = mPositioner.getExpandedBubbleXY(i, getState()).y;
+ ObjectAnimator anim = ObjectAnimator.ofFloat(child, TRANSLATION_Y, transY);
+ animList.add(anim);
+ }
+ updatePointerPosition(true /* forIme */);
+ AnimatorSet set = new AnimatorSet();
+ set.playTogether(animList);
+ set.start();
+ }
+ }
+ }
+
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() != MotionEvent.ACTION_DOWN && ev.getActionIndex() != mPointerIndexDown) {
@@ -2821,7 +3091,7 @@
&& mExpandedBubble.getExpandedView() != null) {
BubbleExpandedView bev = mExpandedBubble.getExpandedView();
bev.setContentVisibility(false);
- bev.setAlphaAnimating(!mIsExpansionAnimating);
+ bev.setAnimating(!mIsExpansionAnimating);
mExpandedViewContainerMatrix.setScaleX(0f);
mExpandedViewContainerMatrix.setScaleY(0f);
mExpandedViewContainerMatrix.setTranslate(0f, 0f);
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 c7db8d8..0072da1 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
@@ -57,7 +57,7 @@
DISMISS_NOTIF_CANCEL, DISMISS_ACCESSIBILITY_ACTION, DISMISS_NO_LONGER_BUBBLE,
DISMISS_USER_CHANGED, DISMISS_GROUP_CANCELLED, DISMISS_INVALID_INTENT,
DISMISS_OVERFLOW_MAX_REACHED, DISMISS_SHORTCUT_REMOVED, DISMISS_PACKAGE_REMOVED,
- DISMISS_NO_BUBBLE_UP, DISMISS_RELOAD_FROM_DISK})
+ DISMISS_NO_BUBBLE_UP, DISMISS_RELOAD_FROM_DISK, DISMISS_USER_REMOVED})
@Target({FIELD, LOCAL_VARIABLE, PARAMETER})
@interface DismissReason {}
@@ -76,6 +76,7 @@
int DISMISS_PACKAGE_REMOVED = 13;
int DISMISS_NO_BUBBLE_UP = 14;
int DISMISS_RELOAD_FROM_DISK = 15;
+ int DISMISS_USER_REMOVED = 16;
/**
* @return {@code true} if there is a bubble associated with the provided key and if its
@@ -213,6 +214,11 @@
int modificationType);
/**
+ * Called when notification panel is expanded or collapsed
+ */
+ void onNotificationPanelExpandedChanged(boolean expanded);
+
+ /**
* Called when the status bar has become visible or invisible (either permanently or
* temporarily).
*/
@@ -243,6 +249,13 @@
void onCurrentProfilesChanged(SparseArray<UserInfo> currentProfiles);
/**
+ * Called when a user is removed.
+ *
+ * @param removedUserId the id of the removed user.
+ */
+ void onUserRemoved(int removedUserId);
+
+ /**
* Called when config changed.
*
* @param newConfig the new config.
@@ -277,7 +290,7 @@
/** Callback to tell SysUi components execute some methods. */
interface SysuiProxy {
- void isNotificationShadeExpand(Consumer<Boolean> callback);
+ void isNotificationPanelExpand(Consumer<Boolean> callback);
void getPendingOrActiveEntry(String key, Consumer<BubbleEntry> callback);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblesNavBarGestureTracker.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblesNavBarGestureTracker.java
new file mode 100644
index 0000000..e7beeeb
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblesNavBarGestureTracker.java
@@ -0,0 +1,104 @@
+/*
+ * 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.bubbles;
+
+import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES;
+import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
+
+import android.content.Context;
+import android.hardware.input.InputManager;
+import android.util.Log;
+import android.view.Choreographer;
+import android.view.InputChannel;
+import android.view.InputEventReceiver;
+import android.view.InputMonitor;
+
+import androidx.annotation.Nullable;
+
+import com.android.wm.shell.bubbles.BubblesNavBarMotionEventHandler.MotionEventListener;
+
+/**
+ * Set up tracking bubbles gestures that begin in navigation bar
+ */
+class BubblesNavBarGestureTracker {
+
+ private static final String TAG = TAG_WITH_CLASS_NAME ? "BubblesGestureTracker" : TAG_BUBBLES;
+
+ private static final String GESTURE_MONITOR = "bubbles-gesture";
+ private final Context mContext;
+ private final BubblePositioner mPositioner;
+
+ @Nullable
+ private InputMonitor mInputMonitor;
+ @Nullable
+ private InputEventReceiver mInputEventReceiver;
+
+ BubblesNavBarGestureTracker(Context context, BubblePositioner positioner) {
+ mContext = context;
+ mPositioner = positioner;
+ }
+
+ /**
+ * Start tracking gestures
+ *
+ * @param listener listener that is notified of touch events
+ */
+ void start(MotionEventListener listener) {
+ if (BubbleDebugConfig.DEBUG_BUBBLE_GESTURE) {
+ Log.d(TAG, "start monitoring bubbles swipe up gesture");
+ }
+
+ stopInternal();
+
+ mInputMonitor = InputManager.getInstance().monitorGestureInput(GESTURE_MONITOR,
+ mContext.getDisplayId());
+ InputChannel inputChannel = mInputMonitor.getInputChannel();
+
+ BubblesNavBarMotionEventHandler motionEventHandler =
+ new BubblesNavBarMotionEventHandler(mContext, mPositioner,
+ this::onInterceptTouch, listener);
+ mInputEventReceiver = new BubblesNavBarInputEventReceiver(inputChannel,
+ Choreographer.getInstance(), motionEventHandler);
+ }
+
+ void stop() {
+ if (BubbleDebugConfig.DEBUG_BUBBLE_GESTURE) {
+ Log.d(TAG, "stop monitoring bubbles swipe up gesture");
+ }
+ stopInternal();
+ }
+
+ private void stopInternal() {
+ if (mInputEventReceiver != null) {
+ mInputEventReceiver.dispose();
+ mInputEventReceiver = null;
+ }
+ if (mInputMonitor != null) {
+ mInputMonitor.dispose();
+ mInputMonitor = null;
+ }
+ }
+
+ private void onInterceptTouch() {
+ if (BubbleDebugConfig.DEBUG_BUBBLE_GESTURE) {
+ Log.d(TAG, "intercept touch event");
+ }
+ if (mInputMonitor != null) {
+ mInputMonitor.pilferPointers();
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblesNavBarInputEventReceiver.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblesNavBarInputEventReceiver.java
new file mode 100644
index 0000000..45037b8
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblesNavBarInputEventReceiver.java
@@ -0,0 +1,51 @@
+/*
+ * 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.bubbles;
+
+import android.os.Looper;
+import android.view.BatchedInputEventReceiver;
+import android.view.Choreographer;
+import android.view.InputChannel;
+import android.view.InputEvent;
+import android.view.MotionEvent;
+
+/**
+ * Bubbles {@link BatchedInputEventReceiver} for monitoring touches from navbar gesture area
+ */
+class BubblesNavBarInputEventReceiver extends BatchedInputEventReceiver {
+
+ private final BubblesNavBarMotionEventHandler mMotionEventHandler;
+
+ BubblesNavBarInputEventReceiver(InputChannel inputChannel,
+ Choreographer choreographer, BubblesNavBarMotionEventHandler motionEventHandler) {
+ super(inputChannel, Looper.myLooper(), choreographer);
+ mMotionEventHandler = motionEventHandler;
+ }
+
+ @Override
+ public void onInputEvent(InputEvent event) {
+ boolean handled = false;
+ try {
+ if (!(event instanceof MotionEvent)) {
+ return;
+ }
+ handled = mMotionEventHandler.onMotionEvent((MotionEvent) event);
+ } finally {
+ finishInputEvent(event, handled);
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblesNavBarMotionEventHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblesNavBarMotionEventHandler.java
new file mode 100644
index 0000000..844526c
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblesNavBarMotionEventHandler.java
@@ -0,0 +1,175 @@
+/*
+ * 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.bubbles;
+
+import static com.android.wm.shell.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_GESTURE;
+import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES;
+import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
+
+import android.content.Context;
+import android.graphics.PointF;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.VelocityTracker;
+import android.view.ViewConfiguration;
+
+import androidx.annotation.Nullable;
+
+/**
+ * Handles {@link MotionEvent}s for bubbles that begin in the nav bar area
+ */
+class BubblesNavBarMotionEventHandler {
+ private static final String TAG =
+ TAG_WITH_CLASS_NAME ? "BubblesNavBarMotionEventHandler" : TAG_BUBBLES;
+ private static final int VELOCITY_UNITS = 1000;
+
+ private final Runnable mOnInterceptTouch;
+ private final MotionEventListener mMotionEventListener;
+ private final int mTouchSlop;
+ private final BubblePositioner mPositioner;
+ private final PointF mTouchDown = new PointF();
+ private boolean mTrackingTouches;
+ private boolean mInterceptingTouches;
+ @Nullable
+ private VelocityTracker mVelocityTracker;
+
+ BubblesNavBarMotionEventHandler(Context context, BubblePositioner positioner,
+ Runnable onInterceptTouch, MotionEventListener motionEventListener) {
+ mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
+ mPositioner = positioner;
+ mOnInterceptTouch = onInterceptTouch;
+ mMotionEventListener = motionEventListener;
+ }
+
+ /**
+ * Handle {@link MotionEvent} and forward it to {@code motionEventListener} defined in
+ * constructor
+ *
+ * @return {@code true} if this {@link MotionEvent} is handled (it started in the gesture area)
+ */
+ public boolean onMotionEvent(MotionEvent motionEvent) {
+ float dx = motionEvent.getX() - mTouchDown.x;
+ float dy = motionEvent.getY() - mTouchDown.y;
+
+ switch (motionEvent.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ if (isInGestureRegion(motionEvent)) {
+ mTouchDown.set(motionEvent.getX(), motionEvent.getY());
+ mMotionEventListener.onDown(motionEvent.getX(), motionEvent.getY());
+ mTrackingTouches = true;
+ return true;
+ }
+ break;
+ case MotionEvent.ACTION_MOVE:
+ if (mTrackingTouches) {
+ if (!mInterceptingTouches && Math.hypot(dx, dy) > mTouchSlop) {
+ mInterceptingTouches = true;
+ mOnInterceptTouch.run();
+ }
+ if (mInterceptingTouches) {
+ getVelocityTracker().addMovement(motionEvent);
+ mMotionEventListener.onMove(dx, dy);
+ }
+ return true;
+ }
+ break;
+ case MotionEvent.ACTION_CANCEL:
+ if (mTrackingTouches) {
+ mMotionEventListener.onCancel();
+ finishTracking();
+ return true;
+ }
+ break;
+ case MotionEvent.ACTION_UP:
+ if (mTrackingTouches) {
+ if (mInterceptingTouches) {
+ getVelocityTracker().computeCurrentVelocity(VELOCITY_UNITS);
+ mMotionEventListener.onUp(getVelocityTracker().getXVelocity(),
+ getVelocityTracker().getYVelocity());
+ }
+ finishTracking();
+ return true;
+ }
+ break;
+ }
+ return false;
+ }
+
+ private boolean isInGestureRegion(MotionEvent ev) {
+ // Only handles touch events beginning in navigation bar system gesture zone
+ if (mPositioner.getNavBarGestureZone().contains((int) ev.getX(), (int) ev.getY())) {
+ if (DEBUG_BUBBLE_GESTURE) {
+ Log.d(TAG, "handling touch y=" + ev.getY()
+ + " navBarGestureZone=" + mPositioner.getNavBarGestureZone());
+ }
+ return true;
+ }
+ return false;
+ }
+
+ private VelocityTracker getVelocityTracker() {
+ if (mVelocityTracker == null) {
+ mVelocityTracker = VelocityTracker.obtain();
+ }
+ return mVelocityTracker;
+ }
+
+ private void finishTracking() {
+ mTouchDown.set(0, 0);
+ mTrackingTouches = false;
+ mInterceptingTouches = false;
+ if (mVelocityTracker != null) {
+ mVelocityTracker.recycle();
+ mVelocityTracker = null;
+ }
+ }
+
+ /**
+ * Callback for receiving {@link MotionEvent} updates
+ */
+ interface MotionEventListener {
+ /**
+ * Touch down action.
+ *
+ * @param x x coordinate
+ * @param y y coordinate
+ */
+ void onDown(float x, float y);
+
+ /**
+ * Move action.
+ * Reports distance from point reported in {@link #onDown(float, float)}
+ *
+ * @param dx distance moved on x-axis from starting point, in pixels
+ * @param dy distance moved on y-axis from starting point, in pixels
+ */
+ void onMove(float dx, float dy);
+
+ /**
+ * Touch up action.
+ *
+ * @param velX velocity of the move action on x axis
+ * @param velY velocity of the move actin on y axis
+ */
+ void onUp(float velX, float velY);
+
+ /**
+ * Motion action was cancelled.
+ */
+ void onCancel();
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/RelativeTouchListener.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/RelativeTouchListener.kt
index cf0cefe..ea9d065 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/RelativeTouchListener.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/RelativeTouchListener.kt
@@ -17,8 +17,6 @@
package com.android.wm.shell.bubbles
import android.graphics.PointF
-import android.os.Handler
-import android.os.Looper
import android.view.MotionEvent
import android.view.VelocityTracker
import android.view.View
@@ -146,6 +144,12 @@
velocityTracker.clear()
movedEnough = false
}
+
+ MotionEvent.ACTION_CANCEL -> {
+ v.handler.removeCallbacksAndMessages(null)
+ velocityTracker.clear()
+ movedEnough = false
+ }
}
return true
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java
index 573f424..c24efb9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java
@@ -17,11 +17,13 @@
package com.android.wm.shell.bubbles.animation;
import static com.android.wm.shell.bubbles.BubblePositioner.NUM_VISIBLE_WHEN_RESTING;
+import static com.android.wm.shell.bubbles.BubbleStackView.HOME_GESTURE_ENABLED;
import android.content.res.Resources;
import android.graphics.Path;
import android.graphics.PointF;
import android.view.View;
+import android.view.animation.Interpolator;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -61,7 +63,10 @@
private static final float DAMPING_RATIO_MEDIUM_LOW_BOUNCY = 0.65f;
/** Stiffness for the expand/collapse path-following animation. */
- private static final int EXPAND_COLLAPSE_ANIM_STIFFNESS = 1000;
+ private static final int EXPAND_COLLAPSE_ANIM_STIFFNESS = 400;
+
+ /** Stiffness for the expand/collapse animation when home gesture handling is off */
+ private static final int EXPAND_COLLAPSE_ANIM_STIFFNESS_WITHOUT_HOME_GESTURE = 1000;
/**
* Velocity required to dismiss an individual bubble without dragging it into the dismiss
@@ -73,6 +78,11 @@
new PhysicsAnimator.SpringConfig(
EXPAND_COLLAPSE_ANIM_STIFFNESS, SpringForce.DAMPING_RATIO_NO_BOUNCY);
+ private final PhysicsAnimator.SpringConfig mAnimateOutSpringConfigWithoutHomeGesture =
+ new PhysicsAnimator.SpringConfig(
+ EXPAND_COLLAPSE_ANIM_STIFFNESS_WITHOUT_HOME_GESTURE,
+ SpringForce.DAMPING_RATIO_NO_BOUNCY);
+
/** Horizontal offset between bubbles, which we need to know to re-stack them. */
private float mStackOffsetPx;
/** Size of each bubble. */
@@ -278,11 +288,20 @@
(firstBubbleLeads && index == 0)
|| (!firstBubbleLeads && index == mLayout.getChildCount() - 1);
+ Interpolator interpolator;
+ if (HOME_GESTURE_ENABLED) {
+ // When home gesture is enabled, we use a different animation timing for collapse
+ interpolator = expanding
+ ? Interpolators.EMPHASIZED_ACCELERATE : Interpolators.EMPHASIZED_DECELERATE;
+ } else {
+ interpolator = Interpolators.LINEAR;
+ }
+
animation
.followAnimatedTargetAlongPath(
path,
EXPAND_COLLAPSE_TARGET_ANIM_DURATION /* targetAnimDuration */,
- Interpolators.LINEAR /* targetAnimInterpolator */,
+ interpolator /* targetAnimInterpolator */,
isLeadBubble ? mLeadBubbleEndAction : null /* endAction */,
() -> mLeadBubbleEndAction = null /* endAction */)
.withStartDelay(startDelay)
@@ -525,10 +544,16 @@
finishRemoval.run();
mOnBubbleAnimatedOutAction.run();
} else {
+ PhysicsAnimator.SpringConfig springConfig;
+ if (HOME_GESTURE_ENABLED) {
+ springConfig = mAnimateOutSpringConfig;
+ } else {
+ springConfig = mAnimateOutSpringConfigWithoutHomeGesture;
+ }
PhysicsAnimator.getInstance(child)
.spring(DynamicAnimation.ALPHA, 0f)
- .spring(DynamicAnimation.SCALE_X, 0f, mAnimateOutSpringConfig)
- .spring(DynamicAnimation.SCALE_Y, 0f, mAnimateOutSpringConfig)
+ .spring(DynamicAnimation.SCALE_X, 0f, springConfig)
+ .spring(DynamicAnimation.SCALE_Y, 0f, springConfig)
.withEndActions(finishRemoval, mOnBubbleAnimatedOutAction)
.start();
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedViewAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedViewAnimationController.java
new file mode 100644
index 0000000..8a33780
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedViewAnimationController.java
@@ -0,0 +1,75 @@
+/*
+ * 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.bubbles.animation;
+
+import com.android.wm.shell.bubbles.BubbleExpandedView;
+
+/**
+ * Animation controller for bubble expanded view collapsing
+ */
+public interface ExpandedViewAnimationController {
+ /**
+ * Set expanded view that this controller is working with.
+ */
+ void setExpandedView(BubbleExpandedView expandedView);
+
+ /**
+ * Set current collapse value, in pixels.
+ *
+ * @param distance pixels that user dragged the view by
+ */
+ void updateDrag(float distance);
+
+ /**
+ * Set current swipe velocity.
+ * Velocity is directional:
+ * <ul>
+ * <li>velocity < 0 means swipe direction is up</li>
+ * <li>velocity > 0 means swipe direction is down</li>
+ * </ul>
+ */
+ void setSwipeVelocity(float velocity);
+
+ /**
+ * Check if view is dragged past collapse threshold or swipe up velocity exceeds min velocity
+ * required to collapse the view
+ */
+ boolean shouldCollapse();
+
+ /**
+ * Animate view to collapsed state
+ *
+ * @param startStackCollapse runnable that is triggered when bubbles can start moving back to
+ * their collapsed location
+ * @param after runnable to run after animation is complete
+ */
+ void animateCollapse(Runnable startStackCollapse, Runnable after);
+
+ /**
+ * Animate the view back to fully expanded state.
+ */
+ void animateBackToExpanded();
+
+ /**
+ * Animate view for IME visibility change
+ */
+ void animateForImeVisibilityChange(boolean visible);
+
+ /**
+ * Reset the view to fully expanded state
+ */
+ void reset();
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedViewAnimationControllerImpl.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedViewAnimationControllerImpl.java
new file mode 100644
index 0000000..ca54232
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedViewAnimationControllerImpl.java
@@ -0,0 +1,432 @@
+/*
+ * 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.bubbles.animation;
+
+import static android.view.View.ALPHA;
+
+import static com.android.wm.shell.bubbles.BubbleDebugConfig.DEBUG_COLLAPSE_ANIMATOR;
+import static com.android.wm.shell.bubbles.BubbleDebugConfig.DEBUG_EXPANDED_VIEW_DRAGGING;
+import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES;
+import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.wm.shell.bubbles.BubbleExpandedView.BOTTOM_CLIP_PROPERTY;
+import static com.android.wm.shell.bubbles.BubbleExpandedView.CONTENT_ALPHA;
+import static com.android.wm.shell.bubbles.BubbleExpandedView.MANAGE_BUTTON_ALPHA;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.util.Log;
+import android.view.HapticFeedbackConstants;
+import android.view.ViewConfiguration;
+
+import androidx.annotation.Nullable;
+import androidx.dynamicanimation.animation.DynamicAnimation;
+import androidx.dynamicanimation.animation.FloatPropertyCompat;
+import androidx.dynamicanimation.animation.SpringAnimation;
+import androidx.dynamicanimation.animation.SpringForce;
+
+import com.android.wm.shell.animation.FlingAnimationUtils;
+import com.android.wm.shell.animation.Interpolators;
+import com.android.wm.shell.bubbles.BubbleExpandedView;
+import com.android.wm.shell.bubbles.BubblePositioner;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Implementation of {@link ExpandedViewAnimationController} that uses a collapse animation to
+ * hide the {@link BubbleExpandedView}
+ */
+public class ExpandedViewAnimationControllerImpl implements ExpandedViewAnimationController {
+
+ private static final String TAG = TAG_WITH_CLASS_NAME ? "ExpandedViewAnimCtrl" : TAG_BUBBLES;
+
+ private static final float COLLAPSE_THRESHOLD = 0.02f;
+
+ private static final int COLLAPSE_DURATION_MS = 250;
+
+ private static final int MANAGE_BUTTON_ANIM_DURATION_MS = 78;
+
+ private static final int CONTENT_OPACITY_ANIM_DELAY_MS = 93;
+ private static final int CONTENT_OPACITY_ANIM_DURATION_MS = 78;
+
+ private static final int BACKGROUND_OPACITY_ANIM_DELAY_MS = 172;
+ private static final int BACKGROUND_OPACITY_ANIM_DURATION_MS = 78;
+
+ /** Animation fraction threshold for content alpha animation when stack collapse should begin */
+ private static final float STACK_COLLAPSE_THRESHOLD = 0.5f;
+
+ private static final FloatPropertyCompat<ExpandedViewAnimationControllerImpl>
+ COLLAPSE_HEIGHT_PROPERTY =
+ new FloatPropertyCompat<ExpandedViewAnimationControllerImpl>("CollapseSpring") {
+ @Override
+ public float getValue(ExpandedViewAnimationControllerImpl controller) {
+ return controller.getCollapsedAmount();
+ }
+
+ @Override
+ public void setValue(ExpandedViewAnimationControllerImpl controller,
+ float value) {
+ controller.setCollapsedAmount(value);
+ }
+ };
+
+ private final int mMinFlingVelocity;
+ private float mSwipeUpVelocity;
+ private float mSwipeDownVelocity;
+ private final BubblePositioner mPositioner;
+ private final FlingAnimationUtils mFlingAnimationUtils;
+ private int mDraggedAmount;
+ private float mCollapsedAmount;
+ @Nullable
+ private BubbleExpandedView mExpandedView;
+ @Nullable
+ private AnimatorSet mCollapseAnimation;
+ private boolean mNotifiedAboutThreshold;
+ private SpringAnimation mBackToExpandedAnimation;
+ @Nullable
+ private ObjectAnimator mBottomClipAnim;
+
+ public ExpandedViewAnimationControllerImpl(Context context, BubblePositioner positioner) {
+ mFlingAnimationUtils = new FlingAnimationUtils(context.getResources().getDisplayMetrics(),
+ COLLAPSE_DURATION_MS / 1000f);
+ mMinFlingVelocity = ViewConfiguration.get(context).getScaledMinimumFlingVelocity();
+ mPositioner = positioner;
+ }
+
+ private static void adjustAnimatorSetDuration(AnimatorSet animatorSet,
+ float durationAdjustment) {
+ for (Animator animator : animatorSet.getChildAnimations()) {
+ animator.setStartDelay((long) (animator.getStartDelay() * durationAdjustment));
+ animator.setDuration((long) (animator.getDuration() * durationAdjustment));
+ }
+ }
+
+ @Override
+ public void setExpandedView(BubbleExpandedView expandedView) {
+ if (mExpandedView != null) {
+ if (DEBUG_COLLAPSE_ANIMATOR) {
+ Log.d(TAG, "updating expandedView, resetting previous");
+ }
+ if (mCollapseAnimation != null) {
+ mCollapseAnimation.cancel();
+ }
+ if (mBackToExpandedAnimation != null) {
+ mBackToExpandedAnimation.cancel();
+ }
+ reset();
+ }
+ mExpandedView = expandedView;
+ }
+
+ @Override
+ public void updateDrag(float distance) {
+ if (mExpandedView != null) {
+ mDraggedAmount = OverScroll.dampedScroll(distance, mExpandedView.getContentHeight());
+
+ if (DEBUG_COLLAPSE_ANIMATOR && DEBUG_EXPANDED_VIEW_DRAGGING) {
+ Log.d(TAG, "updateDrag: distance=" + distance + " dragged=" + mDraggedAmount);
+ }
+
+ setCollapsedAmount(mDraggedAmount);
+
+ if (!mNotifiedAboutThreshold && isPastCollapseThreshold()) {
+ mNotifiedAboutThreshold = true;
+ if (DEBUG_COLLAPSE_ANIMATOR) {
+ Log.d(TAG, "notifying over collapse threshold");
+ }
+ vibrateIfEnabled();
+ }
+ }
+ }
+
+ @Override
+ public void setSwipeVelocity(float velocity) {
+ if (velocity < 0) {
+ mSwipeUpVelocity = Math.abs(velocity);
+ mSwipeDownVelocity = 0;
+ } else {
+ mSwipeUpVelocity = 0;
+ mSwipeDownVelocity = velocity;
+ }
+ }
+
+ @Override
+ public boolean shouldCollapse() {
+ if (mSwipeDownVelocity > mMinFlingVelocity) {
+ // Swipe velocity is positive and over fling velocity.
+ // This is a swipe down, always reset to expanded state, regardless of dragged amount.
+ if (DEBUG_COLLAPSE_ANIMATOR) {
+ Log.d(TAG,
+ "not collapsing expanded view, swipe down velocity: " + mSwipeDownVelocity
+ + " minV: " + mMinFlingVelocity);
+ }
+ return false;
+ }
+
+ if (mSwipeUpVelocity > mMinFlingVelocity) {
+ // Swiping up and over fling velocity, collapse the view.
+ if (DEBUG_COLLAPSE_ANIMATOR) {
+ Log.d(TAG,
+ "collapse expanded view, swipe up velocity: " + mSwipeUpVelocity + " minV: "
+ + mMinFlingVelocity);
+ }
+ return true;
+ }
+
+ if (isPastCollapseThreshold()) {
+ if (DEBUG_COLLAPSE_ANIMATOR) {
+ Log.d(TAG, "collapse expanded view, past threshold, dragged: " + mDraggedAmount);
+ }
+ return true;
+ }
+
+ if (DEBUG_COLLAPSE_ANIMATOR) {
+ Log.d(TAG, "not collapsing expanded view");
+ }
+
+ return false;
+ }
+
+ @Override
+ public void animateCollapse(Runnable startStackCollapse, Runnable after) {
+ if (DEBUG_COLLAPSE_ANIMATOR) {
+ Log.d(TAG,
+ "expandedView animate collapse swipeVel=" + mSwipeUpVelocity + " minFlingVel="
+ + mMinFlingVelocity);
+ }
+ if (mExpandedView != null) {
+ // Mark it as animating immediately to avoid updates to the view before animation starts
+ mExpandedView.setAnimating(true);
+
+ if (mCollapseAnimation != null) {
+ mCollapseAnimation.cancel();
+ }
+ mCollapseAnimation = createCollapseAnimation(mExpandedView, startStackCollapse, after);
+
+ if (mSwipeUpVelocity >= mMinFlingVelocity) {
+ int contentHeight = mExpandedView.getContentHeight();
+
+ // Use a temp animator to get adjusted duration value for swipe.
+ // This new value will be used to adjust animation times proportionally in the
+ // animator set. If we adjust animator set duration directly, all child animations
+ // will get the same animation time.
+ ValueAnimator tempAnimator = new ValueAnimator();
+ mFlingAnimationUtils.applyDismissing(tempAnimator, mCollapsedAmount, contentHeight,
+ mSwipeUpVelocity, (contentHeight - mCollapsedAmount));
+
+ float durationAdjustment =
+ (float) tempAnimator.getDuration() / COLLAPSE_DURATION_MS;
+
+ adjustAnimatorSetDuration(mCollapseAnimation, durationAdjustment);
+ mCollapseAnimation.setInterpolator(tempAnimator.getInterpolator());
+ }
+ mCollapseAnimation.start();
+ }
+ }
+
+ @Override
+ public void animateBackToExpanded() {
+ if (DEBUG_COLLAPSE_ANIMATOR) {
+ Log.d(TAG, "expandedView animate back to expanded");
+ }
+ BubbleExpandedView expandedView = mExpandedView;
+ if (expandedView == null) {
+ return;
+ }
+
+ expandedView.setAnimating(true);
+
+ mBackToExpandedAnimation = new SpringAnimation(this, COLLAPSE_HEIGHT_PROPERTY);
+ mBackToExpandedAnimation.setSpring(new SpringForce()
+ .setStiffness(SpringForce.STIFFNESS_LOW)
+ .setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY)
+ );
+ mBackToExpandedAnimation.addEndListener(new OneTimeEndListener() {
+ @Override
+ public void onAnimationEnd(DynamicAnimation animation, boolean canceled, float value,
+ float velocity) {
+ super.onAnimationEnd(animation, canceled, value, velocity);
+ mNotifiedAboutThreshold = false;
+ mBackToExpandedAnimation = null;
+ expandedView.setAnimating(false);
+ }
+ });
+ mBackToExpandedAnimation.setStartValue(mCollapsedAmount);
+ mBackToExpandedAnimation.animateToFinalPosition(0);
+ }
+
+ @Override
+ public void animateForImeVisibilityChange(boolean visible) {
+ if (mExpandedView != null) {
+ if (mBottomClipAnim != null) {
+ mBottomClipAnim.cancel();
+ }
+ int clip = 0;
+ if (visible) {
+ // Clip the expanded view at the top of the IME view
+ clip = mExpandedView.getContentBottomOnScreen() - mPositioner.getImeTop();
+ // Don't allow negative clip value
+ clip = Math.max(clip, 0);
+ }
+ mBottomClipAnim = ObjectAnimator.ofInt(mExpandedView, BOTTOM_CLIP_PROPERTY, clip);
+ mBottomClipAnim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mBottomClipAnim = null;
+ }
+ });
+ mBottomClipAnim.start();
+ }
+ }
+
+ @Override
+ public void reset() {
+ if (DEBUG_COLLAPSE_ANIMATOR) {
+ Log.d(TAG, "reset expandedView collapsed state");
+ }
+ if (mExpandedView == null) {
+ return;
+ }
+ mExpandedView.setAnimating(false);
+
+ if (mCollapseAnimation != null) {
+ mCollapseAnimation.cancel();
+ }
+ if (mBackToExpandedAnimation != null) {
+ mBackToExpandedAnimation.cancel();
+ }
+ mExpandedView.setContentAlpha(1);
+ mExpandedView.setAlpha(1);
+ mExpandedView.setManageButtonAlpha(1);
+ setCollapsedAmount(0);
+ mExpandedView.setBottomClip(0);
+ mExpandedView.movePointerBy(0, 0);
+ mCollapsedAmount = 0;
+ mDraggedAmount = 0;
+ mSwipeUpVelocity = 0;
+ mSwipeDownVelocity = 0;
+ mNotifiedAboutThreshold = false;
+ }
+
+ private float getCollapsedAmount() {
+ return mCollapsedAmount;
+ }
+
+ private void setCollapsedAmount(float collapsed) {
+ if (mCollapsedAmount != collapsed) {
+ float previous = mCollapsedAmount;
+ mCollapsedAmount = collapsed;
+
+ if (mExpandedView != null) {
+ if (previous == 0) {
+ // View was not collapsed before. Apply z order change
+ mExpandedView.setSurfaceZOrderedOnTop(true);
+ mExpandedView.setAnimating(true);
+ }
+
+ mExpandedView.setTopClip((int) mCollapsedAmount);
+ // Move up with translationY. Use negative collapsed value
+ mExpandedView.setContentTranslationY(-mCollapsedAmount);
+ mExpandedView.setManageButtonTranslationY(-mCollapsedAmount);
+
+ if (mCollapsedAmount == 0) {
+ // View is no longer collapsed. Revert z order change
+ mExpandedView.setSurfaceZOrderedOnTop(false);
+ mExpandedView.setAnimating(false);
+ }
+ }
+ }
+ }
+
+ private boolean isPastCollapseThreshold() {
+ if (mExpandedView != null) {
+ return mDraggedAmount > mExpandedView.getContentHeight() * COLLAPSE_THRESHOLD;
+ }
+ return false;
+ }
+
+ private AnimatorSet createCollapseAnimation(BubbleExpandedView expandedView,
+ Runnable startStackCollapse, Runnable after) {
+ List<Animator> animatorList = new ArrayList<>();
+ animatorList.add(createHeightAnimation(expandedView));
+ animatorList.add(createManageButtonAnimation());
+ ObjectAnimator contentAlphaAnimation = createContentAlphaAnimation();
+ final boolean[] notified = {false};
+ contentAlphaAnimation.addUpdateListener(animation -> {
+ if (!notified[0] && animation.getAnimatedFraction() > STACK_COLLAPSE_THRESHOLD) {
+ notified[0] = true;
+ // Notify bubbles that they can start moving back to the collapsed position
+ startStackCollapse.run();
+ }
+ });
+ animatorList.add(contentAlphaAnimation);
+ animatorList.add(createBackgroundAlphaAnimation());
+
+ AnimatorSet animatorSet = new AnimatorSet();
+ animatorSet.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ after.run();
+ }
+ });
+ animatorSet.playTogether(animatorList);
+ return animatorSet;
+ }
+
+ private ValueAnimator createHeightAnimation(BubbleExpandedView expandedView) {
+ ValueAnimator animator = ValueAnimator.ofInt((int) mCollapsedAmount,
+ expandedView.getContentHeight());
+ animator.setInterpolator(Interpolators.EMPHASIZED_ACCELERATE);
+ animator.setDuration(COLLAPSE_DURATION_MS);
+ animator.addUpdateListener(anim -> setCollapsedAmount((int) anim.getAnimatedValue()));
+ return animator;
+ }
+
+ private ObjectAnimator createManageButtonAnimation() {
+ ObjectAnimator animator = ObjectAnimator.ofFloat(mExpandedView, MANAGE_BUTTON_ALPHA, 0f);
+ animator.setDuration(MANAGE_BUTTON_ANIM_DURATION_MS);
+ animator.setInterpolator(Interpolators.LINEAR);
+ return animator;
+ }
+
+ private ObjectAnimator createContentAlphaAnimation() {
+ ObjectAnimator animator = ObjectAnimator.ofFloat(mExpandedView, CONTENT_ALPHA, 0f);
+ animator.setDuration(CONTENT_OPACITY_ANIM_DURATION_MS);
+ animator.setInterpolator(Interpolators.LINEAR);
+ animator.setStartDelay(CONTENT_OPACITY_ANIM_DELAY_MS);
+ return animator;
+ }
+
+ private ObjectAnimator createBackgroundAlphaAnimation() {
+ ObjectAnimator animator = ObjectAnimator.ofFloat(mExpandedView, ALPHA, 0f);
+ animator.setDuration(BACKGROUND_OPACITY_ANIM_DURATION_MS);
+ animator.setInterpolator(Interpolators.LINEAR);
+ animator.setStartDelay(BACKGROUND_OPACITY_ANIM_DELAY_MS);
+ return animator;
+ }
+
+ @SuppressLint("MissingPermission")
+ private void vibrateIfEnabled() {
+ if (mExpandedView != null) {
+ mExpandedView.performHapticFeedback(HapticFeedbackConstants.DRAG_CROSSING);
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedViewAnimationControllerStub.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedViewAnimationControllerStub.java
new file mode 100644
index 0000000..bb8a3aa
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedViewAnimationControllerStub.java
@@ -0,0 +1,57 @@
+/*
+ * 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.bubbles.animation;
+
+import com.android.wm.shell.bubbles.BubbleExpandedView;
+
+/**
+ * Stub implementation {@link ExpandedViewAnimationController} that does not animate the
+ * {@link BubbleExpandedView}
+ */
+public class ExpandedViewAnimationControllerStub implements ExpandedViewAnimationController {
+ @Override
+ public void setExpandedView(BubbleExpandedView expandedView) {
+ }
+
+ @Override
+ public void updateDrag(float distance) {
+ }
+
+ @Override
+ public void setSwipeVelocity(float velocity) {
+ }
+
+ @Override
+ public boolean shouldCollapse() {
+ return false;
+ }
+
+ @Override
+ public void animateCollapse(Runnable startStackCollapse, Runnable after) {
+ }
+
+ @Override
+ public void animateBackToExpanded() {
+ }
+
+ @Override
+ public void animateForImeVisibilityChange(boolean visible) {
+ }
+
+ @Override
+ public void reset() {
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/OverScroll.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/OverScroll.java
new file mode 100644
index 0000000..d4e76ed
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/OverScroll.java
@@ -0,0 +1,57 @@
+/*
+ * 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.bubbles.animation;
+
+/**
+ * Utility methods for overscroll damping and related effect.
+ *
+ * Copied from packages/apps/Launcher3/src/com/android/launcher3/touch/OverScroll.java
+ */
+public class OverScroll {
+
+ private static final float OVERSCROLL_DAMP_FACTOR = 0.07f;
+
+ /**
+ * This curve determines how the effect of scrolling over the limits of the page diminishes
+ * as the user pulls further and further from the bounds
+ *
+ * @param f The percentage of how much the user has overscrolled.
+ * @return A transformed percentage based on the influence curve.
+ */
+ private static float overScrollInfluenceCurve(float f) {
+ f -= 1.0f;
+ return f * f * f + 1.0f;
+ }
+
+ /**
+ * @param amount The original amount overscrolled.
+ * @param max The maximum amount that the View can overscroll.
+ * @return The dampened overscroll amount.
+ */
+ public static int dampedScroll(float amount, int max) {
+ if (Float.compare(amount, 0) == 0) return 0;
+
+ float f = amount / max;
+ f = f / (Math.abs(f)) * (overScrollInfluenceCurve(Math.abs(f)));
+
+ // Clamp this factor, f, to -1 < f < 1
+ if (Math.abs(f) >= 1) {
+ f /= Math.abs(f);
+ }
+
+ return Math.round(OVERSCROLL_DAMP_FACTOR * f * max);
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleVolatileRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleVolatileRepository.kt
index a5267d8..0d3ba9a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleVolatileRepository.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleVolatileRepository.kt
@@ -15,6 +15,7 @@
*/
package com.android.wm.shell.bubbles.storage
+import android.annotation.UserIdInt
import android.content.pm.LauncherApps
import android.os.UserHandle
import android.util.SparseArray
@@ -95,10 +96,63 @@
}
@Synchronized
- fun removeBubbles(userId: Int, bubbles: List<BubbleEntity>) =
+ fun removeBubbles(@UserIdInt userId: Int, bubbles: List<BubbleEntity>) =
uncache(bubbles.filter { b: BubbleEntity ->
getEntities(userId).removeIf { e: BubbleEntity -> b.key == e.key } })
+ /**
+ * Removes all the bubbles associated with the provided userId.
+ * @return whether bubbles were removed or not.
+ */
+ @Synchronized
+ fun removeBubblesForUser(@UserIdInt userId: Int, @UserIdInt parentUserId: Int): Boolean {
+ if (parentUserId != -1) {
+ return removeBubblesForUserWithParent(userId, parentUserId)
+ } else {
+ val entities = entitiesByUser.get(userId)
+ entitiesByUser.remove(userId)
+ return entities != null
+ }
+ }
+
+ /**
+ * Removes all the bubbles associated with the provided userId when that userId is part of
+ * a profile (e.g. managed account).
+ *
+ * @return whether bubbles were removed or not.
+ */
+ @Synchronized
+ private fun removeBubblesForUserWithParent(
+ @UserIdInt userId: Int,
+ @UserIdInt parentUserId: Int
+ ): Boolean {
+ return entitiesByUser.get(parentUserId).removeIf { b: BubbleEntity -> b.userId == userId }
+ }
+
+ /**
+ * Goes through all the persisted bubbles and removes them if the user is not in the active
+ * list of users.
+ *
+ * @return whether the list of bubbles changed or not (i.e. was a removal made).
+ */
+ @Synchronized
+ fun sanitizeBubbles(activeUsers: List<Int>): Boolean {
+ for (i in 0 until entitiesByUser.size()) {
+ // First check if the user is a parent / top-level user
+ val parentUserId = entitiesByUser.keyAt(i)
+ if (!activeUsers.contains(parentUserId)) {
+ return removeBubblesForUser(parentUserId, -1)
+ } else {
+ // Then check if each of the bubbles in the top-level user, still has a valid user
+ // as it could belong to a profile and have a different id from the parent.
+ return entitiesByUser.get(parentUserId).removeIf { b: BubbleEntity ->
+ !activeUsers.contains(b.userId)
+ }
+ }
+ }
+ return false
+ }
+
private fun cache(bubbles: List<BubbleEntity>) {
bubbles.groupBy { ShortcutKey(it.userId, it.packageName) }.forEach { (key, bubbles) ->
launcherApps.cacheShortcuts(key.pkg, bubbles.map { it.shortcutId },
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayChangeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayChangeController.java
index c32733d..28c7367 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayChangeController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayChangeController.java
@@ -16,11 +16,13 @@
package com.android.wm.shell.common;
+import android.annotation.Nullable;
import android.os.RemoteException;
import android.util.Slog;
-import android.view.IDisplayWindowRotationCallback;
-import android.view.IDisplayWindowRotationController;
+import android.view.IDisplayChangeWindowCallback;
+import android.view.IDisplayChangeWindowController;
import android.view.IWindowManager;
+import android.window.DisplayAreaInfo;
import android.window.WindowContainerTransaction;
import androidx.annotation.BinderThread;
@@ -40,17 +42,17 @@
private final ShellExecutor mMainExecutor;
private final IWindowManager mWmService;
- private final IDisplayWindowRotationController mControllerImpl;
+ private final IDisplayChangeWindowController mControllerImpl;
- private final CopyOnWriteArrayList<OnDisplayChangingListener> mRotationListener =
+ private final CopyOnWriteArrayList<OnDisplayChangingListener> mDisplayChangeListener =
new CopyOnWriteArrayList<>();
public DisplayChangeController(IWindowManager wmService, ShellExecutor mainExecutor) {
mMainExecutor = mainExecutor;
mWmService = wmService;
- mControllerImpl = new DisplayWindowRotationControllerImpl();
+ mControllerImpl = new DisplayChangeWindowControllerImpl();
try {
- mWmService.setDisplayWindowRotationController(mControllerImpl);
+ mWmService.setDisplayChangeWindowController(mControllerImpl);
} catch (RemoteException e) {
throw new RuntimeException("Unable to register rotation controller");
}
@@ -59,63 +61,64 @@
/**
* Adds a display rotation controller.
*/
- public void addRotationListener(OnDisplayChangingListener listener) {
- mRotationListener.add(listener);
+ public void addDisplayChangeListener(OnDisplayChangingListener listener) {
+ mDisplayChangeListener.add(listener);
}
/**
* Removes a display rotation controller.
*/
- public void removeRotationListener(OnDisplayChangingListener listener) {
- mRotationListener.remove(listener);
+ public void removeDisplayChangeListener(OnDisplayChangingListener listener) {
+ mDisplayChangeListener.remove(listener);
}
- /** Query all listeners for changes that should happen on rotation. */
- public void dispatchOnRotateDisplay(WindowContainerTransaction outWct, int displayId,
- final int fromRotation, final int toRotation) {
- for (OnDisplayChangingListener c : mRotationListener) {
- c.onRotateDisplay(displayId, fromRotation, toRotation, outWct);
+ /** Query all listeners for changes that should happen on display change. */
+ public void dispatchOnDisplayChange(WindowContainerTransaction outWct, int displayId,
+ int fromRotation, int toRotation, DisplayAreaInfo newDisplayAreaInfo) {
+ for (OnDisplayChangingListener c : mDisplayChangeListener) {
+ c.onDisplayChange(displayId, fromRotation, toRotation, newDisplayAreaInfo, outWct);
}
}
- private void onRotateDisplay(int displayId, final int fromRotation, final int toRotation,
- IDisplayWindowRotationCallback callback) {
+ private void onDisplayChange(int displayId, int fromRotation, int toRotation,
+ DisplayAreaInfo newDisplayAreaInfo, IDisplayChangeWindowCallback callback) {
WindowContainerTransaction t = new WindowContainerTransaction();
- dispatchOnRotateDisplay(t, displayId, fromRotation, toRotation);
+ dispatchOnDisplayChange(t, displayId, fromRotation, toRotation, newDisplayAreaInfo);
try {
- callback.continueRotateDisplay(toRotation, t);
+ callback.continueDisplayChange(t);
} catch (RemoteException e) {
- Slog.e(TAG, "Failed to continue rotation", e);
+ Slog.e(TAG, "Failed to continue handling display change", e);
}
}
@BinderThread
- private class DisplayWindowRotationControllerImpl
- extends IDisplayWindowRotationController.Stub {
+ private class DisplayChangeWindowControllerImpl
+ extends IDisplayChangeWindowController.Stub {
@Override
- public void onRotateDisplay(int displayId, final int fromRotation,
- final int toRotation, IDisplayWindowRotationCallback callback) {
- mMainExecutor.execute(() -> {
- DisplayChangeController.this.onRotateDisplay(displayId, fromRotation, toRotation,
- callback);
- });
+ public void onDisplayChange(int displayId, int fromRotation, int toRotation,
+ DisplayAreaInfo newDisplayAreaInfo, IDisplayChangeWindowCallback callback) {
+ mMainExecutor.execute(() -> DisplayChangeController.this
+ .onDisplayChange(displayId, fromRotation, toRotation,
+ newDisplayAreaInfo, callback));
}
}
/**
* Give a listener a chance to queue up configuration changes to execute as part of a
- * display rotation. The contents of {@link #onRotateDisplay} must run synchronously.
+ * display rotation. The contents of {@link #onDisplayChange} must run synchronously.
*/
@ShellMainThread
public interface OnDisplayChangingListener {
/**
- * Called before the display is rotated. Contents of this method must run synchronously.
- * @param displayId Id of display that is rotating.
- * @param fromRotation starting rotation of the display.
- * @param toRotation target rotation of the display (after rotating).
+ * Called before the display size has changed.
+ * Contents of this method must run synchronously.
+ * @param displayId display id of the display that is under the change
+ * @param fromRotation rotation before the change
+ * @param toRotation rotation after the change
+ * @param newDisplayAreaInfo display area info after applying the update
* @param t A task transaction to populate.
*/
- void onRotateDisplay(int displayId, int fromRotation, int toRotation,
- WindowContainerTransaction t);
+ void onDisplayChange(int displayId, int fromRotation, int toRotation,
+ @Nullable DisplayAreaInfo newDisplayAreaInfo, WindowContainerTransaction t);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java
index 4ba32e9..764936c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java
@@ -156,14 +156,14 @@
* Adds a display rotation controller.
*/
public void addDisplayChangingController(OnDisplayChangingListener controller) {
- mChangeController.addRotationListener(controller);
+ mChangeController.addDisplayChangeListener(controller);
}
/**
* Removes a display rotation controller.
*/
public void removeDisplayChangingController(OnDisplayChangingListener controller) {
- mChangeController.removeRotationListener(controller);
+ mChangeController.removeDisplayChangeListener(controller);
}
private void onDisplayAdded(int displayId) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
index 3b83f15..6a2acf4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
@@ -498,6 +498,11 @@
dispatchVisibilityChanged(mDisplayId, isShowing);
}
}
+
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ public InsetsSourceControl getImeSourceControl() {
+ return mImeSourceControl;
+ }
}
void removeImeSurface() {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerCallback.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerCallback.java
index 59374a6..b9ddd36 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerCallback.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerCallback.java
@@ -38,7 +38,7 @@
default void onTaskStackChanged() { }
- default void onTaskProfileLocked(int taskId, int userId) { }
+ default void onTaskProfileLocked(RunningTaskInfo taskInfo) { }
default void onTaskDisplayChanged(int taskId, int newDisplayId) { }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerImpl.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerImpl.java
index 3b67005..85e2654 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerImpl.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerImpl.java
@@ -150,8 +150,8 @@
}
@Override
- public void onTaskProfileLocked(int taskId, int userId) {
- mMainHandler.obtainMessage(ON_TASK_PROFILE_LOCKED, taskId, userId).sendToTarget();
+ public void onTaskProfileLocked(ActivityManager.RunningTaskInfo taskInfo) {
+ mMainHandler.obtainMessage(ON_TASK_PROFILE_LOCKED, taskInfo).sendToTarget();
}
@Override
@@ -341,8 +341,10 @@
break;
}
case ON_TASK_PROFILE_LOCKED: {
+ final ActivityManager.RunningTaskInfo
+ info = (ActivityManager.RunningTaskInfo) msg.obj;
for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
- mTaskStackListeners.get(i).onTaskProfileLocked(msg.arg1, msg.arg2);
+ mTaskStackListeners.get(i).onTaskProfileLocked(info);
}
break;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvPipModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvPipModule.java
index dfd4362..1ea5e21 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvPipModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvPipModule.java
@@ -18,6 +18,7 @@
import android.content.Context;
import android.os.Handler;
+import android.os.SystemClock;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.WindowManagerShellWrapper;
@@ -39,6 +40,7 @@
import com.android.wm.shell.pip.PipTransitionState;
import com.android.wm.shell.pip.PipUiEventLogger;
import com.android.wm.shell.pip.tv.TvPipBoundsAlgorithm;
+import com.android.wm.shell.pip.tv.TvPipBoundsController;
import com.android.wm.shell.pip.tv.TvPipBoundsState;
import com.android.wm.shell.pip.tv.TvPipController;
import com.android.wm.shell.pip.tv.TvPipMenuController;
@@ -64,6 +66,7 @@
Context context,
TvPipBoundsState tvPipBoundsState,
TvPipBoundsAlgorithm tvPipBoundsAlgorithm,
+ TvPipBoundsController tvPipBoundsController,
PipAppOpsListener pipAppOpsListener,
PipTaskOrganizer pipTaskOrganizer,
TvPipMenuController tvPipMenuController,
@@ -74,13 +77,13 @@
PipParamsChangedForwarder pipParamsChangedForwarder,
DisplayController displayController,
WindowManagerShellWrapper windowManagerShellWrapper,
- @ShellMainThread ShellExecutor mainExecutor,
- @ShellMainThread Handler mainHandler) {
+ @ShellMainThread ShellExecutor mainExecutor) {
return Optional.of(
TvPipController.create(
context,
tvPipBoundsState,
tvPipBoundsAlgorithm,
+ tvPipBoundsController,
pipAppOpsListener,
pipTaskOrganizer,
pipTransitionController,
@@ -91,8 +94,22 @@
pipParamsChangedForwarder,
displayController,
windowManagerShellWrapper,
- mainExecutor,
- mainHandler));
+ mainExecutor));
+ }
+
+ @WMSingleton
+ @Provides
+ static TvPipBoundsController provideTvPipBoundsController(
+ Context context,
+ @ShellMainThread Handler mainHandler,
+ TvPipBoundsState tvPipBoundsState,
+ TvPipBoundsAlgorithm tvPipBoundsAlgorithm) {
+ return new TvPipBoundsController(
+ context,
+ SystemClock::uptimeMillis,
+ mainHandler,
+ tvPipBoundsState,
+ tvPipBoundsAlgorithm);
}
@WMSingleton
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 409e747..88977aff 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
@@ -38,8 +38,6 @@
import com.android.wm.shell.TaskViewFactoryController;
import com.android.wm.shell.TaskViewTransitions;
import com.android.wm.shell.WindowManagerShellWrapper;
-import com.android.wm.shell.apppairs.AppPairs;
-import com.android.wm.shell.apppairs.AppPairsController;
import com.android.wm.shell.back.BackAnimation;
import com.android.wm.shell.back.BackAnimationController;
import com.android.wm.shell.bubbles.BubbleController;
@@ -69,8 +67,6 @@
import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout;
import com.android.wm.shell.hidedisplaycutout.HideDisplayCutoutController;
import com.android.wm.shell.kidsmode.KidsModeTaskOrganizer;
-import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
-import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController;
import com.android.wm.shell.onehanded.OneHanded;
import com.android.wm.shell.onehanded.OneHandedController;
import com.android.wm.shell.pip.Pip;
@@ -561,29 +557,6 @@
return Optional.empty();
}
- // Legacy split (optional feature)
-
- @WMSingleton
- @Provides
- static Optional<LegacySplitScreen> provideLegacySplitScreen(
- Optional<LegacySplitScreenController> splitScreenController) {
- return splitScreenController.map((controller) -> controller.asLegacySplitScreen());
- }
-
- @BindsOptionalOf
- abstract LegacySplitScreenController optionalLegacySplitScreenController();
-
- // App Pairs (optional feature)
-
- @WMSingleton
- @Provides
- static Optional<AppPairs> provideAppPairs(Optional<AppPairsController> appPairsController) {
- return appPairsController.map((controller) -> controller.asAppPairs());
- }
-
- @BindsOptionalOf
- abstract AppPairsController optionalAppPairs();
-
//
// Starting window
//
@@ -664,7 +637,6 @@
KidsModeTaskOrganizer kidsModeTaskOrganizer,
Optional<BubbleController> bubblesOptional,
Optional<SplitScreenController> splitScreenOptional,
- Optional<AppPairsController> appPairsOptional,
Optional<PipTouchHandler> pipTouchHandlerOptional,
FullscreenTaskListener fullscreenTaskListener,
Optional<FullscreenUnfoldController> appUnfoldTransitionController,
@@ -682,7 +654,6 @@
kidsModeTaskOrganizer,
bubblesOptional,
splitScreenOptional,
- appPairsOptional,
pipTouchHandlerOptional,
fullscreenTaskListener,
appUnfoldTransitionController,
@@ -709,17 +680,15 @@
static ShellCommandHandlerImpl provideShellCommandHandlerImpl(
ShellTaskOrganizer shellTaskOrganizer,
KidsModeTaskOrganizer kidsModeTaskOrganizer,
- Optional<LegacySplitScreenController> legacySplitScreenOptional,
Optional<SplitScreenController> splitScreenOptional,
Optional<Pip> pipOptional,
Optional<OneHandedController> oneHandedOptional,
Optional<HideDisplayCutoutController> hideDisplayCutout,
- Optional<AppPairsController> appPairsOptional,
Optional<RecentTasksController> recentTasksOptional,
@ShellMainThread ShellExecutor mainExecutor) {
return new ShellCommandHandlerImpl(shellTaskOrganizer, kidsModeTaskOrganizer,
- legacySplitScreenOptional, splitScreenOptional, pipOptional, oneHandedOptional,
- hideDisplayCutout, appPairsOptional, recentTasksOptional, mainExecutor);
+ splitScreenOptional, pipOptional, oneHandedOptional, hideDisplayCutout,
+ recentTasksOptional, mainExecutor);
}
@WMSingleton
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 d198d05..c5453d4 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
@@ -16,10 +16,10 @@
package com.android.wm.shell.dagger;
-import android.animation.AnimationHandler;
import android.content.Context;
import android.content.pm.LauncherApps;
import android.os.Handler;
+import android.os.UserManager;
import android.view.WindowManager;
import com.android.internal.jank.InteractionJankMonitor;
@@ -30,7 +30,6 @@
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.TaskViewTransitions;
import com.android.wm.shell.WindowManagerShellWrapper;
-import com.android.wm.shell.apppairs.AppPairsController;
import com.android.wm.shell.bubbles.BubbleController;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayImeController;
@@ -42,12 +41,11 @@
import com.android.wm.shell.common.SystemWindows;
import com.android.wm.shell.common.TaskStackListenerImpl;
import com.android.wm.shell.common.TransactionPool;
-import com.android.wm.shell.common.annotations.ChoreographerSfVsync;
+import com.android.wm.shell.common.annotations.ShellBackgroundThread;
import com.android.wm.shell.common.annotations.ShellMainThread;
import com.android.wm.shell.draganddrop.DragAndDropController;
import com.android.wm.shell.freeform.FreeformTaskListener;
import com.android.wm.shell.fullscreen.FullscreenUnfoldController;
-import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController;
import com.android.wm.shell.onehanded.OneHandedController;
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.pip.PipAnimationController;
@@ -107,6 +105,7 @@
IStatusBarService statusBarService,
WindowManager windowManager,
WindowManagerShellWrapper windowManagerShellWrapper,
+ UserManager userManager,
LauncherApps launcherApps,
TaskStackListenerImpl taskStackListener,
UiEventLogger uiEventLogger,
@@ -116,13 +115,15 @@
DragAndDropController dragAndDropController,
@ShellMainThread ShellExecutor mainExecutor,
@ShellMainThread Handler mainHandler,
+ @ShellBackgroundThread ShellExecutor bgExecutor,
TaskViewTransitions taskViewTransitions,
SyncTransactionQueue syncQueue) {
return BubbleController.create(context, null /* synchronizer */,
floatingContentCoordinator, statusBarService, windowManager,
- windowManagerShellWrapper, launcherApps, taskStackListener,
+ windowManagerShellWrapper, userManager, launcherApps, taskStackListener,
uiEventLogger, organizer, displayController, oneHandedOptional,
- dragAndDropController, mainExecutor, mainHandler, taskViewTransitions, syncQueue);
+ dragAndDropController, mainExecutor, mainHandler, bgExecutor,
+ taskViewTransitions, syncQueue);
}
//
@@ -179,31 +180,6 @@
recentTasks, stageTaskUnfoldControllerProvider);
}
- @WMSingleton
- @Provides
- static LegacySplitScreenController provideLegacySplitScreen(Context context,
- DisplayController displayController, SystemWindows systemWindows,
- DisplayImeController displayImeController, TransactionPool transactionPool,
- ShellTaskOrganizer shellTaskOrganizer, SyncTransactionQueue syncQueue,
- TaskStackListenerImpl taskStackListener, Transitions transitions,
- @ShellMainThread ShellExecutor mainExecutor,
- @ChoreographerSfVsync AnimationHandler sfVsyncAnimationHandler) {
- return new LegacySplitScreenController(context, displayController, systemWindows,
- displayImeController, transactionPool, shellTaskOrganizer, syncQueue,
- taskStackListener, transitions, mainExecutor, sfVsyncAnimationHandler);
- }
-
- @WMSingleton
- @Provides
- static AppPairsController provideAppPairs(ShellTaskOrganizer shellTaskOrganizer,
- SyncTransactionQueue syncQueue, DisplayController displayController,
- @ShellMainThread ShellExecutor mainExecutor,
- DisplayImeController displayImeController,
- DisplayInsetsController displayInsetsController) {
- return new AppPairsController(shellTaskOrganizer, syncQueue, displayController,
- mainExecutor, displayImeController, displayInsetsController);
- }
-
//
// Pip
//
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/kidsmode/KidsModeSettingsObserver.java b/libs/WindowManager/Shell/src/com/android/wm/shell/kidsmode/KidsModeSettingsObserver.java
index f8f9d6b..65cb7ac 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/kidsmode/KidsModeSettingsObserver.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/kidsmode/KidsModeSettingsObserver.java
@@ -16,13 +16,18 @@
package com.android.wm.shell.kidsmode;
+import android.annotation.NonNull;
+import android.app.ActivityManager;
import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
+import android.net.Uri;
import android.os.Handler;
import android.os.UserHandle;
import android.provider.Settings;
+import java.util.Collection;
+
/**
* A ContentObserver for listening kids mode relative setting keys:
* - {@link Settings.Secure#NAVIGATION_MODE}
@@ -64,7 +69,11 @@
}
@Override
- public void onChange(boolean selfChange) {
+ public void onChange(boolean selfChange, @NonNull Collection<Uri> uris, int flags, int userId) {
+ if (userId != ActivityManager.getCurrentUser()) {
+ return;
+ }
+
if (mOnChangeRunnable != null) {
mOnChangeRunnable.run();
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizer.java
index dc70358..b4c87b6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizer.java
@@ -23,7 +23,10 @@
import static android.view.Display.DEFAULT_DISPLAY;
import android.app.ActivityManager;
+import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Binder;
@@ -87,6 +90,13 @@
private KidsModeSettingsObserver mKidsModeSettingsObserver;
private boolean mEnabled;
+ private final BroadcastReceiver mUserSwitchIntentReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ updateKidsModeState();
+ }
+ };
+
DisplayController.OnDisplaysChangedListener mOnDisplaysChangedListener =
new DisplayController.OnDisplaysChangedListener() {
@Override
@@ -169,12 +179,15 @@
public void initialize(StartingWindowController startingWindowController) {
initStartingWindow(startingWindowController);
if (mKidsModeSettingsObserver == null) {
- mKidsModeSettingsObserver = new KidsModeSettingsObserver(
- mMainHandler, mContext);
+ mKidsModeSettingsObserver = new KidsModeSettingsObserver(mMainHandler, mContext);
}
mKidsModeSettingsObserver.setOnChangeRunnable(() -> updateKidsModeState());
updateKidsModeState();
mKidsModeSettingsObserver.register();
+
+ final IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_USER_SWITCHED);
+ mContext.registerReceiverForAllUsers(mUserSwitchIntentReceiver, filter, null, mMainHandler);
}
@Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerImeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerImeController.java
deleted file mode 100644
index aced072..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerImeController.java
+++ /dev/null
@@ -1,418 +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.wm.shell.legacysplitscreen;
-
-import static android.content.res.Configuration.SCREEN_HEIGHT_DP_UNDEFINED;
-import static android.content.res.Configuration.SCREEN_WIDTH_DP_UNDEFINED;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ValueAnimator;
-import android.annotation.Nullable;
-import android.graphics.Rect;
-import android.util.Slog;
-import android.view.Choreographer;
-import android.view.SurfaceControl;
-import android.window.TaskOrganizer;
-import android.window.WindowContainerToken;
-import android.window.WindowContainerTransaction;
-
-import com.android.wm.shell.common.DisplayImeController;
-import com.android.wm.shell.common.ShellExecutor;
-import com.android.wm.shell.common.TransactionPool;
-
-class DividerImeController implements DisplayImeController.ImePositionProcessor {
- private static final String TAG = "DividerImeController";
- private static final boolean DEBUG = LegacySplitScreenController.DEBUG;
-
- private static final float ADJUSTED_NONFOCUS_DIM = 0.3f;
-
- private final LegacySplitScreenTaskListener mSplits;
- private final TransactionPool mTransactionPool;
- private final ShellExecutor mMainExecutor;
- private final TaskOrganizer mTaskOrganizer;
-
- /**
- * These are the y positions of the top of the IME surface when it is hidden and when it is
- * shown respectively. These are NOT necessarily the top of the visible IME itself.
- */
- private int mHiddenTop = 0;
- private int mShownTop = 0;
-
- // The following are target states (what we are curretly animating towards).
- /**
- * {@code true} if, at the end of the animation, the split task positions should be
- * adjusted by height of the IME. This happens when the secondary split is the IME target.
- */
- private boolean mTargetAdjusted = false;
- /**
- * {@code true} if, at the end of the animation, the IME should be shown/visible
- * regardless of what has focus.
- */
- private boolean mTargetShown = false;
- private float mTargetPrimaryDim = 0.f;
- private float mTargetSecondaryDim = 0.f;
-
- // The following are the current (most recent) states set during animation
- /** {@code true} if the secondary split has IME focus. */
- private boolean mSecondaryHasFocus = false;
- /** The dimming currently applied to the primary/secondary splits. */
- private float mLastPrimaryDim = 0.f;
- private float mLastSecondaryDim = 0.f;
- /** The most recent y position of the top of the IME surface */
- private int mLastAdjustTop = -1;
-
- // The following are states reached last time an animation fully completed.
- /** {@code true} if the IME was shown/visible by the last-completed animation. */
- private boolean mImeWasShown = false;
- /** {@code true} if the split positions were adjusted by the last-completed animation. */
- private boolean mAdjusted = false;
-
- /**
- * When some aspect of split-screen needs to animate independent from the IME,
- * this will be non-null and control split animation.
- */
- @Nullable
- private ValueAnimator mAnimation = null;
-
- private boolean mPaused = true;
- private boolean mPausedTargetAdjusted = false;
-
- DividerImeController(LegacySplitScreenTaskListener splits, TransactionPool pool,
- ShellExecutor mainExecutor, TaskOrganizer taskOrganizer) {
- mSplits = splits;
- mTransactionPool = pool;
- mMainExecutor = mainExecutor;
- mTaskOrganizer = taskOrganizer;
- }
-
- private DividerView getView() {
- return mSplits.mSplitScreenController.getDividerView();
- }
-
- private LegacySplitDisplayLayout getLayout() {
- return mSplits.mSplitScreenController.getSplitLayout();
- }
-
- private boolean isDividerHidden() {
- final DividerView view = mSplits.mSplitScreenController.getDividerView();
- return view == null || view.isHidden();
- }
-
- private boolean getSecondaryHasFocus(int displayId) {
- WindowContainerToken imeSplit = mTaskOrganizer.getImeTarget(displayId);
- return imeSplit != null
- && (imeSplit.asBinder() == mSplits.mSecondary.token.asBinder());
- }
-
- void reset() {
- mPaused = true;
- mPausedTargetAdjusted = false;
- mAnimation = null;
- mAdjusted = mTargetAdjusted = false;
- mImeWasShown = mTargetShown = false;
- mTargetPrimaryDim = mTargetSecondaryDim = mLastPrimaryDim = mLastSecondaryDim = 0.f;
- mSecondaryHasFocus = false;
- mLastAdjustTop = -1;
- }
-
- private void updateDimTargets() {
- final boolean splitIsVisible = !getView().isHidden();
- mTargetPrimaryDim = (mSecondaryHasFocus && mTargetShown && splitIsVisible)
- ? ADJUSTED_NONFOCUS_DIM : 0.f;
- mTargetSecondaryDim = (!mSecondaryHasFocus && mTargetShown && splitIsVisible)
- ? ADJUSTED_NONFOCUS_DIM : 0.f;
- }
-
-
- @Override
- public void onImeControlTargetChanged(int displayId, boolean controlling) {
- // Restore the split layout when wm-shell is not controlling IME insets anymore.
- if (!controlling && mTargetShown) {
- mPaused = false;
- mTargetAdjusted = mTargetShown = false;
- mTargetPrimaryDim = mTargetSecondaryDim = 0.f;
- updateImeAdjustState(true /* force */);
- startAsyncAnimation();
- }
- }
-
- @Override
- @ImeAnimationFlags
- public int onImeStartPositioning(int displayId, int hiddenTop, int shownTop,
- boolean imeShouldShow, boolean imeIsFloating, SurfaceControl.Transaction t) {
- if (isDividerHidden()) {
- return 0;
- }
- mHiddenTop = hiddenTop;
- mShownTop = shownTop;
- mTargetShown = imeShouldShow;
- mSecondaryHasFocus = getSecondaryHasFocus(displayId);
- final boolean targetAdjusted = imeShouldShow && mSecondaryHasFocus
- && !imeIsFloating && !getLayout().mDisplayLayout.isLandscape()
- && !mSplits.mSplitScreenController.isMinimized();
- if (mLastAdjustTop < 0) {
- mLastAdjustTop = imeShouldShow ? hiddenTop : shownTop;
- } else if (mLastAdjustTop != (imeShouldShow ? mShownTop : mHiddenTop)) {
- if (mTargetAdjusted != targetAdjusted && targetAdjusted == mAdjusted) {
- // Check for an "interruption" of an existing animation. In this case, we
- // need to fake-flip the last-known state direction so that the animation
- // completes in the other direction.
- mAdjusted = mTargetAdjusted;
- } else if (targetAdjusted && mTargetAdjusted && mAdjusted) {
- // Already fully adjusted for IME, but IME height has changed; so, force-start
- // an async animation to the new IME height.
- mAdjusted = false;
- }
- }
- if (mPaused) {
- mPausedTargetAdjusted = targetAdjusted;
- if (DEBUG) Slog.d(TAG, " ime starting but paused " + dumpState());
- return (targetAdjusted || mAdjusted) ? IME_ANIMATION_NO_ALPHA : 0;
- }
- mTargetAdjusted = targetAdjusted;
- updateDimTargets();
- if (DEBUG) Slog.d(TAG, " ime starting. " + dumpState());
- if (mAnimation != null || (mImeWasShown && imeShouldShow
- && mTargetAdjusted != mAdjusted)) {
- // We need to animate adjustment independently of the IME position, so
- // start our own animation to drive adjustment. This happens when a
- // different split's editor has gained focus while the IME is still visible.
- startAsyncAnimation();
- }
- updateImeAdjustState();
-
- return (mTargetAdjusted || mAdjusted) ? IME_ANIMATION_NO_ALPHA : 0;
- }
-
- private void updateImeAdjustState() {
- updateImeAdjustState(false /* force */);
- }
-
- private void updateImeAdjustState(boolean force) {
- if (mAdjusted != mTargetAdjusted || force) {
- // Reposition the server's secondary split position so that it evaluates
- // insets properly.
- WindowContainerTransaction wct = new WindowContainerTransaction();
- final LegacySplitDisplayLayout splitLayout = getLayout();
- if (mTargetAdjusted) {
- splitLayout.updateAdjustedBounds(mShownTop, mHiddenTop, mShownTop);
- wct.setBounds(mSplits.mSecondary.token, splitLayout.mAdjustedSecondary);
- // "Freeze" the configuration size so that the app doesn't get a config
- // or relaunch. This is required because normally nav-bar contributes
- // to configuration bounds (via nondecorframe).
- Rect adjustAppBounds = new Rect(mSplits.mSecondary.configuration
- .windowConfiguration.getAppBounds());
- adjustAppBounds.offset(0, splitLayout.mAdjustedSecondary.top
- - splitLayout.mSecondary.top);
- wct.setAppBounds(mSplits.mSecondary.token, adjustAppBounds);
- wct.setScreenSizeDp(mSplits.mSecondary.token,
- mSplits.mSecondary.configuration.screenWidthDp,
- mSplits.mSecondary.configuration.screenHeightDp);
-
- wct.setBounds(mSplits.mPrimary.token, splitLayout.mAdjustedPrimary);
- adjustAppBounds = new Rect(mSplits.mPrimary.configuration
- .windowConfiguration.getAppBounds());
- adjustAppBounds.offset(0, splitLayout.mAdjustedPrimary.top
- - splitLayout.mPrimary.top);
- wct.setAppBounds(mSplits.mPrimary.token, adjustAppBounds);
- wct.setScreenSizeDp(mSplits.mPrimary.token,
- mSplits.mPrimary.configuration.screenWidthDp,
- mSplits.mPrimary.configuration.screenHeightDp);
- } else {
- wct.setBounds(mSplits.mSecondary.token, splitLayout.mSecondary);
- wct.setAppBounds(mSplits.mSecondary.token, null);
- wct.setScreenSizeDp(mSplits.mSecondary.token,
- SCREEN_WIDTH_DP_UNDEFINED, SCREEN_HEIGHT_DP_UNDEFINED);
- wct.setBounds(mSplits.mPrimary.token, splitLayout.mPrimary);
- wct.setAppBounds(mSplits.mPrimary.token, null);
- wct.setScreenSizeDp(mSplits.mPrimary.token,
- SCREEN_WIDTH_DP_UNDEFINED, SCREEN_HEIGHT_DP_UNDEFINED);
- }
-
- if (!mSplits.mSplitScreenController.getWmProxy().queueSyncTransactionIfWaiting(wct)) {
- mTaskOrganizer.applyTransaction(wct);
- }
- }
-
- // Update all the adjusted-for-ime states
- if (!mPaused) {
- final DividerView view = getView();
- if (view != null) {
- view.setAdjustedForIme(mTargetShown, mTargetShown
- ? DisplayImeController.ANIMATION_DURATION_SHOW_MS
- : DisplayImeController.ANIMATION_DURATION_HIDE_MS);
- }
- }
- mSplits.mSplitScreenController.setAdjustedForIme(mTargetShown && !mPaused);
- }
-
- @Override
- public void onImePositionChanged(int displayId, int imeTop,
- SurfaceControl.Transaction t) {
- if (mAnimation != null || isDividerHidden() || mPaused) {
- // Not synchronized with IME anymore, so return.
- return;
- }
- final float fraction = ((float) imeTop - mHiddenTop) / (mShownTop - mHiddenTop);
- final float progress = mTargetShown ? fraction : 1.f - fraction;
- onProgress(progress, t);
- }
-
- @Override
- public void onImeEndPositioning(int displayId, boolean cancelled,
- SurfaceControl.Transaction t) {
- if (mAnimation != null || isDividerHidden() || mPaused) {
- // Not synchronized with IME anymore, so return.
- return;
- }
- onEnd(cancelled, t);
- }
-
- private void onProgress(float progress, SurfaceControl.Transaction t) {
- final DividerView view = getView();
- if (mTargetAdjusted != mAdjusted && !mPaused) {
- final LegacySplitDisplayLayout splitLayout = getLayout();
- final float fraction = mTargetAdjusted ? progress : 1.f - progress;
- mLastAdjustTop = (int) (fraction * mShownTop + (1.f - fraction) * mHiddenTop);
- splitLayout.updateAdjustedBounds(mLastAdjustTop, mHiddenTop, mShownTop);
- view.resizeSplitSurfaces(t, splitLayout.mAdjustedPrimary,
- splitLayout.mAdjustedSecondary);
- }
- final float invProg = 1.f - progress;
- view.setResizeDimLayer(t, true /* primary */,
- mLastPrimaryDim * invProg + progress * mTargetPrimaryDim);
- view.setResizeDimLayer(t, false /* primary */,
- mLastSecondaryDim * invProg + progress * mTargetSecondaryDim);
- }
-
- void setDimsHidden(SurfaceControl.Transaction t, boolean hidden) {
- final DividerView view = getView();
- if (hidden) {
- view.setResizeDimLayer(t, true /* primary */, 0.f /* alpha */);
- view.setResizeDimLayer(t, false /* primary */, 0.f /* alpha */);
- } else {
- updateDimTargets();
- view.setResizeDimLayer(t, true /* primary */, mTargetPrimaryDim);
- view.setResizeDimLayer(t, false /* primary */, mTargetSecondaryDim);
- }
- }
-
- private void onEnd(boolean cancelled, SurfaceControl.Transaction t) {
- if (!cancelled) {
- onProgress(1.f, t);
- mAdjusted = mTargetAdjusted;
- mImeWasShown = mTargetShown;
- mLastAdjustTop = mAdjusted ? mShownTop : mHiddenTop;
- mLastPrimaryDim = mTargetPrimaryDim;
- mLastSecondaryDim = mTargetSecondaryDim;
- }
- }
-
- private void startAsyncAnimation() {
- if (mAnimation != null) {
- mAnimation.cancel();
- }
- mAnimation = ValueAnimator.ofFloat(0.f, 1.f);
- mAnimation.setDuration(DisplayImeController.ANIMATION_DURATION_SHOW_MS);
- if (mTargetAdjusted != mAdjusted) {
- final float fraction =
- ((float) mLastAdjustTop - mHiddenTop) / (mShownTop - mHiddenTop);
- final float progress = mTargetAdjusted ? fraction : 1.f - fraction;
- mAnimation.setCurrentFraction(progress);
- }
-
- mAnimation.addUpdateListener(animation -> {
- SurfaceControl.Transaction t = mTransactionPool.acquire();
- float value = (float) animation.getAnimatedValue();
- onProgress(value, t);
- t.setFrameTimelineVsync(Choreographer.getSfInstance().getVsyncId());
- t.apply();
- mTransactionPool.release(t);
- });
- mAnimation.setInterpolator(DisplayImeController.INTERPOLATOR);
- mAnimation.addListener(new AnimatorListenerAdapter() {
- private boolean mCancel = false;
-
- @Override
- public void onAnimationCancel(Animator animation) {
- mCancel = true;
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- SurfaceControl.Transaction t = mTransactionPool.acquire();
- onEnd(mCancel, t);
- t.apply();
- mTransactionPool.release(t);
- mAnimation = null;
- }
- });
- mAnimation.start();
- }
-
- private String dumpState() {
- return "top:" + mHiddenTop + "->" + mShownTop
- + " adj:" + mAdjusted + "->" + mTargetAdjusted + "(" + mLastAdjustTop + ")"
- + " shw:" + mImeWasShown + "->" + mTargetShown
- + " dims:" + mLastPrimaryDim + "," + mLastSecondaryDim
- + "->" + mTargetPrimaryDim + "," + mTargetSecondaryDim
- + " shf:" + mSecondaryHasFocus + " desync:" + (mAnimation != null)
- + " paus:" + mPaused + "[" + mPausedTargetAdjusted + "]";
- }
-
- /** Completely aborts/resets adjustment state */
- public void pause(int displayId) {
- if (DEBUG) Slog.d(TAG, "ime pause posting " + dumpState());
- mMainExecutor.execute(() -> {
- if (DEBUG) Slog.d(TAG, "ime pause run posted " + dumpState());
- if (mPaused) {
- return;
- }
- mPaused = true;
- mPausedTargetAdjusted = mTargetAdjusted;
- mTargetAdjusted = false;
- mTargetPrimaryDim = mTargetSecondaryDim = 0.f;
- updateImeAdjustState();
- startAsyncAnimation();
- if (mAnimation != null) {
- mAnimation.end();
- }
- });
- }
-
- public void resume(int displayId) {
- if (DEBUG) Slog.d(TAG, "ime resume posting " + dumpState());
- mMainExecutor.execute(() -> {
- if (DEBUG) Slog.d(TAG, "ime resume run posted " + dumpState());
- if (!mPaused) {
- return;
- }
- mPaused = false;
- mTargetAdjusted = mPausedTargetAdjusted;
- updateDimTargets();
- final DividerView view = getView();
- if ((mTargetAdjusted != mAdjusted) && !mSplits.mSplitScreenController.isMinimized()
- && view != null) {
- // End unminimize animations since they conflict with adjustment animations.
- view.finishAnimations();
- }
- updateImeAdjustState();
- startAsyncAnimation();
- });
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerState.java
deleted file mode 100644
index af2ab15..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerState.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.legacysplitscreen;
-
-/**
- * Class to hold state of divider that needs to persist across configuration changes.
- */
-final class DividerState {
- public boolean animateAfterRecentsDrawn;
- public float mRatioPositionBeforeMinimized;
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerView.java
deleted file mode 100644
index 73be283..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerView.java
+++ /dev/null
@@ -1,1314 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.legacysplitscreen;
-
-import static android.view.PointerIcon.TYPE_HORIZONTAL_DOUBLE_ARROW;
-import static android.view.PointerIcon.TYPE_VERTICAL_DOUBLE_ARROW;
-import static android.view.WindowManager.DOCKED_RIGHT;
-
-import static com.android.wm.shell.animation.Interpolators.DIM_INTERPOLATOR;
-import static com.android.wm.shell.animation.Interpolators.SLOWDOWN_INTERPOLATOR;
-import static com.android.wm.shell.common.split.DividerView.TOUCH_ANIMATION_DURATION;
-import static com.android.wm.shell.common.split.DividerView.TOUCH_RELEASE_ANIMATION_DURATION;
-
-import android.animation.AnimationHandler;
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ValueAnimator;
-import android.annotation.Nullable;
-import android.content.Context;
-import android.content.res.Configuration;
-import android.graphics.Matrix;
-import android.graphics.Rect;
-import android.graphics.Region;
-import android.graphics.Region.Op;
-import android.hardware.display.DisplayManager;
-import android.os.Bundle;
-import android.util.AttributeSet;
-import android.util.Slog;
-import android.view.Choreographer;
-import android.view.Display;
-import android.view.MotionEvent;
-import android.view.PointerIcon;
-import android.view.SurfaceControl;
-import android.view.SurfaceControl.Transaction;
-import android.view.VelocityTracker;
-import android.view.View;
-import android.view.View.OnTouchListener;
-import android.view.ViewConfiguration;
-import android.view.ViewTreeObserver.InternalInsetsInfo;
-import android.view.ViewTreeObserver.OnComputeInternalInsetsListener;
-import android.view.WindowManager;
-import android.view.accessibility.AccessibilityNodeInfo;
-import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
-import android.view.animation.Interpolator;
-import android.view.animation.PathInterpolator;
-import android.widget.FrameLayout;
-
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.internal.policy.DividerSnapAlgorithm;
-import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget;
-import com.android.internal.policy.DockedDividerUtils;
-import com.android.wm.shell.R;
-import com.android.wm.shell.animation.FlingAnimationUtils;
-import com.android.wm.shell.animation.Interpolators;
-import com.android.wm.shell.common.split.DividerHandleView;
-
-import java.util.function.Consumer;
-
-/**
- * Docked stack divider.
- */
-public class DividerView extends FrameLayout implements OnTouchListener,
- OnComputeInternalInsetsListener {
- private static final String TAG = "DividerView";
- private static final boolean DEBUG = LegacySplitScreenController.DEBUG;
-
- interface DividerCallbacks {
- void onDraggingStart();
- void onDraggingEnd();
- }
-
- public static final int INVALID_RECENTS_GROW_TARGET = -1;
-
- private static final int LOG_VALUE_RESIZE_50_50 = 0;
- private static final int LOG_VALUE_RESIZE_DOCKED_SMALLER = 1;
- private static final int LOG_VALUE_RESIZE_DOCKED_LARGER = 2;
-
- private static final int LOG_VALUE_UNDOCK_MAX_DOCKED = 0;
- private static final int LOG_VALUE_UNDOCK_MAX_OTHER = 1;
-
- private static final int TASK_POSITION_SAME = Integer.MAX_VALUE;
-
- /**
- * How much the background gets scaled when we are in the minimized dock state.
- */
- private static final float MINIMIZE_DOCK_SCALE = 0f;
- private static final float ADJUSTED_FOR_IME_SCALE = 0.5f;
-
- private static final Interpolator IME_ADJUST_INTERPOLATOR =
- new PathInterpolator(0.2f, 0f, 0.1f, 1f);
-
- private DividerHandleView mHandle;
- private View mBackground;
- private MinimizedDockShadow mMinimizedShadow;
- private int mStartX;
- private int mStartY;
- private int mStartPosition;
- private int mDockSide;
- private boolean mMoving;
- private int mTouchSlop;
- private boolean mBackgroundLifted;
- private boolean mIsInMinimizeInteraction;
- SnapTarget mSnapTargetBeforeMinimized;
-
- private int mDividerInsets;
- private final Display mDefaultDisplay;
-
- private int mDividerSize;
- private int mTouchElevation;
- private int mLongPressEntraceAnimDuration;
-
- private final Rect mDockedRect = new Rect();
- private final Rect mDockedTaskRect = new Rect();
- private final Rect mOtherTaskRect = new Rect();
- private final Rect mOtherRect = new Rect();
- private final Rect mDockedInsetRect = new Rect();
- private final Rect mOtherInsetRect = new Rect();
- private final Rect mLastResizeRect = new Rect();
- private final Rect mTmpRect = new Rect();
- private LegacySplitScreenController mSplitScreenController;
- private WindowManagerProxy mWindowManagerProxy;
- private DividerWindowManager mWindowManager;
- private VelocityTracker mVelocityTracker;
- private FlingAnimationUtils mFlingAnimationUtils;
- private LegacySplitDisplayLayout mSplitLayout;
- private DividerImeController mImeController;
- private DividerCallbacks mCallback;
-
- private AnimationHandler mSfVsyncAnimationHandler;
- private ValueAnimator mCurrentAnimator;
- private boolean mEntranceAnimationRunning;
- private boolean mExitAnimationRunning;
- private int mExitStartPosition;
- private boolean mDockedStackMinimized;
- private boolean mHomeStackResizable;
- private boolean mAdjustedForIme;
- private DividerState mState;
-
- private LegacySplitScreenTaskListener mTiles;
- boolean mFirstLayout = true;
- int mDividerPositionX;
- int mDividerPositionY;
-
- private final Matrix mTmpMatrix = new Matrix();
- private final float[] mTmpValues = new float[9];
-
- // The view is removed or in the process of been removed from the system.
- private boolean mRemoved;
-
- // Whether the surface for this view has been hidden regardless of actual visibility. This is
- // used interact with keyguard.
- private boolean mSurfaceHidden = false;
-
- private final AccessibilityDelegate mHandleDelegate = new AccessibilityDelegate() {
- @Override
- public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
- super.onInitializeAccessibilityNodeInfo(host, info);
- final DividerSnapAlgorithm snapAlgorithm = getSnapAlgorithm();
- if (isHorizontalDivision()) {
- info.addAction(new AccessibilityAction(R.id.action_move_tl_full,
- mContext.getString(R.string.accessibility_action_divider_top_full)));
- if (snapAlgorithm.isFirstSplitTargetAvailable()) {
- info.addAction(new AccessibilityAction(R.id.action_move_tl_70,
- mContext.getString(R.string.accessibility_action_divider_top_70)));
- }
- if (snapAlgorithm.showMiddleSplitTargetForAccessibility()) {
- // Only show the middle target if there are more than 1 split target
- info.addAction(new AccessibilityAction(R.id.action_move_tl_50,
- mContext.getString(R.string.accessibility_action_divider_top_50)));
- }
- if (snapAlgorithm.isLastSplitTargetAvailable()) {
- info.addAction(new AccessibilityAction(R.id.action_move_tl_30,
- mContext.getString(R.string.accessibility_action_divider_top_30)));
- }
- info.addAction(new AccessibilityAction(R.id.action_move_rb_full,
- mContext.getString(R.string.accessibility_action_divider_bottom_full)));
- } else {
- info.addAction(new AccessibilityAction(R.id.action_move_tl_full,
- mContext.getString(R.string.accessibility_action_divider_left_full)));
- if (snapAlgorithm.isFirstSplitTargetAvailable()) {
- info.addAction(new AccessibilityAction(R.id.action_move_tl_70,
- mContext.getString(R.string.accessibility_action_divider_left_70)));
- }
- if (snapAlgorithm.showMiddleSplitTargetForAccessibility()) {
- // Only show the middle target if there are more than 1 split target
- info.addAction(new AccessibilityAction(R.id.action_move_tl_50,
- mContext.getString(R.string.accessibility_action_divider_left_50)));
- }
- if (snapAlgorithm.isLastSplitTargetAvailable()) {
- info.addAction(new AccessibilityAction(R.id.action_move_tl_30,
- mContext.getString(R.string.accessibility_action_divider_left_30)));
- }
- info.addAction(new AccessibilityAction(R.id.action_move_rb_full,
- mContext.getString(R.string.accessibility_action_divider_right_full)));
- }
- }
-
- @Override
- public boolean performAccessibilityAction(View host, int action, Bundle args) {
- int currentPosition = getCurrentPosition();
- SnapTarget nextTarget = null;
- DividerSnapAlgorithm snapAlgorithm = mSplitLayout.getSnapAlgorithm();
- if (action == R.id.action_move_tl_full) {
- nextTarget = snapAlgorithm.getDismissEndTarget();
- } else if (action == R.id.action_move_tl_70) {
- nextTarget = snapAlgorithm.getLastSplitTarget();
- } else if (action == R.id.action_move_tl_50) {
- nextTarget = snapAlgorithm.getMiddleTarget();
- } else if (action == R.id.action_move_tl_30) {
- nextTarget = snapAlgorithm.getFirstSplitTarget();
- } else if (action == R.id.action_move_rb_full) {
- nextTarget = snapAlgorithm.getDismissStartTarget();
- }
- if (nextTarget != null) {
- startDragging(true /* animate */, false /* touching */);
- stopDragging(currentPosition, nextTarget, 250, Interpolators.FAST_OUT_SLOW_IN);
- return true;
- }
- return super.performAccessibilityAction(host, action, args);
- }
- };
-
- private final Runnable mResetBackgroundRunnable = new Runnable() {
- @Override
- public void run() {
- resetBackground();
- }
- };
-
- public DividerView(Context context) {
- this(context, null);
- }
-
- public DividerView(Context context, @Nullable AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public DividerView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
- this(context, attrs, defStyleAttr, 0);
- }
-
- public DividerView(Context context, @Nullable AttributeSet attrs, int defStyleAttr,
- int defStyleRes) {
- super(context, attrs, defStyleAttr, defStyleRes);
- final DisplayManager displayManager =
- (DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE);
- mDefaultDisplay = displayManager.getDisplay(Display.DEFAULT_DISPLAY);
- }
-
- public void setAnimationHandler(AnimationHandler sfVsyncAnimationHandler) {
- mSfVsyncAnimationHandler = sfVsyncAnimationHandler;
- }
-
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
- mHandle = findViewById(R.id.docked_divider_handle);
- mBackground = findViewById(R.id.docked_divider_background);
- mMinimizedShadow = findViewById(R.id.minimized_dock_shadow);
- mHandle.setOnTouchListener(this);
- final int dividerWindowWidth = getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.docked_stack_divider_thickness);
- mDividerInsets = getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.docked_stack_divider_insets);
- mDividerSize = dividerWindowWidth - 2 * mDividerInsets;
- mTouchElevation = getResources().getDimensionPixelSize(
- R.dimen.docked_stack_divider_lift_elevation);
- mLongPressEntraceAnimDuration = getResources().getInteger(
- R.integer.long_press_dock_anim_duration);
- mTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
- mFlingAnimationUtils = new FlingAnimationUtils(getResources().getDisplayMetrics(), 0.3f);
- boolean landscape = getResources().getConfiguration().orientation
- == Configuration.ORIENTATION_LANDSCAPE;
- mHandle.setPointerIcon(PointerIcon.getSystemIcon(getContext(),
- landscape ? TYPE_HORIZONTAL_DOUBLE_ARROW : TYPE_VERTICAL_DOUBLE_ARROW));
- getViewTreeObserver().addOnComputeInternalInsetsListener(this);
- mHandle.setAccessibilityDelegate(mHandleDelegate);
- }
-
- @Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
-
- // Save the current target if not minimized once attached to window
- if (mDockSide != WindowManager.DOCKED_INVALID && !mIsInMinimizeInteraction) {
- saveSnapTargetBeforeMinimized(mSnapTargetBeforeMinimized);
- }
- mFirstLayout = true;
- }
-
- void onDividerRemoved() {
- mRemoved = true;
- mCallback = null;
- }
-
- @Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- super.onLayout(changed, left, top, right, bottom);
- if (mFirstLayout) {
- // Wait for first layout so that the ViewRootImpl surface has been created.
- initializeSurfaceState();
- mFirstLayout = false;
- }
- int minimizeLeft = 0;
- int minimizeTop = 0;
- if (mDockSide == WindowManager.DOCKED_TOP) {
- minimizeTop = mBackground.getTop();
- } else if (mDockSide == WindowManager.DOCKED_LEFT) {
- minimizeLeft = mBackground.getLeft();
- } else if (mDockSide == WindowManager.DOCKED_RIGHT) {
- minimizeLeft = mBackground.getRight() - mMinimizedShadow.getWidth();
- }
- mMinimizedShadow.layout(minimizeLeft, minimizeTop,
- minimizeLeft + mMinimizedShadow.getMeasuredWidth(),
- minimizeTop + mMinimizedShadow.getMeasuredHeight());
- if (changed) {
- notifySplitScreenBoundsChanged();
- }
- }
-
- void injectDependencies(LegacySplitScreenController splitScreenController,
- DividerWindowManager windowManager, DividerState dividerState,
- DividerCallbacks callback, LegacySplitScreenTaskListener tiles,
- LegacySplitDisplayLayout sdl, DividerImeController imeController,
- WindowManagerProxy wmProxy) {
- mSplitScreenController = splitScreenController;
- mWindowManager = windowManager;
- mState = dividerState;
- mCallback = callback;
- mTiles = tiles;
- mSplitLayout = sdl;
- mImeController = imeController;
- mWindowManagerProxy = wmProxy;
-
- if (mState.mRatioPositionBeforeMinimized == 0) {
- // Set the middle target as the initial state
- mSnapTargetBeforeMinimized = mSplitLayout.getSnapAlgorithm().getMiddleTarget();
- } else {
- repositionSnapTargetBeforeMinimized();
- }
- }
-
- /** Gets non-minimized secondary bounds of split screen. */
- public Rect getNonMinimizedSplitScreenSecondaryBounds() {
- mOtherTaskRect.set(mSplitLayout.mSecondary);
- return mOtherTaskRect;
- }
-
- private boolean inSplitMode() {
- return getVisibility() == VISIBLE;
- }
-
- /** Unlike setVisible, this directly hides the surface without changing view visibility. */
- void setHidden(boolean hidden) {
- if (mSurfaceHidden == hidden) {
- return;
- }
- mSurfaceHidden = hidden;
- post(() -> {
- final SurfaceControl sc = getWindowSurfaceControl();
- if (sc == null) {
- return;
- }
- Transaction t = mTiles.getTransaction();
- if (hidden) {
- t.hide(sc);
- } else {
- t.show(sc);
- }
- mImeController.setDimsHidden(t, hidden);
- t.apply();
- mTiles.releaseTransaction(t);
- });
- }
-
- boolean isHidden() {
- return getVisibility() != View.VISIBLE || mSurfaceHidden;
- }
-
- /** Starts dragging the divider bar. */
- public boolean startDragging(boolean animate, boolean touching) {
- cancelFlingAnimation();
- if (touching) {
- mHandle.setTouching(true, animate);
- }
- mDockSide = mSplitLayout.getPrimarySplitSide();
-
- mWindowManagerProxy.setResizing(true);
- if (touching) {
- mWindowManager.setSlippery(false);
- liftBackground();
- }
- if (mCallback != null) {
- mCallback.onDraggingStart();
- }
- return inSplitMode();
- }
-
- /** Stops dragging the divider bar. */
- public void stopDragging(int position, float velocity, boolean avoidDismissStart,
- boolean logMetrics) {
- mHandle.setTouching(false, true /* animate */);
- fling(position, velocity, avoidDismissStart, logMetrics);
- mWindowManager.setSlippery(true);
- releaseBackground();
- }
-
- private void stopDragging(int position, SnapTarget target, long duration,
- Interpolator interpolator) {
- stopDragging(position, target, duration, 0 /* startDelay*/, 0 /* endDelay */, interpolator);
- }
-
- private void stopDragging(int position, SnapTarget target, long duration,
- Interpolator interpolator, long endDelay) {
- stopDragging(position, target, duration, 0 /* startDelay*/, endDelay, interpolator);
- }
-
- private void stopDragging(int position, SnapTarget target, long duration, long startDelay,
- long endDelay, Interpolator interpolator) {
- mHandle.setTouching(false, true /* animate */);
- flingTo(position, target, duration, startDelay, endDelay, interpolator);
- mWindowManager.setSlippery(true);
- releaseBackground();
- }
-
- private void stopDragging() {
- mHandle.setTouching(false, true /* animate */);
- mWindowManager.setSlippery(true);
- mWindowManagerProxy.setResizing(false);
- releaseBackground();
- }
-
- private void updateDockSide() {
- mDockSide = mSplitLayout.getPrimarySplitSide();
- mMinimizedShadow.setDockSide(mDockSide);
- }
-
- public DividerSnapAlgorithm getSnapAlgorithm() {
- return mDockedStackMinimized ? mSplitLayout.getMinimizedSnapAlgorithm(mHomeStackResizable)
- : mSplitLayout.getSnapAlgorithm();
- }
-
- public int getCurrentPosition() {
- return isHorizontalDivision() ? mDividerPositionY : mDividerPositionX;
- }
-
- public boolean isMinimized() {
- return mDockedStackMinimized;
- }
-
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- convertToScreenCoordinates(event);
- final int action = event.getAction() & MotionEvent.ACTION_MASK;
- switch (action) {
- case MotionEvent.ACTION_DOWN:
- mVelocityTracker = VelocityTracker.obtain();
- mVelocityTracker.addMovement(event);
- mStartX = (int) event.getX();
- mStartY = (int) event.getY();
- boolean result = startDragging(true /* animate */, true /* touching */);
- if (!result) {
-
- // Weren't able to start dragging successfully, so cancel it again.
- stopDragging();
- }
- mStartPosition = getCurrentPosition();
- mMoving = false;
- return result;
- case MotionEvent.ACTION_MOVE:
- mVelocityTracker.addMovement(event);
- int x = (int) event.getX();
- int y = (int) event.getY();
- boolean exceededTouchSlop =
- isHorizontalDivision() && Math.abs(y - mStartY) > mTouchSlop
- || (!isHorizontalDivision() && Math.abs(x - mStartX) > mTouchSlop);
- if (!mMoving && exceededTouchSlop) {
- mStartX = x;
- mStartY = y;
- mMoving = true;
- }
- if (mMoving && mDockSide != WindowManager.DOCKED_INVALID) {
- SnapTarget snapTarget = getSnapAlgorithm().calculateSnapTarget(
- mStartPosition, 0 /* velocity */, false /* hardDismiss */);
- resizeStackSurfaces(calculatePosition(x, y), mStartPosition, snapTarget,
- null /* transaction */);
- }
- break;
- case MotionEvent.ACTION_UP:
- case MotionEvent.ACTION_CANCEL:
- if (!mMoving) {
- stopDragging();
- break;
- }
-
- x = (int) event.getRawX();
- y = (int) event.getRawY();
- mVelocityTracker.addMovement(event);
- mVelocityTracker.computeCurrentVelocity(1000);
- int position = calculatePosition(x, y);
- stopDragging(position, isHorizontalDivision() ? mVelocityTracker.getYVelocity()
- : mVelocityTracker.getXVelocity(), false /* avoidDismissStart */,
- true /* log */);
- mMoving = false;
- break;
- }
- return true;
- }
-
- private void logResizeEvent(SnapTarget snapTarget) {
- if (snapTarget == mSplitLayout.getSnapAlgorithm().getDismissStartTarget()) {
- MetricsLogger.action(
- mContext, MetricsEvent.ACTION_WINDOW_UNDOCK_MAX, dockSideTopLeft(mDockSide)
- ? LOG_VALUE_UNDOCK_MAX_OTHER
- : LOG_VALUE_UNDOCK_MAX_DOCKED);
- } else if (snapTarget == mSplitLayout.getSnapAlgorithm().getDismissEndTarget()) {
- MetricsLogger.action(
- mContext, MetricsEvent.ACTION_WINDOW_UNDOCK_MAX, dockSideBottomRight(mDockSide)
- ? LOG_VALUE_UNDOCK_MAX_OTHER
- : LOG_VALUE_UNDOCK_MAX_DOCKED);
- } else if (snapTarget == mSplitLayout.getSnapAlgorithm().getMiddleTarget()) {
- MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_DOCK_RESIZE,
- LOG_VALUE_RESIZE_50_50);
- } else if (snapTarget == mSplitLayout.getSnapAlgorithm().getFirstSplitTarget()) {
- MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_DOCK_RESIZE,
- dockSideTopLeft(mDockSide)
- ? LOG_VALUE_RESIZE_DOCKED_SMALLER
- : LOG_VALUE_RESIZE_DOCKED_LARGER);
- } else if (snapTarget == mSplitLayout.getSnapAlgorithm().getLastSplitTarget()) {
- MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_DOCK_RESIZE,
- dockSideTopLeft(mDockSide)
- ? LOG_VALUE_RESIZE_DOCKED_LARGER
- : LOG_VALUE_RESIZE_DOCKED_SMALLER);
- }
- }
-
- private void convertToScreenCoordinates(MotionEvent event) {
- event.setLocation(event.getRawX(), event.getRawY());
- }
-
- private void fling(int position, float velocity, boolean avoidDismissStart,
- boolean logMetrics) {
- DividerSnapAlgorithm currentSnapAlgorithm = getSnapAlgorithm();
- SnapTarget snapTarget = currentSnapAlgorithm.calculateSnapTarget(position, velocity);
- if (avoidDismissStart && snapTarget == currentSnapAlgorithm.getDismissStartTarget()) {
- snapTarget = currentSnapAlgorithm.getFirstSplitTarget();
- }
- if (logMetrics) {
- logResizeEvent(snapTarget);
- }
- ValueAnimator anim = getFlingAnimator(position, snapTarget, 0 /* endDelay */);
- mFlingAnimationUtils.apply(anim, position, snapTarget.position, velocity);
- anim.start();
- }
-
- private void flingTo(int position, SnapTarget target, long duration, long startDelay,
- long endDelay, Interpolator interpolator) {
- ValueAnimator anim = getFlingAnimator(position, target, endDelay);
- anim.setDuration(duration);
- anim.setStartDelay(startDelay);
- anim.setInterpolator(interpolator);
- anim.start();
- }
-
- private ValueAnimator getFlingAnimator(int position, final SnapTarget snapTarget,
- final long endDelay) {
- if (mCurrentAnimator != null) {
- cancelFlingAnimation();
- updateDockSide();
- }
- if (DEBUG) Slog.d(TAG, "Getting fling " + position + "->" + snapTarget.position);
- final boolean taskPositionSameAtEnd = snapTarget.flag == SnapTarget.FLAG_NONE;
- ValueAnimator anim = ValueAnimator.ofInt(position, snapTarget.position);
- anim.addUpdateListener(animation -> resizeStackSurfaces((int) animation.getAnimatedValue(),
- taskPositionSameAtEnd && animation.getAnimatedFraction() == 1f
- ? TASK_POSITION_SAME
- : snapTarget.taskPosition,
- snapTarget, null /* transaction */));
- Consumer<Boolean> endAction = cancelled -> {
- if (DEBUG) Slog.d(TAG, "End Fling " + cancelled + " min:" + mIsInMinimizeInteraction);
- final boolean wasMinimizeInteraction = mIsInMinimizeInteraction;
- // Reset minimized divider position after unminimized state animation finishes.
- if (!cancelled && !mDockedStackMinimized && mIsInMinimizeInteraction) {
- mIsInMinimizeInteraction = false;
- }
- boolean dismissed = commitSnapFlags(snapTarget);
- mWindowManagerProxy.setResizing(false);
- updateDockSide();
- mCurrentAnimator = null;
- mEntranceAnimationRunning = false;
- mExitAnimationRunning = false;
- if (!dismissed && !wasMinimizeInteraction) {
- mWindowManagerProxy.applyResizeSplits(snapTarget.position, mSplitLayout);
- }
- if (mCallback != null) {
- mCallback.onDraggingEnd();
- }
-
- // Record last snap target the divider moved to
- if (!mIsInMinimizeInteraction) {
- // The last snapTarget position can be negative when the last divider position was
- // offscreen. In that case, save the middle (default) SnapTarget so calculating next
- // position isn't negative.
- final SnapTarget saveTarget;
- if (snapTarget.position < 0) {
- saveTarget = mSplitLayout.getSnapAlgorithm().getMiddleTarget();
- } else {
- saveTarget = snapTarget;
- }
- final DividerSnapAlgorithm snapAlgo = mSplitLayout.getSnapAlgorithm();
- if (saveTarget.position != snapAlgo.getDismissEndTarget().position
- && saveTarget.position != snapAlgo.getDismissStartTarget().position) {
- saveSnapTargetBeforeMinimized(saveTarget);
- }
- }
- notifySplitScreenBoundsChanged();
- };
- anim.addListener(new AnimatorListenerAdapter() {
-
- private boolean mCancelled;
-
- @Override
- public void onAnimationCancel(Animator animation) {
- mCancelled = true;
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- long delay = 0;
- if (endDelay != 0) {
- delay = endDelay;
- } else if (mCancelled) {
- delay = 0;
- }
- if (delay == 0) {
- endAction.accept(mCancelled);
- } else {
- final Boolean cancelled = mCancelled;
- if (DEBUG) Slog.d(TAG, "Posting endFling " + cancelled + " d:" + delay + "ms");
- getHandler().postDelayed(() -> endAction.accept(cancelled), delay);
- }
- }
- });
- mCurrentAnimator = anim;
- mCurrentAnimator.setAnimationHandler(mSfVsyncAnimationHandler);
- return anim;
- }
-
- private void notifySplitScreenBoundsChanged() {
- if (mSplitLayout.mPrimary == null || mSplitLayout.mSecondary == null) {
- return;
- }
- mOtherTaskRect.set(mSplitLayout.mSecondary);
-
- mTmpRect.set(mHandle.getLeft(), mHandle.getTop(), mHandle.getRight(), mHandle.getBottom());
- if (isHorizontalDivision()) {
- mTmpRect.offsetTo(mHandle.getLeft(), mDividerPositionY);
- } else {
- mTmpRect.offsetTo(mDividerPositionX, mHandle.getTop());
- }
- mWindowManagerProxy.setTouchRegion(mTmpRect);
-
- mTmpRect.set(mSplitLayout.mDisplayLayout.stableInsets());
- switch (mSplitLayout.getPrimarySplitSide()) {
- case WindowManager.DOCKED_LEFT:
- mTmpRect.left = 0;
- break;
- case WindowManager.DOCKED_RIGHT:
- mTmpRect.right = 0;
- break;
- case WindowManager.DOCKED_TOP:
- mTmpRect.top = 0;
- break;
- }
- mSplitScreenController.notifyBoundsChanged(mOtherTaskRect, mTmpRect);
- }
-
- private void cancelFlingAnimation() {
- if (mCurrentAnimator != null) {
- mCurrentAnimator.cancel();
- }
- }
-
- private boolean commitSnapFlags(SnapTarget target) {
- if (target.flag == SnapTarget.FLAG_NONE) {
- return false;
- }
- final boolean dismissOrMaximize;
- if (target.flag == SnapTarget.FLAG_DISMISS_START) {
- dismissOrMaximize = mDockSide == WindowManager.DOCKED_LEFT
- || mDockSide == WindowManager.DOCKED_TOP;
- } else {
- dismissOrMaximize = mDockSide == WindowManager.DOCKED_RIGHT
- || mDockSide == WindowManager.DOCKED_BOTTOM;
- }
- mWindowManagerProxy.dismissOrMaximizeDocked(mTiles, mSplitLayout, dismissOrMaximize);
- Transaction t = mTiles.getTransaction();
- setResizeDimLayer(t, true /* primary */, 0f);
- setResizeDimLayer(t, false /* primary */, 0f);
- t.apply();
- mTiles.releaseTransaction(t);
- return true;
- }
-
- private void liftBackground() {
- if (mBackgroundLifted) {
- return;
- }
- if (isHorizontalDivision()) {
- mBackground.animate().scaleY(1.4f);
- } else {
- mBackground.animate().scaleX(1.4f);
- }
- mBackground.animate()
- .setInterpolator(Interpolators.TOUCH_RESPONSE)
- .setDuration(TOUCH_ANIMATION_DURATION)
- .translationZ(mTouchElevation)
- .start();
-
- // Lift handle as well so it doesn't get behind the background, even though it doesn't
- // cast shadow.
- mHandle.animate()
- .setInterpolator(Interpolators.TOUCH_RESPONSE)
- .setDuration(TOUCH_ANIMATION_DURATION)
- .translationZ(mTouchElevation)
- .start();
- mBackgroundLifted = true;
- }
-
- private void releaseBackground() {
- if (!mBackgroundLifted) {
- return;
- }
- mBackground.animate()
- .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
- .setDuration(TOUCH_RELEASE_ANIMATION_DURATION)
- .translationZ(0)
- .scaleX(1f)
- .scaleY(1f)
- .start();
- mHandle.animate()
- .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
- .setDuration(TOUCH_RELEASE_ANIMATION_DURATION)
- .translationZ(0)
- .start();
- mBackgroundLifted = false;
- }
-
- private void initializeSurfaceState() {
- int midPos = mSplitLayout.getSnapAlgorithm().getMiddleTarget().position;
- // Recalculate the split-layout's internal tile bounds
- mSplitLayout.resizeSplits(midPos);
- Transaction t = mTiles.getTransaction();
- if (mDockedStackMinimized) {
- int position = mSplitLayout.getMinimizedSnapAlgorithm(mHomeStackResizable)
- .getMiddleTarget().position;
- calculateBoundsForPosition(position, mDockSide, mDockedRect);
- calculateBoundsForPosition(position, DockedDividerUtils.invertDockSide(mDockSide),
- mOtherRect);
- mDividerPositionX = mDividerPositionY = position;
- resizeSplitSurfaces(t, mDockedRect, mSplitLayout.mPrimary,
- mOtherRect, mSplitLayout.mSecondary);
- } else {
- resizeSplitSurfaces(t, mSplitLayout.mPrimary, null,
- mSplitLayout.mSecondary, null);
- }
- setResizeDimLayer(t, true /* primary */, 0.f /* alpha */);
- setResizeDimLayer(t, false /* secondary */, 0.f /* alpha */);
- t.apply();
- mTiles.releaseTransaction(t);
-
- // Get the actually-visible bar dimensions (relative to full window). This is a thin
- // bar going through the center.
- final Rect dividerBar = isHorizontalDivision()
- ? new Rect(0, mDividerInsets, mSplitLayout.mDisplayLayout.width(),
- mDividerInsets + mDividerSize)
- : new Rect(mDividerInsets, 0, mDividerInsets + mDividerSize,
- mSplitLayout.mDisplayLayout.height());
- final Region touchRegion = new Region(dividerBar);
- // Add in the "draggable" portion. While not visible, this is an expanded area that the
- // user can interact with.
- touchRegion.union(new Rect(mHandle.getLeft(), mHandle.getTop(),
- mHandle.getRight(), mHandle.getBottom()));
- mWindowManager.setTouchRegion(touchRegion);
- }
-
- void setMinimizedDockStack(boolean minimized, boolean isHomeStackResizable,
- Transaction t) {
- mHomeStackResizable = isHomeStackResizable;
- updateDockSide();
- if (!minimized) {
- resetBackground();
- }
- mMinimizedShadow.setAlpha(minimized ? 1f : 0f);
- if (mDockedStackMinimized != minimized) {
- mDockedStackMinimized = minimized;
- if (mSplitLayout.mDisplayLayout.rotation() != mDefaultDisplay.getRotation()) {
- // Splitscreen to minimize is about to starts after rotating landscape to seascape,
- // update display info and snap algorithm targets
- repositionSnapTargetBeforeMinimized();
- }
- if (mIsInMinimizeInteraction != minimized || mCurrentAnimator != null) {
- cancelFlingAnimation();
- if (minimized) {
- // Relayout to recalculate the divider shadow when minimizing
- requestLayout();
- mIsInMinimizeInteraction = true;
- resizeStackSurfaces(mSplitLayout.getMinimizedSnapAlgorithm(mHomeStackResizable)
- .getMiddleTarget(), t);
- } else {
- resizeStackSurfaces(mSnapTargetBeforeMinimized, t);
- mIsInMinimizeInteraction = false;
- }
- }
- }
- }
-
- void enterSplitMode(boolean isHomeStackResizable) {
- setHidden(false);
-
- SnapTarget miniMid =
- mSplitLayout.getMinimizedSnapAlgorithm(isHomeStackResizable).getMiddleTarget();
- if (mDockedStackMinimized) {
- mDividerPositionY = mDividerPositionX = miniMid.position;
- }
- }
-
- /**
- * Tries to grab a surface control from ViewRootImpl. If this isn't available for some reason
- * (ie. the window isn't ready yet), it will get the surfacecontrol that the WindowlessWM has
- * assigned to it.
- */
- private SurfaceControl getWindowSurfaceControl() {
- return mWindowManager.mSystemWindows.getViewSurface(this);
- }
-
- void exitSplitMode() {
- // The view is going to be removed right after this function involved, updates the surface
- // in the current thread instead of posting it to the view's UI thread.
- final SurfaceControl sc = getWindowSurfaceControl();
- if (sc == null) {
- return;
- }
- Transaction t = mTiles.getTransaction();
- t.hide(sc);
- mImeController.setDimsHidden(t, true);
- t.apply();
- mTiles.releaseTransaction(t);
-
- // Reset tile bounds
- int midPos = mSplitLayout.getSnapAlgorithm().getMiddleTarget().position;
- mWindowManagerProxy.applyResizeSplits(midPos, mSplitLayout);
- }
-
- void setMinimizedDockStack(boolean minimized, long animDuration,
- boolean isHomeStackResizable) {
- if (DEBUG) Slog.d(TAG, "setMinDock: " + mDockedStackMinimized + "->" + minimized);
- mHomeStackResizable = isHomeStackResizable;
- updateDockSide();
- if (mDockedStackMinimized != minimized) {
- mIsInMinimizeInteraction = true;
- mDockedStackMinimized = minimized;
- stopDragging(minimized
- ? mSnapTargetBeforeMinimized.position
- : getCurrentPosition(),
- minimized
- ? mSplitLayout.getMinimizedSnapAlgorithm(mHomeStackResizable)
- .getMiddleTarget()
- : mSnapTargetBeforeMinimized,
- animDuration, Interpolators.FAST_OUT_SLOW_IN, 0);
- setAdjustedForIme(false, animDuration);
- }
- if (!minimized) {
- mBackground.animate().withEndAction(mResetBackgroundRunnable);
- }
- mBackground.animate()
- .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
- .setDuration(animDuration)
- .start();
- }
-
- // Needed to end any currently playing animations when they might compete with other anims
- // (specifically, IME adjust animation immediately after leaving minimized). Someday maybe
- // these can be unified, but not today.
- void finishAnimations() {
- if (mCurrentAnimator != null) {
- mCurrentAnimator.end();
- }
- }
-
- void setAdjustedForIme(boolean adjustedForIme, long animDuration) {
- if (mAdjustedForIme == adjustedForIme) {
- return;
- }
- updateDockSide();
- mHandle.animate()
- .setInterpolator(IME_ADJUST_INTERPOLATOR)
- .setDuration(animDuration)
- .alpha(adjustedForIme ? 0f : 1f)
- .start();
- if (mDockSide == WindowManager.DOCKED_TOP) {
- mBackground.setPivotY(0);
- mBackground.animate()
- .scaleY(adjustedForIme ? ADJUSTED_FOR_IME_SCALE : 1f);
- }
- if (!adjustedForIme) {
- mBackground.animate().withEndAction(mResetBackgroundRunnable);
- }
- mBackground.animate()
- .setInterpolator(IME_ADJUST_INTERPOLATOR)
- .setDuration(animDuration)
- .start();
- mAdjustedForIme = adjustedForIme;
- }
-
- private void saveSnapTargetBeforeMinimized(SnapTarget target) {
- mSnapTargetBeforeMinimized = target;
- mState.mRatioPositionBeforeMinimized = (float) target.position
- / (isHorizontalDivision() ? mSplitLayout.mDisplayLayout.height()
- : mSplitLayout.mDisplayLayout.width());
- }
-
- private void resetBackground() {
- mBackground.setPivotX(mBackground.getWidth() / 2);
- mBackground.setPivotY(mBackground.getHeight() / 2);
- mBackground.setScaleX(1f);
- mBackground.setScaleY(1f);
- mMinimizedShadow.setAlpha(0f);
- }
-
- @Override
- protected void onConfigurationChanged(Configuration newConfig) {
- super.onConfigurationChanged(newConfig);
- }
-
- private void repositionSnapTargetBeforeMinimized() {
- int position = (int) (mState.mRatioPositionBeforeMinimized
- * (isHorizontalDivision() ? mSplitLayout.mDisplayLayout.height()
- : mSplitLayout.mDisplayLayout.width()));
-
- // Set the snap target before minimized but do not save until divider is attached and not
- // minimized because it does not know its minimized state yet.
- mSnapTargetBeforeMinimized =
- mSplitLayout.getSnapAlgorithm().calculateNonDismissingSnapTarget(position);
- }
-
- private int calculatePosition(int touchX, int touchY) {
- return isHorizontalDivision() ? calculateYPosition(touchY) : calculateXPosition(touchX);
- }
-
- public boolean isHorizontalDivision() {
- return getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;
- }
-
- private int calculateXPosition(int touchX) {
- return mStartPosition + touchX - mStartX;
- }
-
- private int calculateYPosition(int touchY) {
- return mStartPosition + touchY - mStartY;
- }
-
- private void alignTopLeft(Rect containingRect, Rect rect) {
- int width = rect.width();
- int height = rect.height();
- rect.set(containingRect.left, containingRect.top,
- containingRect.left + width, containingRect.top + height);
- }
-
- private void alignBottomRight(Rect containingRect, Rect rect) {
- int width = rect.width();
- int height = rect.height();
- rect.set(containingRect.right - width, containingRect.bottom - height,
- containingRect.right, containingRect.bottom);
- }
-
- private void calculateBoundsForPosition(int position, int dockSide, Rect outRect) {
- DockedDividerUtils.calculateBoundsForPosition(position, dockSide, outRect,
- mSplitLayout.mDisplayLayout.width(), mSplitLayout.mDisplayLayout.height(),
- mDividerSize);
- }
-
- private void resizeStackSurfaces(SnapTarget taskSnapTarget, Transaction t) {
- resizeStackSurfaces(taskSnapTarget.position, taskSnapTarget.position, taskSnapTarget, t);
- }
-
- void resizeSplitSurfaces(Transaction t, Rect dockedRect, Rect otherRect) {
- resizeSplitSurfaces(t, dockedRect, null, otherRect, null);
- }
-
- private void resizeSplitSurfaces(Transaction t, Rect dockedRect, Rect dockedTaskRect,
- Rect otherRect, Rect otherTaskRect) {
- dockedTaskRect = dockedTaskRect == null ? dockedRect : dockedTaskRect;
- otherTaskRect = otherTaskRect == null ? otherRect : otherTaskRect;
-
- mDividerPositionX = mSplitLayout.getPrimarySplitSide() == DOCKED_RIGHT
- ? otherRect.right : dockedRect.right;
- mDividerPositionY = dockedRect.bottom;
-
- if (DEBUG) {
- Slog.d(TAG, "Resizing split surfaces: " + dockedRect + " " + dockedTaskRect
- + " " + otherRect + " " + otherTaskRect);
- }
-
- t.setPosition(mTiles.mPrimarySurface, dockedTaskRect.left, dockedTaskRect.top);
- Rect crop = new Rect(dockedRect);
- crop.offsetTo(-Math.min(dockedTaskRect.left - dockedRect.left, 0),
- -Math.min(dockedTaskRect.top - dockedRect.top, 0));
- t.setWindowCrop(mTiles.mPrimarySurface, crop);
- t.setPosition(mTiles.mSecondarySurface, otherTaskRect.left, otherTaskRect.top);
- crop.set(otherRect);
- crop.offsetTo(-(otherTaskRect.left - otherRect.left),
- -(otherTaskRect.top - otherRect.top));
- t.setWindowCrop(mTiles.mSecondarySurface, crop);
- final SurfaceControl dividerCtrl = getWindowSurfaceControl();
- if (dividerCtrl != null) {
- if (isHorizontalDivision()) {
- t.setPosition(dividerCtrl, 0, mDividerPositionY - mDividerInsets);
- } else {
- t.setPosition(dividerCtrl, mDividerPositionX - mDividerInsets, 0);
- }
- }
- }
-
- void setResizeDimLayer(Transaction t, boolean primary, float alpha) {
- SurfaceControl dim = primary ? mTiles.mPrimaryDim : mTiles.mSecondaryDim;
- if (alpha <= 0.001f) {
- t.hide(dim);
- } else {
- t.setAlpha(dim, alpha);
- t.show(dim);
- }
- }
-
- void resizeStackSurfaces(int position, int taskPosition, SnapTarget taskSnapTarget,
- Transaction transaction) {
- if (mRemoved) {
- // This divider view has been removed so shouldn't have any additional influence.
- return;
- }
- calculateBoundsForPosition(position, mDockSide, mDockedRect);
- calculateBoundsForPosition(position, DockedDividerUtils.invertDockSide(mDockSide),
- mOtherRect);
-
- if (mDockedRect.equals(mLastResizeRect) && !mEntranceAnimationRunning) {
- return;
- }
-
- // Make sure shadows are updated
- if (mBackground.getZ() > 0f) {
- mBackground.invalidate();
- }
-
- final boolean ownTransaction = transaction == null;
- final Transaction t = ownTransaction ? mTiles.getTransaction() : transaction;
- mLastResizeRect.set(mDockedRect);
- if (mIsInMinimizeInteraction) {
- calculateBoundsForPosition(mSnapTargetBeforeMinimized.position, mDockSide,
- mDockedTaskRect);
- calculateBoundsForPosition(mSnapTargetBeforeMinimized.position,
- DockedDividerUtils.invertDockSide(mDockSide), mOtherTaskRect);
-
- // Move a right-docked-app to line up with the divider while dragging it
- if (mDockSide == DOCKED_RIGHT) {
- mDockedTaskRect.offset(Math.max(position, -mDividerSize)
- - mDockedTaskRect.left + mDividerSize, 0);
- }
- resizeSplitSurfaces(t, mDockedRect, mDockedTaskRect, mOtherRect, mOtherTaskRect);
- if (ownTransaction) {
- t.setFrameTimelineVsync(Choreographer.getSfInstance().getVsyncId());
- t.apply();
- mTiles.releaseTransaction(t);
- }
- return;
- }
-
- if (mEntranceAnimationRunning && taskPosition != TASK_POSITION_SAME) {
- calculateBoundsForPosition(taskPosition, mDockSide, mDockedTaskRect);
-
- // Move a docked app if from the right in position with the divider up to insets
- if (mDockSide == DOCKED_RIGHT) {
- mDockedTaskRect.offset(Math.max(position, -mDividerSize)
- - mDockedTaskRect.left + mDividerSize, 0);
- }
- calculateBoundsForPosition(taskPosition, DockedDividerUtils.invertDockSide(mDockSide),
- mOtherTaskRect);
- resizeSplitSurfaces(t, mDockedRect, mDockedTaskRect, mOtherRect, mOtherTaskRect);
- } else if (mExitAnimationRunning && taskPosition != TASK_POSITION_SAME) {
- calculateBoundsForPosition(taskPosition, mDockSide, mDockedTaskRect);
- mDockedInsetRect.set(mDockedTaskRect);
- calculateBoundsForPosition(mExitStartPosition,
- DockedDividerUtils.invertDockSide(mDockSide), mOtherTaskRect);
- mOtherInsetRect.set(mOtherTaskRect);
- applyExitAnimationParallax(mOtherTaskRect, position);
-
- // Move a right-docked-app to line up with the divider while dragging it
- if (mDockSide == DOCKED_RIGHT) {
- mDockedTaskRect.offset(position + mDividerSize, 0);
- }
- resizeSplitSurfaces(t, mDockedRect, mDockedTaskRect, mOtherRect, mOtherTaskRect);
- } else if (taskPosition != TASK_POSITION_SAME) {
- calculateBoundsForPosition(position, DockedDividerUtils.invertDockSide(mDockSide),
- mOtherRect);
- int dockSideInverted = DockedDividerUtils.invertDockSide(mDockSide);
- int taskPositionDocked =
- restrictDismissingTaskPosition(taskPosition, mDockSide, taskSnapTarget);
- int taskPositionOther =
- restrictDismissingTaskPosition(taskPosition, dockSideInverted, taskSnapTarget);
- calculateBoundsForPosition(taskPositionDocked, mDockSide, mDockedTaskRect);
- calculateBoundsForPosition(taskPositionOther, dockSideInverted, mOtherTaskRect);
- mTmpRect.set(0, 0, mSplitLayout.mDisplayLayout.width(),
- mSplitLayout.mDisplayLayout.height());
- alignTopLeft(mDockedRect, mDockedTaskRect);
- alignTopLeft(mOtherRect, mOtherTaskRect);
- mDockedInsetRect.set(mDockedTaskRect);
- mOtherInsetRect.set(mOtherTaskRect);
- if (dockSideTopLeft(mDockSide)) {
- alignTopLeft(mTmpRect, mDockedInsetRect);
- alignBottomRight(mTmpRect, mOtherInsetRect);
- } else {
- alignBottomRight(mTmpRect, mDockedInsetRect);
- alignTopLeft(mTmpRect, mOtherInsetRect);
- }
- applyDismissingParallax(mDockedTaskRect, mDockSide, taskSnapTarget, position,
- taskPositionDocked);
- applyDismissingParallax(mOtherTaskRect, dockSideInverted, taskSnapTarget, position,
- taskPositionOther);
- resizeSplitSurfaces(t, mDockedRect, mDockedTaskRect, mOtherRect, mOtherTaskRect);
- } else {
- resizeSplitSurfaces(t, mDockedRect, null, mOtherRect, null);
- }
- SnapTarget closestDismissTarget = getSnapAlgorithm().getClosestDismissTarget(position);
- float dimFraction = getDimFraction(position, closestDismissTarget);
- setResizeDimLayer(t, isDismissTargetPrimary(closestDismissTarget), dimFraction);
- if (ownTransaction) {
- t.apply();
- mTiles.releaseTransaction(t);
- }
- }
-
- private void applyExitAnimationParallax(Rect taskRect, int position) {
- if (mDockSide == WindowManager.DOCKED_TOP) {
- taskRect.offset(0, (int) ((position - mExitStartPosition) * 0.25f));
- } else if (mDockSide == WindowManager.DOCKED_LEFT) {
- taskRect.offset((int) ((position - mExitStartPosition) * 0.25f), 0);
- } else if (mDockSide == WindowManager.DOCKED_RIGHT) {
- taskRect.offset((int) ((mExitStartPosition - position) * 0.25f), 0);
- }
- }
-
- private float getDimFraction(int position, SnapTarget dismissTarget) {
- if (mEntranceAnimationRunning) {
- return 0f;
- }
- float fraction = getSnapAlgorithm().calculateDismissingFraction(position);
- fraction = Math.max(0, Math.min(fraction, 1f));
- fraction = DIM_INTERPOLATOR.getInterpolation(fraction);
- return fraction;
- }
-
- /**
- * When the snap target is dismissing one side, make sure that the dismissing side doesn't get
- * 0 size.
- */
- private int restrictDismissingTaskPosition(int taskPosition, int dockSide,
- SnapTarget snapTarget) {
- if (snapTarget.flag == SnapTarget.FLAG_DISMISS_START && dockSideTopLeft(dockSide)) {
- return Math.max(mSplitLayout.getSnapAlgorithm().getFirstSplitTarget().position,
- mStartPosition);
- } else if (snapTarget.flag == SnapTarget.FLAG_DISMISS_END
- && dockSideBottomRight(dockSide)) {
- return Math.min(mSplitLayout.getSnapAlgorithm().getLastSplitTarget().position,
- mStartPosition);
- } else {
- return taskPosition;
- }
- }
-
- /**
- * Applies a parallax to the task when dismissing.
- */
- private void applyDismissingParallax(Rect taskRect, int dockSide, SnapTarget snapTarget,
- int position, int taskPosition) {
- float fraction = Math.min(1, Math.max(0,
- mSplitLayout.getSnapAlgorithm().calculateDismissingFraction(position)));
- SnapTarget dismissTarget = null;
- SnapTarget splitTarget = null;
- int start = 0;
- if (position <= mSplitLayout.getSnapAlgorithm().getLastSplitTarget().position
- && dockSideTopLeft(dockSide)) {
- dismissTarget = mSplitLayout.getSnapAlgorithm().getDismissStartTarget();
- splitTarget = mSplitLayout.getSnapAlgorithm().getFirstSplitTarget();
- start = taskPosition;
- } else if (position >= mSplitLayout.getSnapAlgorithm().getLastSplitTarget().position
- && dockSideBottomRight(dockSide)) {
- dismissTarget = mSplitLayout.getSnapAlgorithm().getDismissEndTarget();
- splitTarget = mSplitLayout.getSnapAlgorithm().getLastSplitTarget();
- start = splitTarget.position;
- }
- if (dismissTarget != null && fraction > 0f
- && isDismissing(splitTarget, position, dockSide)) {
- fraction = calculateParallaxDismissingFraction(fraction, dockSide);
- int offsetPosition = (int) (start + fraction
- * (dismissTarget.position - splitTarget.position));
- int width = taskRect.width();
- int height = taskRect.height();
- switch (dockSide) {
- case WindowManager.DOCKED_LEFT:
- taskRect.left = offsetPosition - width;
- taskRect.right = offsetPosition;
- break;
- case WindowManager.DOCKED_RIGHT:
- taskRect.left = offsetPosition + mDividerSize;
- taskRect.right = offsetPosition + width + mDividerSize;
- break;
- case WindowManager.DOCKED_TOP:
- taskRect.top = offsetPosition - height;
- taskRect.bottom = offsetPosition;
- break;
- case WindowManager.DOCKED_BOTTOM:
- taskRect.top = offsetPosition + mDividerSize;
- taskRect.bottom = offsetPosition + height + mDividerSize;
- break;
- }
- }
- }
-
- /**
- * @return for a specified {@code fraction}, this returns an adjusted value that simulates a
- * slowing down parallax effect
- */
- private static float calculateParallaxDismissingFraction(float fraction, int dockSide) {
- float result = SLOWDOWN_INTERPOLATOR.getInterpolation(fraction) / 3.5f;
-
- // Less parallax at the top, just because.
- if (dockSide == WindowManager.DOCKED_TOP) {
- result /= 2f;
- }
- return result;
- }
-
- private static boolean isDismissing(SnapTarget snapTarget, int position, int dockSide) {
- if (dockSide == WindowManager.DOCKED_TOP || dockSide == WindowManager.DOCKED_LEFT) {
- return position < snapTarget.position;
- } else {
- return position > snapTarget.position;
- }
- }
-
- private boolean isDismissTargetPrimary(SnapTarget dismissTarget) {
- return (dismissTarget.flag == SnapTarget.FLAG_DISMISS_START && dockSideTopLeft(mDockSide))
- || (dismissTarget.flag == SnapTarget.FLAG_DISMISS_END
- && dockSideBottomRight(mDockSide));
- }
-
- /**
- * @return true if and only if {@code dockSide} is top or left
- */
- private static boolean dockSideTopLeft(int dockSide) {
- return dockSide == WindowManager.DOCKED_TOP || dockSide == WindowManager.DOCKED_LEFT;
- }
-
- /**
- * @return true if and only if {@code dockSide} is bottom or right
- */
- private static boolean dockSideBottomRight(int dockSide) {
- return dockSide == WindowManager.DOCKED_BOTTOM || dockSide == WindowManager.DOCKED_RIGHT;
- }
-
- @Override
- public void onComputeInternalInsets(InternalInsetsInfo inoutInfo) {
- inoutInfo.setTouchableInsets(InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
- inoutInfo.touchableRegion.set(mHandle.getLeft(), mHandle.getTop(), mHandle.getRight(),
- mHandle.getBottom());
- inoutInfo.touchableRegion.op(mBackground.getLeft(), mBackground.getTop(),
- mBackground.getRight(), mBackground.getBottom(), Op.UNION);
- }
-
- void onUndockingTask() {
- int dockSide = mSplitLayout.getPrimarySplitSide();
- if (inSplitMode()) {
- startDragging(false /* animate */, false /* touching */);
- SnapTarget target = dockSideTopLeft(dockSide)
- ? mSplitLayout.getSnapAlgorithm().getDismissEndTarget()
- : mSplitLayout.getSnapAlgorithm().getDismissStartTarget();
-
- // Don't start immediately - give a little bit time to settle the drag resize change.
- mExitAnimationRunning = true;
- mExitStartPosition = getCurrentPosition();
- stopDragging(mExitStartPosition, target, 336 /* duration */, 100 /* startDelay */,
- 0 /* endDelay */, Interpolators.FAST_OUT_SLOW_IN);
- }
- }
-
- private int calculatePositionForInsetBounds() {
- mSplitLayout.mDisplayLayout.getStableBounds(mTmpRect);
- return DockedDividerUtils.calculatePositionForBounds(mTmpRect, mDockSide, mDividerSize);
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerWindowManager.java
deleted file mode 100644
index 2c3ae68..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerWindowManager.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.legacysplitscreen;
-
-import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
-import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
-import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
-import static android.view.WindowManager.LayoutParams.FLAG_SLIPPERY;
-import static android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
-import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
-import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
-import static android.view.WindowManager.SHELL_ROOT_LAYER_DIVIDER;
-
-import android.graphics.PixelFormat;
-import android.graphics.Region;
-import android.os.Binder;
-import android.view.View;
-import android.view.WindowManager;
-
-import com.android.wm.shell.common.SystemWindows;
-
-/**
- * Manages the window parameters of the docked stack divider.
- */
-final class DividerWindowManager {
-
- private static final String WINDOW_TITLE = "DockedStackDivider";
-
- final SystemWindows mSystemWindows;
- private WindowManager.LayoutParams mLp;
- private View mView;
-
- DividerWindowManager(SystemWindows systemWindows) {
- mSystemWindows = systemWindows;
- }
-
- /** Add a divider view */
- void add(View view, int width, int height, int displayId) {
- mLp = new WindowManager.LayoutParams(
- width, height, TYPE_DOCK_DIVIDER,
- FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCH_MODAL
- | FLAG_WATCH_OUTSIDE_TOUCH | FLAG_SPLIT_TOUCH | FLAG_SLIPPERY,
- PixelFormat.TRANSLUCENT);
- mLp.token = new Binder();
- mLp.setTitle(WINDOW_TITLE);
- mLp.privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION | PRIVATE_FLAG_TRUSTED_OVERLAY;
- mLp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
- view.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
- | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
- | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
- mSystemWindows.addView(view, mLp, displayId, SHELL_ROOT_LAYER_DIVIDER);
- mView = view;
- }
-
- void remove() {
- if (mView != null) {
- mSystemWindows.removeView(mView);
- }
- mView = null;
- }
-
- void setSlippery(boolean slippery) {
- boolean changed = false;
- if (slippery && (mLp.flags & FLAG_SLIPPERY) == 0) {
- mLp.flags |= FLAG_SLIPPERY;
- changed = true;
- } else if (!slippery && (mLp.flags & FLAG_SLIPPERY) != 0) {
- mLp.flags &= ~FLAG_SLIPPERY;
- changed = true;
- }
- if (changed) {
- mSystemWindows.updateViewLayout(mView, mLp);
- }
- }
-
- void setTouchable(boolean touchable) {
- if (mView == null) {
- return;
- }
- boolean changed = false;
- if (!touchable && (mLp.flags & FLAG_NOT_TOUCHABLE) == 0) {
- mLp.flags |= FLAG_NOT_TOUCHABLE;
- changed = true;
- } else if (touchable && (mLp.flags & FLAG_NOT_TOUCHABLE) != 0) {
- mLp.flags &= ~FLAG_NOT_TOUCHABLE;
- changed = true;
- }
- if (changed) {
- mSystemWindows.updateViewLayout(mView, mLp);
- }
- }
-
- /** Sets the touch region to `touchRegion`. Use null to unset.*/
- void setTouchRegion(Region touchRegion) {
- if (mView == null) {
- return;
- }
- mSystemWindows.setTouchableRegion(mView, touchRegion);
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/ForcedResizableInfoActivity.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/ForcedResizableInfoActivity.java
deleted file mode 100644
index 4fe28e6..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/ForcedResizableInfoActivity.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.legacysplitscreen;
-
-import static android.app.ITaskStackListener.FORCED_RESIZEABLE_REASON_SECONDARY_DISPLAY;
-import static android.app.ITaskStackListener.FORCED_RESIZEABLE_REASON_SPLIT_SCREEN;
-
-import android.annotation.Nullable;
-import android.app.Activity;
-import android.app.ActivityManager;
-import android.os.Bundle;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.View.OnTouchListener;
-import android.widget.TextView;
-
-import com.android.wm.shell.R;
-
-/**
- * Translucent activity that gets started on top of a task in multi-window to inform the user that
- * we forced the activity below to be resizable.
- *
- * Note: This activity runs on the main thread of the process hosting the Shell lib.
- */
-public class ForcedResizableInfoActivity extends Activity implements OnTouchListener {
-
- public static final String EXTRA_FORCED_RESIZEABLE_REASON = "extra_forced_resizeable_reason";
-
- private static final long DISMISS_DELAY = 2500;
-
- private final Runnable mFinishRunnable = new Runnable() {
- @Override
- public void run() {
- finish();
- }
- };
-
- @Override
- protected void onCreate(@Nullable Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.forced_resizable_activity);
- TextView tv = findViewById(com.android.internal.R.id.message);
- int reason = getIntent().getIntExtra(EXTRA_FORCED_RESIZEABLE_REASON, -1);
- String text;
- switch (reason) {
- case FORCED_RESIZEABLE_REASON_SPLIT_SCREEN:
- text = getString(R.string.dock_forced_resizable);
- break;
- case FORCED_RESIZEABLE_REASON_SECONDARY_DISPLAY:
- text = getString(R.string.forced_resizable_secondary_display);
- break;
- default:
- throw new IllegalArgumentException("Unexpected forced resizeable reason: "
- + reason);
- }
- tv.setText(text);
- getWindow().setTitle(text);
- getWindow().getDecorView().setOnTouchListener(this);
- }
-
- @Override
- protected void onStart() {
- super.onStart();
- getWindow().getDecorView().postDelayed(mFinishRunnable, DISMISS_DELAY);
- }
-
- @Override
- protected void onStop() {
- super.onStop();
- finish();
- }
-
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- finish();
- return true;
- }
-
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- finish();
- return true;
- }
-
- @Override
- public void finish() {
- super.finish();
- overridePendingTransition(0, R.anim.forced_resizable_exit);
- }
-
- @Override
- public void setTaskDescription(ActivityManager.TaskDescription taskDescription) {
- // Do nothing
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/ForcedResizableInfoActivityController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/ForcedResizableInfoActivityController.java
deleted file mode 100644
index 139544f9..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/ForcedResizableInfoActivityController.java
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.legacysplitscreen;
-
-
-import static com.android.wm.shell.legacysplitscreen.ForcedResizableInfoActivity.EXTRA_FORCED_RESIZEABLE_REASON;
-
-import android.app.ActivityOptions;
-import android.content.Context;
-import android.content.Intent;
-import android.os.UserHandle;
-import android.util.ArraySet;
-import android.widget.Toast;
-
-import com.android.wm.shell.R;
-import com.android.wm.shell.common.ShellExecutor;
-
-import java.util.function.Consumer;
-
-/**
- * Controller that decides when to show the {@link ForcedResizableInfoActivity}.
- */
-final class ForcedResizableInfoActivityController implements DividerView.DividerCallbacks {
-
- private static final String SELF_PACKAGE_NAME = "com.android.systemui";
-
- private static final int TIMEOUT = 1000;
- private final Context mContext;
- private final ShellExecutor mMainExecutor;
- private final ArraySet<PendingTaskRecord> mPendingTasks = new ArraySet<>();
- private final ArraySet<String> mPackagesShownInSession = new ArraySet<>();
- private boolean mDividerDragging;
-
- private final Runnable mTimeoutRunnable = this::showPending;
-
- private final Consumer<Boolean> mDockedStackExistsListener = exists -> {
- if (!exists) {
- mPackagesShownInSession.clear();
- }
- };
-
- /** Record of force resized task that's pending to be handled. */
- private class PendingTaskRecord {
- int mTaskId;
- /**
- * {@link android.app.ITaskStackListener#FORCED_RESIZEABLE_REASON_SPLIT_SCREEN} or
- * {@link android.app.ITaskStackListener#FORCED_RESIZEABLE_REASON_SECONDARY_DISPLAY}
- */
- int mReason;
-
- PendingTaskRecord(int taskId, int reason) {
- this.mTaskId = taskId;
- this.mReason = reason;
- }
- }
-
- ForcedResizableInfoActivityController(Context context,
- LegacySplitScreenController splitScreenController,
- ShellExecutor mainExecutor) {
- mContext = context;
- mMainExecutor = mainExecutor;
- splitScreenController.registerInSplitScreenListener(mDockedStackExistsListener);
- }
-
- @Override
- public void onDraggingStart() {
- mDividerDragging = true;
- mMainExecutor.removeCallbacks(mTimeoutRunnable);
- }
-
- @Override
- public void onDraggingEnd() {
- mDividerDragging = false;
- showPending();
- }
-
- void onAppTransitionFinished() {
- if (!mDividerDragging) {
- showPending();
- }
- }
-
- void activityForcedResizable(String packageName, int taskId, int reason) {
- if (debounce(packageName)) {
- return;
- }
- mPendingTasks.add(new PendingTaskRecord(taskId, reason));
- postTimeout();
- }
-
- void activityDismissingSplitScreen() {
- Toast.makeText(mContext, R.string.dock_non_resizeble_failed_to_dock_text,
- Toast.LENGTH_SHORT).show();
- }
-
- void activityLaunchOnSecondaryDisplayFailed() {
- Toast.makeText(mContext, R.string.activity_launch_on_secondary_display_failed_text,
- Toast.LENGTH_SHORT).show();
- }
-
- private void showPending() {
- mMainExecutor.removeCallbacks(mTimeoutRunnable);
- for (int i = mPendingTasks.size() - 1; i >= 0; i--) {
- PendingTaskRecord pendingRecord = mPendingTasks.valueAt(i);
- Intent intent = new Intent(mContext, ForcedResizableInfoActivity.class);
- ActivityOptions options = ActivityOptions.makeBasic();
- options.setLaunchTaskId(pendingRecord.mTaskId);
- // Set as task overlay and allow to resume, so that when an app enters split-screen and
- // becomes paused, the overlay will still be shown.
- options.setTaskOverlay(true, true /* canResume */);
- intent.putExtra(EXTRA_FORCED_RESIZEABLE_REASON, pendingRecord.mReason);
- mContext.startActivityAsUser(intent, options.toBundle(), UserHandle.CURRENT);
- }
- mPendingTasks.clear();
- }
-
- private void postTimeout() {
- mMainExecutor.removeCallbacks(mTimeoutRunnable);
- mMainExecutor.executeDelayed(mTimeoutRunnable, TIMEOUT);
- }
-
- private boolean debounce(String packageName) {
- if (packageName == null) {
- return false;
- }
-
- // We launch ForcedResizableInfoActivity into a task that was forced resizable, so that
- // triggers another notification. So ignore our own activity.
- if (SELF_PACKAGE_NAME.equals(packageName)) {
- return true;
- }
- boolean debounce = mPackagesShownInSession.contains(packageName);
- mPackagesShownInSession.add(packageName);
- return debounce;
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitDisplayLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitDisplayLayout.java
deleted file mode 100644
index f201634..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitDisplayLayout.java
+++ /dev/null
@@ -1,326 +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.wm.shell.legacysplitscreen;
-
-import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
-import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
-import static android.util.RotationUtils.rotateBounds;
-import static android.view.WindowManager.DOCKED_BOTTOM;
-import static android.view.WindowManager.DOCKED_INVALID;
-import static android.view.WindowManager.DOCKED_LEFT;
-import static android.view.WindowManager.DOCKED_RIGHT;
-import static android.view.WindowManager.DOCKED_TOP;
-
-import android.annotation.NonNull;
-import android.content.Context;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.graphics.Rect;
-import android.util.TypedValue;
-import android.window.WindowContainerTransaction;
-
-import com.android.internal.policy.DividerSnapAlgorithm;
-import com.android.internal.policy.DockedDividerUtils;
-import com.android.wm.shell.common.DisplayLayout;
-
-/**
- * Handles split-screen related internal display layout. In general, this represents the
- * WM-facing understanding of the splits.
- */
-public class LegacySplitDisplayLayout {
- /** Minimum size of an adjusted stack bounds relative to original stack bounds. Used to
- * restrict IME adjustment so that a min portion of top stack remains visible.*/
- private static final float ADJUSTED_STACK_FRACTION_MIN = 0.3f;
-
- private static final int DIVIDER_WIDTH_INACTIVE_DP = 4;
-
- LegacySplitScreenTaskListener mTiles;
- DisplayLayout mDisplayLayout;
- Context mContext;
-
- // Lazy stuff
- boolean mResourcesValid = false;
- int mDividerSize;
- int mDividerSizeInactive;
- private DividerSnapAlgorithm mSnapAlgorithm = null;
- private DividerSnapAlgorithm mMinimizedSnapAlgorithm = null;
- Rect mPrimary = null;
- Rect mSecondary = null;
- Rect mAdjustedPrimary = null;
- Rect mAdjustedSecondary = null;
- final Rect mTmpBounds = new Rect();
-
- public LegacySplitDisplayLayout(Context ctx, DisplayLayout dl,
- LegacySplitScreenTaskListener taskTiles) {
- mTiles = taskTiles;
- mDisplayLayout = dl;
- mContext = ctx;
- }
-
- void rotateTo(int newRotation) {
- mDisplayLayout.rotateTo(mContext.getResources(), newRotation);
- final Configuration config = new Configuration();
- config.unset();
- config.orientation = mDisplayLayout.getOrientation();
- Rect tmpRect = new Rect(0, 0, mDisplayLayout.width(), mDisplayLayout.height());
- tmpRect.inset(mDisplayLayout.nonDecorInsets());
- config.windowConfiguration.setAppBounds(tmpRect);
- tmpRect.set(0, 0, mDisplayLayout.width(), mDisplayLayout.height());
- tmpRect.inset(mDisplayLayout.stableInsets());
- config.screenWidthDp = (int) (tmpRect.width() / mDisplayLayout.density());
- config.screenHeightDp = (int) (tmpRect.height() / mDisplayLayout.density());
- mContext = mContext.createConfigurationContext(config);
- mSnapAlgorithm = null;
- mMinimizedSnapAlgorithm = null;
- mResourcesValid = false;
- }
-
- private void updateResources() {
- if (mResourcesValid) {
- return;
- }
- mResourcesValid = true;
- Resources res = mContext.getResources();
- mDividerSize = DockedDividerUtils.getDividerSize(res,
- DockedDividerUtils.getDividerInsets(res));
- mDividerSizeInactive = (int) TypedValue.applyDimension(
- TypedValue.COMPLEX_UNIT_DIP, DIVIDER_WIDTH_INACTIVE_DP, res.getDisplayMetrics());
- }
-
- int getPrimarySplitSide() {
- switch (mDisplayLayout.getNavigationBarPosition(mContext.getResources())) {
- case DisplayLayout.NAV_BAR_BOTTOM:
- return mDisplayLayout.isLandscape() ? DOCKED_LEFT : DOCKED_TOP;
- case DisplayLayout.NAV_BAR_LEFT:
- return DOCKED_RIGHT;
- case DisplayLayout.NAV_BAR_RIGHT:
- return DOCKED_LEFT;
- default:
- return DOCKED_INVALID;
- }
- }
-
- DividerSnapAlgorithm getSnapAlgorithm() {
- if (mSnapAlgorithm == null) {
- updateResources();
- boolean isHorizontalDivision = !mDisplayLayout.isLandscape();
- mSnapAlgorithm = new DividerSnapAlgorithm(mContext.getResources(),
- mDisplayLayout.width(), mDisplayLayout.height(), mDividerSize,
- isHorizontalDivision, mDisplayLayout.stableInsets(), getPrimarySplitSide());
- }
- return mSnapAlgorithm;
- }
-
- DividerSnapAlgorithm getMinimizedSnapAlgorithm(boolean homeStackResizable) {
- if (mMinimizedSnapAlgorithm == null) {
- updateResources();
- boolean isHorizontalDivision = !mDisplayLayout.isLandscape();
- mMinimizedSnapAlgorithm = new DividerSnapAlgorithm(mContext.getResources(),
- mDisplayLayout.width(), mDisplayLayout.height(), mDividerSize,
- isHorizontalDivision, mDisplayLayout.stableInsets(), getPrimarySplitSide(),
- true /* isMinimized */, homeStackResizable);
- }
- return mMinimizedSnapAlgorithm;
- }
-
- /**
- * Resize primary bounds and secondary bounds by divider position.
- *
- * @param position divider position.
- * @return true if calculated bounds changed.
- */
- boolean resizeSplits(int position) {
- mPrimary = mPrimary == null ? new Rect() : mPrimary;
- mSecondary = mSecondary == null ? new Rect() : mSecondary;
- int dockSide = getPrimarySplitSide();
- boolean boundsChanged;
-
- mTmpBounds.set(mPrimary);
- DockedDividerUtils.calculateBoundsForPosition(position, dockSide, mPrimary,
- mDisplayLayout.width(), mDisplayLayout.height(), mDividerSize);
- boundsChanged = !mPrimary.equals(mTmpBounds);
-
- mTmpBounds.set(mSecondary);
- DockedDividerUtils.calculateBoundsForPosition(position,
- DockedDividerUtils.invertDockSide(dockSide), mSecondary, mDisplayLayout.width(),
- mDisplayLayout.height(), mDividerSize);
- boundsChanged |= !mSecondary.equals(mTmpBounds);
- return boundsChanged;
- }
-
- void resizeSplits(int position, WindowContainerTransaction t) {
- if (resizeSplits(position)) {
- t.setBounds(mTiles.mPrimary.token, mPrimary);
- t.setBounds(mTiles.mSecondary.token, mSecondary);
-
- t.setSmallestScreenWidthDp(mTiles.mPrimary.token,
- getSmallestWidthDpForBounds(mContext, mDisplayLayout, mPrimary));
- t.setSmallestScreenWidthDp(mTiles.mSecondary.token,
- getSmallestWidthDpForBounds(mContext, mDisplayLayout, mSecondary));
- }
- }
-
- Rect calcResizableMinimizedHomeStackBounds() {
- DividerSnapAlgorithm.SnapTarget miniMid =
- getMinimizedSnapAlgorithm(true /* resizable */).getMiddleTarget();
- Rect homeBounds = new Rect();
- DockedDividerUtils.calculateBoundsForPosition(miniMid.position,
- DockedDividerUtils.invertDockSide(getPrimarySplitSide()), homeBounds,
- mDisplayLayout.width(), mDisplayLayout.height(), mDividerSize);
- return homeBounds;
- }
-
- /**
- * Updates the adjustment depending on it's current state.
- */
- void updateAdjustedBounds(int currImeTop, int hiddenTop, int shownTop) {
- adjustForIME(mDisplayLayout, currImeTop, hiddenTop, shownTop, mDividerSize,
- mDividerSizeInactive, mPrimary, mSecondary);
- }
-
- /** Assumes top/bottom split. Splits are not adjusted for left/right splits. */
- private void adjustForIME(DisplayLayout dl, int currImeTop, int hiddenTop, int shownTop,
- int dividerWidth, int dividerWidthInactive, Rect primaryBounds, Rect secondaryBounds) {
- if (mAdjustedPrimary == null) {
- mAdjustedPrimary = new Rect();
- mAdjustedSecondary = new Rect();
- }
-
- final Rect displayStableRect = new Rect();
- dl.getStableBounds(displayStableRect);
-
- final float shownFraction = ((float) (currImeTop - hiddenTop)) / (shownTop - hiddenTop);
- final int currDividerWidth =
- (int) (dividerWidthInactive * shownFraction + dividerWidth * (1.f - shownFraction));
-
- // Calculate the highest we can move the bottom of the top stack to keep 30% visible.
- final int minTopStackBottom = displayStableRect.top
- + (int) ((mPrimary.bottom - displayStableRect.top) * ADJUSTED_STACK_FRACTION_MIN);
- // Based on that, calculate the maximum amount we'll allow the ime to shift things.
- final int maxOffset = mPrimary.bottom - minTopStackBottom;
- // Calculate how much we would shift things without limits (basically the height of ime).
- final int desiredOffset = hiddenTop - shownTop;
- // Calculate an "adjustedTop" which is the currImeTop but restricted by our constraints.
- // We want an effect where the adjustment only occurs during the "highest" portion of the
- // ime animation. This is done by shifting the adjustment values by the difference in
- // offsets (effectively playing the whole adjustment animation some fixed amount of pixels
- // below the ime top).
- final int topCorrection = Math.max(0, desiredOffset - maxOffset);
- final int adjustedTop = currImeTop + topCorrection;
- // The actual yOffset is the distance between adjustedTop and the bottom of the display.
- // Since our adjustedTop values are playing "below" the ime, we clamp at 0 so we only
- // see adjustment upward.
- final int yOffset = Math.max(0, dl.height() - adjustedTop);
-
- // TOP
- // Reduce the offset by an additional small amount to squish the divider bar.
- mAdjustedPrimary.set(primaryBounds);
- mAdjustedPrimary.offset(0, -yOffset + (dividerWidth - currDividerWidth));
-
- // BOTTOM
- mAdjustedSecondary.set(secondaryBounds);
- mAdjustedSecondary.offset(0, -yOffset);
- }
-
- static int getSmallestWidthDpForBounds(@NonNull Context context, DisplayLayout dl,
- Rect bounds) {
- int dividerSize = DockedDividerUtils.getDividerSize(context.getResources(),
- DockedDividerUtils.getDividerInsets(context.getResources()));
-
- int minWidth = Integer.MAX_VALUE;
-
- // Go through all screen orientations and find the orientation in which the task has the
- // smallest width.
- Rect tmpRect = new Rect();
- Rect rotatedDisplayRect = new Rect();
- Rect displayRect = new Rect(0, 0, dl.width(), dl.height());
-
- DisplayLayout tmpDL = new DisplayLayout();
- for (int rotation = 0; rotation < 4; rotation++) {
- tmpDL.set(dl);
- tmpDL.rotateTo(context.getResources(), rotation);
- DividerSnapAlgorithm snap = initSnapAlgorithmForRotation(context, tmpDL, dividerSize);
-
- tmpRect.set(bounds);
- rotateBounds(tmpRect, displayRect, dl.rotation(), rotation);
- rotatedDisplayRect.set(0, 0, tmpDL.width(), tmpDL.height());
- final int dockSide = getPrimarySplitSide(tmpRect, rotatedDisplayRect,
- tmpDL.getOrientation());
- final int position = DockedDividerUtils.calculatePositionForBounds(tmpRect, dockSide,
- dividerSize);
-
- final int snappedPosition =
- snap.calculateNonDismissingSnapTarget(position).position;
- DockedDividerUtils.calculateBoundsForPosition(snappedPosition, dockSide, tmpRect,
- tmpDL.width(), tmpDL.height(), dividerSize);
- Rect insettedDisplay = new Rect(rotatedDisplayRect);
- insettedDisplay.inset(tmpDL.stableInsets());
- tmpRect.intersect(insettedDisplay);
- minWidth = Math.min(tmpRect.width(), minWidth);
- }
- return (int) (minWidth / dl.density());
- }
-
- static DividerSnapAlgorithm initSnapAlgorithmForRotation(Context context, DisplayLayout dl,
- int dividerSize) {
- final Configuration config = new Configuration();
- config.unset();
- config.orientation = dl.getOrientation();
- Rect tmpRect = new Rect(0, 0, dl.width(), dl.height());
- tmpRect.inset(dl.nonDecorInsets());
- config.windowConfiguration.setAppBounds(tmpRect);
- tmpRect.set(0, 0, dl.width(), dl.height());
- tmpRect.inset(dl.stableInsets());
- config.screenWidthDp = (int) (tmpRect.width() / dl.density());
- config.screenHeightDp = (int) (tmpRect.height() / dl.density());
- final Context rotationContext = context.createConfigurationContext(config);
- return new DividerSnapAlgorithm(
- rotationContext.getResources(), dl.width(), dl.height(), dividerSize,
- config.orientation == ORIENTATION_PORTRAIT, dl.stableInsets());
- }
-
- /**
- * Get the current primary-split side. Determined by its location of {@param bounds} within
- * {@param displayRect} but if both are the same, it will try to dock to each side and determine
- * if allowed in its respected {@param orientation}.
- *
- * @param bounds bounds of the primary split task to get which side is docked
- * @param displayRect bounds of the display that contains the primary split task
- * @param orientation the origination of device
- * @return current primary-split side
- */
- static int getPrimarySplitSide(Rect bounds, Rect displayRect, int orientation) {
- if (orientation == ORIENTATION_PORTRAIT) {
- // Portrait mode, docked either at the top or the bottom.
- final int diff = (displayRect.bottom - bounds.bottom) - (bounds.top - displayRect.top);
- if (diff < 0) {
- return DOCKED_BOTTOM;
- } else {
- // Top is default
- return DOCKED_TOP;
- }
- } else if (orientation == ORIENTATION_LANDSCAPE) {
- // Landscape mode, docked either on the left or on the right.
- final int diff = (displayRect.right - bounds.right) - (bounds.left - displayRect.left);
- if (diff < 0) {
- return DOCKED_RIGHT;
- }
- return DOCKED_LEFT;
- }
- return DOCKED_INVALID;
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreen.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreen.java
deleted file mode 100644
index 499a9c5..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreen.java
+++ /dev/null
@@ -1,85 +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.wm.shell.legacysplitscreen;
-
-import android.graphics.Rect;
-import android.window.WindowContainerToken;
-
-import com.android.wm.shell.common.annotations.ExternalThread;
-
-import java.io.PrintWriter;
-import java.util.function.BiConsumer;
-import java.util.function.Consumer;
-
-/**
- * Interface to engage split screen feature.
- */
-@ExternalThread
-public interface LegacySplitScreen {
- /** Called when keyguard showing state changed. */
- void onKeyguardVisibilityChanged(boolean isShowing);
-
- /** Returns {@link DividerView}. */
- DividerView getDividerView();
-
- /** Returns {@code true} if one of the split screen is in minimized mode. */
- boolean isMinimized();
-
- /** Returns {@code true} if the home stack is resizable. */
- boolean isHomeStackResizable();
-
- /** Returns {@code true} if the divider is visible. */
- boolean isDividerVisible();
-
- /** Switch to minimized state if appropriate. */
- void setMinimized(boolean minimized);
-
- /** Called when there's a task undocking. */
- void onUndockingTask();
-
- /** Called when app transition finished. */
- void onAppTransitionFinished();
-
- /** Dumps current status of Split Screen. */
- void dump(PrintWriter pw);
-
- /** Registers listener that gets called whenever the existence of the divider changes. */
- void registerInSplitScreenListener(Consumer<Boolean> listener);
-
- /** Unregisters listener that gets called whenever the existence of the divider changes. */
- void unregisterInSplitScreenListener(Consumer<Boolean> listener);
-
- /** Registers listener that gets called whenever the split screen bounds changes. */
- void registerBoundsChangeListener(BiConsumer<Rect, Rect> listener);
-
- /** @return the container token for the secondary split root task. */
- WindowContainerToken getSecondaryRoot();
-
- /**
- * Splits the primary task if feasible, this is to preserve legacy way to toggle split screen.
- * Like triggering split screen through long pressing recents app button or through
- * {@link android.accessibilityservice.AccessibilityService#GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN}.
- *
- * @return {@code true} if it successes to split the primary task.
- */
- boolean splitPrimaryTask();
-
- /**
- * Exits the split to make the primary task fullscreen.
- */
- void dismissSplitToPrimaryTask();
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenController.java
deleted file mode 100644
index 67e487d..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenController.java
+++ /dev/null
@@ -1,762 +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.wm.shell.legacysplitscreen;
-
-import static android.app.ActivityManager.LOCK_TASK_MODE_PINNED;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
-import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
-import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
-import static android.view.Display.DEFAULT_DISPLAY;
-
-import android.animation.AnimationHandler;
-import android.app.ActivityManager;
-import android.app.ActivityManager.RunningTaskInfo;
-import android.app.ActivityTaskManager;
-import android.content.Context;
-import android.content.res.Configuration;
-import android.graphics.Rect;
-import android.os.RemoteException;
-import android.provider.Settings;
-import android.util.Slog;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.Toast;
-import android.window.TaskOrganizer;
-import android.window.WindowContainerToken;
-import android.window.WindowContainerTransaction;
-
-import com.android.internal.policy.DividerSnapAlgorithm;
-import com.android.wm.shell.R;
-import com.android.wm.shell.ShellTaskOrganizer;
-import com.android.wm.shell.common.DisplayChangeController;
-import com.android.wm.shell.common.DisplayController;
-import com.android.wm.shell.common.DisplayImeController;
-import com.android.wm.shell.common.DisplayLayout;
-import com.android.wm.shell.common.ShellExecutor;
-import com.android.wm.shell.common.SyncTransactionQueue;
-import com.android.wm.shell.common.SystemWindows;
-import com.android.wm.shell.common.TaskStackListenerCallback;
-import com.android.wm.shell.common.TaskStackListenerImpl;
-import com.android.wm.shell.common.TransactionPool;
-import com.android.wm.shell.transition.Transitions;
-
-import java.io.PrintWriter;
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.function.BiConsumer;
-import java.util.function.Consumer;
-
-/**
- * Controls split screen feature.
- */
-public class LegacySplitScreenController implements DisplayController.OnDisplaysChangedListener {
- static final boolean DEBUG = false;
-
- private static final String TAG = "SplitScreenCtrl";
- private static final int DEFAULT_APP_TRANSITION_DURATION = 336;
-
- private final Context mContext;
- private final DisplayChangeController.OnDisplayChangingListener mRotationController;
- private final DisplayController mDisplayController;
- private final DisplayImeController mImeController;
- private final DividerImeController mImePositionProcessor;
- private final DividerState mDividerState = new DividerState();
- private final ForcedResizableInfoActivityController mForcedResizableController;
- private final ShellExecutor mMainExecutor;
- private final AnimationHandler mSfVsyncAnimationHandler;
- private final LegacySplitScreenTaskListener mSplits;
- private final SystemWindows mSystemWindows;
- final TransactionPool mTransactionPool;
- private final WindowManagerProxy mWindowManagerProxy;
- private final TaskOrganizer mTaskOrganizer;
- private final SplitScreenImpl mImpl = new SplitScreenImpl();
-
- private final CopyOnWriteArrayList<WeakReference<Consumer<Boolean>>> mDockedStackExistsListeners
- = new CopyOnWriteArrayList<>();
- private final ArrayList<WeakReference<BiConsumer<Rect, Rect>>> mBoundsChangedListeners =
- new ArrayList<>();
-
-
- private DividerWindowManager mWindowManager;
- private DividerView mView;
-
- // Keeps track of real-time split geometry including snap positions and ime adjustments
- private LegacySplitDisplayLayout mSplitLayout;
-
- // Transient: this contains the layout calculated for a new rotation requested by WM. This is
- // kept around so that we can wait for a matching configuration change and then use the exact
- // layout that we sent back to WM.
- private LegacySplitDisplayLayout mRotateSplitLayout;
-
- private boolean mIsKeyguardShowing;
- private boolean mVisible = false;
- private volatile boolean mMinimized = false;
- private volatile boolean mAdjustedForIme = false;
- private boolean mHomeStackResizable = false;
-
- public LegacySplitScreenController(Context context,
- DisplayController displayController, SystemWindows systemWindows,
- DisplayImeController imeController, TransactionPool transactionPool,
- ShellTaskOrganizer shellTaskOrganizer, SyncTransactionQueue syncQueue,
- TaskStackListenerImpl taskStackListener, Transitions transitions,
- ShellExecutor mainExecutor, AnimationHandler sfVsyncAnimationHandler) {
- mContext = context;
- mDisplayController = displayController;
- mSystemWindows = systemWindows;
- mImeController = imeController;
- mMainExecutor = mainExecutor;
- mSfVsyncAnimationHandler = sfVsyncAnimationHandler;
- mForcedResizableController = new ForcedResizableInfoActivityController(context, this,
- mainExecutor);
- mTransactionPool = transactionPool;
- mWindowManagerProxy = new WindowManagerProxy(syncQueue, shellTaskOrganizer);
- mTaskOrganizer = shellTaskOrganizer;
- mSplits = new LegacySplitScreenTaskListener(this, shellTaskOrganizer, transitions,
- syncQueue);
- mImePositionProcessor = new DividerImeController(mSplits, mTransactionPool, mMainExecutor,
- shellTaskOrganizer);
- mRotationController =
- (display, fromRotation, toRotation, wct) -> {
- if (!mSplits.isSplitScreenSupported() || mWindowManagerProxy == null) {
- return;
- }
- WindowContainerTransaction t = new WindowContainerTransaction();
- DisplayLayout displayLayout =
- new DisplayLayout(mDisplayController.getDisplayLayout(display));
- LegacySplitDisplayLayout sdl =
- new LegacySplitDisplayLayout(mContext, displayLayout, mSplits);
- sdl.rotateTo(toRotation);
- mRotateSplitLayout = sdl;
- // snap resets to middle target when not minimized and rotation changed.
- final int position = mMinimized ? mView.mSnapTargetBeforeMinimized.position
- : sdl.getSnapAlgorithm().getMiddleTarget().position;
- DividerSnapAlgorithm snap = sdl.getSnapAlgorithm();
- final DividerSnapAlgorithm.SnapTarget target =
- snap.calculateNonDismissingSnapTarget(position);
- sdl.resizeSplits(target.position, t);
-
- if (isSplitActive() && mHomeStackResizable) {
- mWindowManagerProxy
- .applyHomeTasksMinimized(sdl, mSplits.mSecondary.token, t);
- }
- if (mWindowManagerProxy.queueSyncTransactionIfWaiting(t)) {
- // Because sync transactions are serialized, its possible for an "older"
- // bounds-change to get applied after a screen rotation. In that case, we
- // want to actually defer on that rather than apply immediately. Of course,
- // this means that the bounds may not change until after the rotation so
- // the user might see some artifacts. This should be rare.
- Slog.w(TAG, "Screen rotated while other operations were pending, this may"
- + " result in some graphical artifacts.");
- } else {
- wct.merge(t, true /* transfer */);
- }
- };
-
- mWindowManager = new DividerWindowManager(mSystemWindows);
-
- // No need to listen to display window container or create root tasks if the device is not
- // using legacy split screen.
- if (!context.getResources().getBoolean(com.android.internal.R.bool.config_useLegacySplit)) {
- return;
- }
-
-
- mDisplayController.addDisplayWindowListener(this);
- // Don't initialize the divider or anything until we get the default display.
-
- taskStackListener.addListener(
- new TaskStackListenerCallback() {
- @Override
- public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
- boolean homeTaskVisible, boolean clearedTask, boolean wasVisible) {
- if (!wasVisible || task.getWindowingMode()
- != WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
- || !mSplits.isSplitScreenSupported()) {
- return;
- }
-
- if (isMinimized()) {
- onUndockingTask();
- }
- }
-
- @Override
- public void onActivityForcedResizable(String packageName, int taskId,
- int reason) {
- mForcedResizableController.activityForcedResizable(packageName, taskId,
- reason);
- }
-
- @Override
- public void onActivityDismissingDockedStack() {
- mForcedResizableController.activityDismissingSplitScreen();
- }
-
- @Override
- public void onActivityLaunchOnSecondaryDisplayFailed() {
- mForcedResizableController.activityLaunchOnSecondaryDisplayFailed();
- }
- });
- }
-
- public LegacySplitScreen asLegacySplitScreen() {
- return mImpl;
- }
-
- public void onSplitScreenSupported() {
- // Set starting tile bounds based on middle target
- final WindowContainerTransaction tct = new WindowContainerTransaction();
- int midPos = mSplitLayout.getSnapAlgorithm().getMiddleTarget().position;
- mSplitLayout.resizeSplits(midPos, tct);
- mTaskOrganizer.applyTransaction(tct);
- }
-
- public void onKeyguardVisibilityChanged(boolean showing) {
- if (!isSplitActive() || mView == null) {
- return;
- }
- mView.setHidden(showing);
- mIsKeyguardShowing = showing;
- }
-
- @Override
- public void onDisplayAdded(int displayId) {
- if (displayId != DEFAULT_DISPLAY) {
- return;
- }
- mSplitLayout = new LegacySplitDisplayLayout(mDisplayController.getDisplayContext(displayId),
- mDisplayController.getDisplayLayout(displayId), mSplits);
- mImeController.addPositionProcessor(mImePositionProcessor);
- mDisplayController.addDisplayChangingController(mRotationController);
- if (!ActivityTaskManager.supportsSplitScreenMultiWindow(mContext)) {
- removeDivider();
- return;
- }
- try {
- mSplits.init();
- } catch (Exception e) {
- Slog.e(TAG, "Failed to register docked stack listener", e);
- removeDivider();
- return;
- }
- }
-
- @Override
- public void onDisplayConfigurationChanged(int displayId, Configuration newConfig) {
- if (displayId != DEFAULT_DISPLAY || !mSplits.isSplitScreenSupported()) {
- return;
- }
- mSplitLayout = new LegacySplitDisplayLayout(mDisplayController.getDisplayContext(displayId),
- mDisplayController.getDisplayLayout(displayId), mSplits);
- if (mRotateSplitLayout == null) {
- int midPos = mSplitLayout.getSnapAlgorithm().getMiddleTarget().position;
- final WindowContainerTransaction tct = new WindowContainerTransaction();
- mSplitLayout.resizeSplits(midPos, tct);
- mTaskOrganizer.applyTransaction(tct);
- } else if (mSplitLayout.mDisplayLayout.rotation()
- == mRotateSplitLayout.mDisplayLayout.rotation()) {
- mSplitLayout.mPrimary = new Rect(mRotateSplitLayout.mPrimary);
- mSplitLayout.mSecondary = new Rect(mRotateSplitLayout.mSecondary);
- mRotateSplitLayout = null;
- }
- if (isSplitActive()) {
- update(newConfig);
- }
- }
-
- public boolean isMinimized() {
- return mMinimized;
- }
-
- public boolean isHomeStackResizable() {
- return mHomeStackResizable;
- }
-
- public DividerView getDividerView() {
- return mView;
- }
-
- public boolean isDividerVisible() {
- return mView != null && mView.getVisibility() == View.VISIBLE;
- }
-
- /**
- * This indicates that at-least one of the splits has content. This differs from
- * isDividerVisible because the divider is only visible once *everything* is in split mode
- * while this only cares if some things are (eg. while entering/exiting as well).
- */
- public boolean isSplitActive() {
- return mSplits.mPrimary != null && mSplits.mSecondary != null
- && (mSplits.mPrimary.topActivityType != ACTIVITY_TYPE_UNDEFINED
- || mSplits.mSecondary.topActivityType != ACTIVITY_TYPE_UNDEFINED);
- }
-
- public void addDivider(Configuration configuration) {
- Context dctx = mDisplayController.getDisplayContext(mContext.getDisplayId());
- mView = (DividerView)
- LayoutInflater.from(dctx).inflate(R.layout.docked_stack_divider, null);
- mView.setAnimationHandler(mSfVsyncAnimationHandler);
- DisplayLayout displayLayout = mDisplayController.getDisplayLayout(mContext.getDisplayId());
- mView.injectDependencies(this, mWindowManager, mDividerState, mForcedResizableController,
- mSplits, mSplitLayout, mImePositionProcessor, mWindowManagerProxy);
- mView.setVisibility(mVisible ? View.VISIBLE : View.INVISIBLE);
- mView.setMinimizedDockStack(mMinimized, mHomeStackResizable, null /* transaction */);
- final int size = dctx.getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.docked_stack_divider_thickness);
- final boolean landscape = configuration.orientation == ORIENTATION_LANDSCAPE;
- final int width = landscape ? size : displayLayout.width();
- final int height = landscape ? displayLayout.height() : size;
- mWindowManager.add(mView, width, height, mContext.getDisplayId());
- }
-
- public void removeDivider() {
- if (mView != null) {
- mView.onDividerRemoved();
- }
- mWindowManager.remove();
- }
-
- public void update(Configuration configuration) {
- final boolean isDividerHidden = mView != null && mIsKeyguardShowing;
-
- removeDivider();
- addDivider(configuration);
-
- if (mMinimized) {
- mView.setMinimizedDockStack(true, mHomeStackResizable, null /* transaction */);
- updateTouchable();
- }
- mView.setHidden(isDividerHidden);
- }
-
- public void onTaskVanished() {
- removeDivider();
- }
-
- public void updateVisibility(final boolean visible) {
- if (DEBUG) Slog.d(TAG, "Updating visibility " + mVisible + "->" + visible);
- if (mVisible != visible) {
- mVisible = visible;
- mView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
-
- if (visible) {
- mView.enterSplitMode(mHomeStackResizable);
- // Update state because animations won't finish.
- mWindowManagerProxy.runInSync(
- t -> mView.setMinimizedDockStack(mMinimized, mHomeStackResizable, t));
-
- } else {
- mView.exitSplitMode();
- mWindowManagerProxy.runInSync(
- t -> mView.setMinimizedDockStack(false, mHomeStackResizable, t));
- }
- // Notify existence listeners
- synchronized (mDockedStackExistsListeners) {
- mDockedStackExistsListeners.removeIf(wf -> {
- Consumer<Boolean> l = wf.get();
- if (l != null) l.accept(visible);
- return l == null;
- });
- }
- }
- }
-
- public void setMinimized(final boolean minimized) {
- if (DEBUG) Slog.d(TAG, "posting ext setMinimized " + minimized + " vis:" + mVisible);
- mMainExecutor.execute(() -> {
- if (DEBUG) Slog.d(TAG, "run posted ext setMinimized " + minimized + " vis:" + mVisible);
- if (!mVisible) {
- return;
- }
- setHomeMinimized(minimized);
- });
- }
-
- public void setHomeMinimized(final boolean minimized) {
- if (DEBUG) {
- Slog.d(TAG, "setHomeMinimized min:" + mMinimized + "->" + minimized + " hrsz:"
- + mHomeStackResizable + " split:" + isDividerVisible());
- }
- WindowContainerTransaction wct = new WindowContainerTransaction();
- final boolean minimizedChanged = mMinimized != minimized;
- // Update minimized state
- if (minimizedChanged) {
- mMinimized = minimized;
- }
- // Always set this because we could be entering split when mMinimized is already true
- wct.setFocusable(mSplits.mPrimary.token, !mMinimized);
-
- // Sync state to DividerView if it exists.
- if (mView != null) {
- final int displayId = mView.getDisplay() != null
- ? mView.getDisplay().getDisplayId() : DEFAULT_DISPLAY;
- // pause ime here (before updateMinimizedDockedStack)
- if (mMinimized) {
- mImePositionProcessor.pause(displayId);
- }
- if (minimizedChanged) {
- // This conflicts with IME adjustment, so only call it when things change.
- mView.setMinimizedDockStack(minimized, getAnimDuration(), mHomeStackResizable);
- }
- if (!mMinimized) {
- // afterwards so it can end any animations started in view
- mImePositionProcessor.resume(displayId);
- }
- }
- updateTouchable();
-
- // If we are only setting focusability, a sync transaction isn't necessary (in fact it
- // can interrupt other animations), so see if it can be submitted on pending instead.
- if (!mWindowManagerProxy.queueSyncTransactionIfWaiting(wct)) {
- mTaskOrganizer.applyTransaction(wct);
- }
- }
-
- public void setAdjustedForIme(boolean adjustedForIme) {
- if (mAdjustedForIme == adjustedForIme) {
- return;
- }
- mAdjustedForIme = adjustedForIme;
- updateTouchable();
- }
-
- public void updateTouchable() {
- mWindowManager.setTouchable(!mAdjustedForIme);
- }
-
- public void onUndockingTask() {
- if (mView != null) {
- mView.onUndockingTask();
- }
- }
-
- public void onAppTransitionFinished() {
- if (mView == null) {
- return;
- }
- mForcedResizableController.onAppTransitionFinished();
- }
-
- public void dump(PrintWriter pw) {
- pw.print(" mVisible="); pw.println(mVisible);
- pw.print(" mMinimized="); pw.println(mMinimized);
- pw.print(" mAdjustedForIme="); pw.println(mAdjustedForIme);
- }
-
- public long getAnimDuration() {
- float transitionScale = Settings.Global.getFloat(mContext.getContentResolver(),
- Settings.Global.TRANSITION_ANIMATION_SCALE,
- mContext.getResources().getFloat(
- com.android.internal.R.dimen
- .config_appTransitionAnimationDurationScaleDefault));
- final long transitionDuration = DEFAULT_APP_TRANSITION_DURATION;
- return (long) (transitionDuration * transitionScale);
- }
-
- public void registerInSplitScreenListener(Consumer<Boolean> listener) {
- listener.accept(isDividerVisible());
- synchronized (mDockedStackExistsListeners) {
- mDockedStackExistsListeners.add(new WeakReference<>(listener));
- }
- }
-
- public void unregisterInSplitScreenListener(Consumer<Boolean> listener) {
- synchronized (mDockedStackExistsListeners) {
- for (int i = mDockedStackExistsListeners.size() - 1; i >= 0; i--) {
- if (mDockedStackExistsListeners.get(i) == listener) {
- mDockedStackExistsListeners.remove(i);
- }
- }
- }
- }
-
- public void registerBoundsChangeListener(BiConsumer<Rect, Rect> listener) {
- synchronized (mBoundsChangedListeners) {
- mBoundsChangedListeners.add(new WeakReference<>(listener));
- }
- }
-
- public boolean splitPrimaryTask() {
- try {
- if (ActivityTaskManager.getService().getLockTaskModeState() == LOCK_TASK_MODE_PINNED) {
- return false;
- }
- } catch (RemoteException e) {
- return false;
- }
- if (isSplitActive() || mSplits.mPrimary == null) {
- return false;
- }
-
- // Try fetching the top running task.
- final List<RunningTaskInfo> runningTasks =
- ActivityTaskManager.getInstance().getTasks(1 /* maxNum */);
- if (runningTasks == null || runningTasks.isEmpty()) {
- return false;
- }
- // Note: The set of running tasks from the system is ordered by recency.
- final RunningTaskInfo topRunningTask = runningTasks.get(0);
- final int activityType = topRunningTask.getActivityType();
- if (activityType == ACTIVITY_TYPE_HOME || activityType == ACTIVITY_TYPE_RECENTS) {
- return false;
- }
-
- if (!topRunningTask.supportsSplitScreenMultiWindow) {
- Toast.makeText(mContext, R.string.dock_non_resizeble_failed_to_dock_text,
- Toast.LENGTH_SHORT).show();
- return false;
- }
-
- final WindowContainerTransaction wct = new WindowContainerTransaction();
- // Clear out current windowing mode before reparenting to split task.
- wct.setWindowingMode(topRunningTask.token, WINDOWING_MODE_UNDEFINED);
- wct.reparent(topRunningTask.token, mSplits.mPrimary.token, true /* onTop */);
- mWindowManagerProxy.applySyncTransaction(wct);
- return true;
- }
-
- public void dismissSplitToPrimaryTask() {
- startDismissSplit(true /* toPrimaryTask */);
- }
-
- /** Notifies the bounds of split screen changed. */
- public void notifyBoundsChanged(Rect secondaryWindowBounds, Rect secondaryWindowInsets) {
- synchronized (mBoundsChangedListeners) {
- mBoundsChangedListeners.removeIf(wf -> {
- BiConsumer<Rect, Rect> l = wf.get();
- if (l != null) l.accept(secondaryWindowBounds, secondaryWindowInsets);
- return l == null;
- });
- }
- }
-
- public void startEnterSplit() {
- update(mDisplayController.getDisplayContext(
- mContext.getDisplayId()).getResources().getConfiguration());
- // Set resizable directly here because applyEnterSplit already resizes home stack.
- mHomeStackResizable = mWindowManagerProxy.applyEnterSplit(mSplits,
- mRotateSplitLayout != null ? mRotateSplitLayout : mSplitLayout);
- }
-
- public void prepareEnterSplitTransition(WindowContainerTransaction outWct) {
- // Set resizable directly here because buildEnterSplit already resizes home stack.
- mHomeStackResizable = mWindowManagerProxy.buildEnterSplit(outWct, mSplits,
- mRotateSplitLayout != null ? mRotateSplitLayout : mSplitLayout);
- }
-
- public void finishEnterSplitTransition(boolean minimized) {
- update(mDisplayController.getDisplayContext(
- mContext.getDisplayId()).getResources().getConfiguration());
- if (minimized) {
- ensureMinimizedSplit();
- } else {
- ensureNormalSplit();
- }
- }
-
- public void startDismissSplit(boolean toPrimaryTask) {
- startDismissSplit(toPrimaryTask, false /* snapped */);
- }
-
- public void startDismissSplit(boolean toPrimaryTask, boolean snapped) {
- if (Transitions.ENABLE_SHELL_TRANSITIONS) {
- mSplits.getSplitTransitions().dismissSplit(
- mSplits, mSplitLayout, !toPrimaryTask, snapped);
- } else {
- mWindowManagerProxy.applyDismissSplit(mSplits, mSplitLayout, !toPrimaryTask);
- onDismissSplit();
- }
- }
-
- public void onDismissSplit() {
- updateVisibility(false /* visible */);
- mMinimized = false;
- // Resets divider bar position to undefined, so new divider bar will apply default position
- // next time entering split mode.
- mDividerState.mRatioPositionBeforeMinimized = 0;
- removeDivider();
- mImePositionProcessor.reset();
- }
-
- public void ensureMinimizedSplit() {
- setHomeMinimized(true /* minimized */);
- if (mView != null && !isDividerVisible()) {
- // Wasn't in split-mode yet, so enter now.
- if (DEBUG) {
- Slog.d(TAG, " entering split mode with minimized=true");
- }
- updateVisibility(true /* visible */);
- }
- }
-
- public void ensureNormalSplit() {
- setHomeMinimized(false /* minimized */);
- if (mView != null && !isDividerVisible()) {
- // Wasn't in split-mode, so enter now.
- if (DEBUG) {
- Slog.d(TAG, " enter split mode unminimized ");
- }
- updateVisibility(true /* visible */);
- }
- }
-
- public LegacySplitDisplayLayout getSplitLayout() {
- return mSplitLayout;
- }
-
- public WindowManagerProxy getWmProxy() {
- return mWindowManagerProxy;
- }
-
- public WindowContainerToken getSecondaryRoot() {
- if (mSplits == null || mSplits.mSecondary == null) {
- return null;
- }
- return mSplits.mSecondary.token;
- }
-
- private class SplitScreenImpl implements LegacySplitScreen {
- @Override
- public boolean isMinimized() {
- return mMinimized;
- }
-
- @Override
- public boolean isHomeStackResizable() {
- return mHomeStackResizable;
- }
-
- /**
- * TODO: Remove usage from outside the shell.
- */
- @Override
- public DividerView getDividerView() {
- return LegacySplitScreenController.this.getDividerView();
- }
-
- @Override
- public boolean isDividerVisible() {
- boolean[] result = new boolean[1];
- try {
- mMainExecutor.executeBlocking(() -> {
- result[0] = LegacySplitScreenController.this.isDividerVisible();
- });
- } catch (InterruptedException e) {
- Slog.e(TAG, "Failed to get divider visible");
- }
- return result[0];
- }
-
- @Override
- public void onKeyguardVisibilityChanged(boolean isShowing) {
- mMainExecutor.execute(() -> {
- LegacySplitScreenController.this.onKeyguardVisibilityChanged(isShowing);
- });
- }
-
- @Override
- public void setMinimized(boolean minimized) {
- mMainExecutor.execute(() -> {
- LegacySplitScreenController.this.setMinimized(minimized);
- });
- }
-
- @Override
- public void onUndockingTask() {
- mMainExecutor.execute(() -> {
- LegacySplitScreenController.this.onUndockingTask();
- });
- }
-
- @Override
- public void onAppTransitionFinished() {
- mMainExecutor.execute(() -> {
- LegacySplitScreenController.this.onAppTransitionFinished();
- });
- }
-
- @Override
- public void registerInSplitScreenListener(Consumer<Boolean> listener) {
- mMainExecutor.execute(() -> {
- LegacySplitScreenController.this.registerInSplitScreenListener(listener);
- });
- }
-
- @Override
- public void unregisterInSplitScreenListener(Consumer<Boolean> listener) {
- mMainExecutor.execute(() -> {
- LegacySplitScreenController.this.unregisterInSplitScreenListener(listener);
- });
- }
-
- @Override
- public void registerBoundsChangeListener(BiConsumer<Rect, Rect> listener) {
- mMainExecutor.execute(() -> {
- LegacySplitScreenController.this.registerBoundsChangeListener(listener);
- });
- }
-
- @Override
- public WindowContainerToken getSecondaryRoot() {
- WindowContainerToken[] result = new WindowContainerToken[1];
- try {
- mMainExecutor.executeBlocking(() -> {
- result[0] = LegacySplitScreenController.this.getSecondaryRoot();
- });
- } catch (InterruptedException e) {
- Slog.e(TAG, "Failed to get secondary root");
- }
- return result[0];
- }
-
- @Override
- public boolean splitPrimaryTask() {
- boolean[] result = new boolean[1];
- try {
- mMainExecutor.executeBlocking(() -> {
- result[0] = LegacySplitScreenController.this.splitPrimaryTask();
- });
- } catch (InterruptedException e) {
- Slog.e(TAG, "Failed to split primary task");
- }
- return result[0];
- }
-
- @Override
- public void dismissSplitToPrimaryTask() {
- mMainExecutor.execute(() -> {
- LegacySplitScreenController.this.dismissSplitToPrimaryTask();
- });
- }
-
- @Override
- public void dump(PrintWriter pw) {
- try {
- mMainExecutor.executeBlocking(() -> {
- LegacySplitScreenController.this.dump(pw);
- });
- } catch (InterruptedException e) {
- Slog.e(TAG, "Failed to dump LegacySplitScreenController in 2s");
- }
- }
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenTaskListener.java
deleted file mode 100644
index d2f42c3..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenTaskListener.java
+++ /dev/null
@@ -1,376 +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.wm.shell.legacysplitscreen;
-
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
-import static android.view.Display.DEFAULT_DISPLAY;
-
-import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_TASK_ORG;
-
-import android.app.ActivityManager.RunningTaskInfo;
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.util.Log;
-import android.util.SparseArray;
-import android.view.SurfaceControl;
-import android.view.SurfaceSession;
-import android.window.TaskOrganizer;
-
-import androidx.annotation.NonNull;
-
-import com.android.internal.protolog.common.ProtoLog;
-import com.android.wm.shell.ShellTaskOrganizer;
-import com.android.wm.shell.common.SurfaceUtils;
-import com.android.wm.shell.common.SyncTransactionQueue;
-import com.android.wm.shell.transition.Transitions;
-
-import java.io.PrintWriter;
-import java.util.ArrayList;
-
-class LegacySplitScreenTaskListener implements ShellTaskOrganizer.TaskListener {
- private static final String TAG = LegacySplitScreenTaskListener.class.getSimpleName();
- private static final boolean DEBUG = LegacySplitScreenController.DEBUG;
-
- private final ShellTaskOrganizer mTaskOrganizer;
- private final SyncTransactionQueue mSyncQueue;
- private final SparseArray<SurfaceControl> mLeashByTaskId = new SparseArray<>();
-
- // TODO(shell-transitions): Remove when switched to shell-transitions.
- private final SparseArray<Point> mPositionByTaskId = new SparseArray<>();
-
- RunningTaskInfo mPrimary;
- RunningTaskInfo mSecondary;
- SurfaceControl mPrimarySurface;
- SurfaceControl mSecondarySurface;
- SurfaceControl mPrimaryDim;
- SurfaceControl mSecondaryDim;
- Rect mHomeBounds = new Rect();
- final LegacySplitScreenController mSplitScreenController;
- private boolean mSplitScreenSupported = false;
-
- final SurfaceSession mSurfaceSession = new SurfaceSession();
-
- private final LegacySplitScreenTransitions mSplitTransitions;
-
- LegacySplitScreenTaskListener(LegacySplitScreenController splitScreenController,
- ShellTaskOrganizer shellTaskOrganizer,
- Transitions transitions,
- SyncTransactionQueue syncQueue) {
- mSplitScreenController = splitScreenController;
- mTaskOrganizer = shellTaskOrganizer;
- mSplitTransitions = new LegacySplitScreenTransitions(splitScreenController.mTransactionPool,
- transitions, mSplitScreenController, this);
- transitions.addHandler(mSplitTransitions);
- mSyncQueue = syncQueue;
- }
-
- void init() {
- synchronized (this) {
- try {
- mTaskOrganizer.createRootTask(
- DEFAULT_DISPLAY, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, this);
- mTaskOrganizer.createRootTask(
- DEFAULT_DISPLAY, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, this);
- } catch (Exception e) {
- // teardown to prevent callbacks
- mTaskOrganizer.removeListener(this);
- throw e;
- }
- }
- }
-
- boolean isSplitScreenSupported() {
- return mSplitScreenSupported;
- }
-
- SurfaceControl.Transaction getTransaction() {
- return mSplitScreenController.mTransactionPool.acquire();
- }
-
- void releaseTransaction(SurfaceControl.Transaction t) {
- mSplitScreenController.mTransactionPool.release(t);
- }
-
- TaskOrganizer getTaskOrganizer() {
- return mTaskOrganizer;
- }
-
- LegacySplitScreenTransitions getSplitTransitions() {
- return mSplitTransitions;
- }
-
- @Override
- public void onTaskAppeared(RunningTaskInfo taskInfo, SurfaceControl leash) {
- synchronized (this) {
- if (taskInfo.hasParentTask()) {
- handleChildTaskAppeared(taskInfo, leash);
- return;
- }
-
- final int winMode = taskInfo.getWindowingMode();
- if (winMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
- ProtoLog.v(WM_SHELL_TASK_ORG,
- "%s onTaskAppeared Primary taskId=%d", TAG, taskInfo.taskId);
- mPrimary = taskInfo;
- mPrimarySurface = leash;
- } else if (winMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) {
- ProtoLog.v(WM_SHELL_TASK_ORG,
- "%s onTaskAppeared Secondary taskId=%d", TAG, taskInfo.taskId);
- mSecondary = taskInfo;
- mSecondarySurface = leash;
- } else {
- ProtoLog.v(WM_SHELL_TASK_ORG, "%s onTaskAppeared unknown taskId=%d winMode=%d",
- TAG, taskInfo.taskId, winMode);
- }
-
- if (!mSplitScreenSupported && mPrimarySurface != null && mSecondarySurface != null) {
- mSplitScreenSupported = true;
- mSplitScreenController.onSplitScreenSupported();
- ProtoLog.v(WM_SHELL_TASK_ORG, "%s onTaskAppeared Supported", TAG);
-
- // Initialize dim surfaces:
- SurfaceControl.Transaction t = getTransaction();
- mPrimaryDim = SurfaceUtils.makeDimLayer(
- t, mPrimarySurface, "Primary Divider Dim", mSurfaceSession);
- mSecondaryDim = SurfaceUtils.makeDimLayer(
- t, mSecondarySurface, "Secondary Divider Dim", mSurfaceSession);
- t.apply();
- releaseTransaction(t);
- }
- }
- }
-
- @Override
- public void onTaskVanished(RunningTaskInfo taskInfo) {
- synchronized (this) {
- mPositionByTaskId.remove(taskInfo.taskId);
- if (taskInfo.hasParentTask()) {
- mLeashByTaskId.remove(taskInfo.taskId);
- return;
- }
-
- final boolean isPrimaryTask = mPrimary != null
- && taskInfo.token.equals(mPrimary.token);
- final boolean isSecondaryTask = mSecondary != null
- && taskInfo.token.equals(mSecondary.token);
-
- if (mSplitScreenSupported && (isPrimaryTask || isSecondaryTask)) {
- mSplitScreenSupported = false;
-
- SurfaceControl.Transaction t = getTransaction();
- t.remove(mPrimaryDim);
- t.remove(mSecondaryDim);
- t.remove(mPrimarySurface);
- t.remove(mSecondarySurface);
- t.apply();
- releaseTransaction(t);
-
- mSplitScreenController.onTaskVanished();
- }
- }
- }
-
- @Override
- public void onTaskInfoChanged(RunningTaskInfo taskInfo) {
- if (taskInfo.displayId != DEFAULT_DISPLAY) {
- return;
- }
- synchronized (this) {
- if (!taskInfo.supportsMultiWindow) {
- if (mSplitScreenController.isDividerVisible()) {
- // Dismiss the split screen if the task no longer supports multi window.
- if (taskInfo.taskId == mPrimary.taskId
- || taskInfo.parentTaskId == mPrimary.taskId) {
- // If the primary is focused, dismiss to primary.
- mSplitScreenController
- .startDismissSplit(taskInfo.isFocused /* toPrimaryTask */);
- } else {
- // If the secondary is not focused, dismiss to primary.
- mSplitScreenController
- .startDismissSplit(!taskInfo.isFocused /* toPrimaryTask */);
- }
- }
- return;
- }
- if (taskInfo.hasParentTask()) {
- // changed messages are noisy since it reports on every ensureVisibility. This
- // conflicts with legacy app-transitions which "swaps" the position to a
- // leash. For now, only update when position actually changes to avoid
- // poorly-timed duplicate calls.
- if (taskInfo.positionInParent.equals(mPositionByTaskId.get(taskInfo.taskId))) {
- return;
- }
- handleChildTaskChanged(taskInfo);
- } else {
- handleTaskInfoChanged(taskInfo);
- }
- mPositionByTaskId.put(taskInfo.taskId, new Point(taskInfo.positionInParent));
- }
- }
-
- private void handleChildTaskAppeared(RunningTaskInfo taskInfo, SurfaceControl leash) {
- mLeashByTaskId.put(taskInfo.taskId, leash);
- mPositionByTaskId.put(taskInfo.taskId, new Point(taskInfo.positionInParent));
- if (Transitions.ENABLE_SHELL_TRANSITIONS) return;
- updateChildTaskSurface(taskInfo, leash, true /* firstAppeared */);
- }
-
- private void handleChildTaskChanged(RunningTaskInfo taskInfo) {
- if (Transitions.ENABLE_SHELL_TRANSITIONS) return;
- final SurfaceControl leash = mLeashByTaskId.get(taskInfo.taskId);
- updateChildTaskSurface(taskInfo, leash, false /* firstAppeared */);
- }
-
- private void updateChildTaskSurface(
- RunningTaskInfo taskInfo, SurfaceControl leash, boolean firstAppeared) {
- final Point taskPositionInParent = taskInfo.positionInParent;
- mSyncQueue.runInSync(t -> {
- t.setWindowCrop(leash, null);
- t.setPosition(leash, taskPositionInParent.x, taskPositionInParent.y);
- if (firstAppeared && !Transitions.ENABLE_SHELL_TRANSITIONS) {
- t.setAlpha(leash, 1f);
- t.setMatrix(leash, 1, 0, 0, 1);
- t.show(leash);
- }
- });
- }
-
- /**
- * This is effectively a finite state machine which moves between the various split-screen
- * presentations based on the contents of the split regions.
- */
- private void handleTaskInfoChanged(RunningTaskInfo info) {
- if (!mSplitScreenSupported) {
- // This shouldn't happen; but apparently there is a chance that SysUI crashes without
- // system server receiving binder-death (or maybe it receives binder-death too late?).
- // In this situation, when sys-ui restarts, the split root-tasks will still exist so
- // there is a small window of time during init() where WM might send messages here
- // before init() fails. So, avoid a cycle of crashes by returning early.
- Log.e(TAG, "Got handleTaskInfoChanged when not initialized: " + info);
- return;
- }
- final boolean secondaryImpliedMinimize = mSecondary.topActivityType == ACTIVITY_TYPE_HOME
- || (mSecondary.topActivityType == ACTIVITY_TYPE_RECENTS
- && mSplitScreenController.isHomeStackResizable());
- final boolean primaryWasEmpty = mPrimary.topActivityType == ACTIVITY_TYPE_UNDEFINED;
- final boolean secondaryWasEmpty = mSecondary.topActivityType == ACTIVITY_TYPE_UNDEFINED;
- if (info.token.asBinder() == mPrimary.token.asBinder()) {
- mPrimary = info;
- } else if (info.token.asBinder() == mSecondary.token.asBinder()) {
- mSecondary = info;
- }
- if (DEBUG) {
- Log.d(TAG, "onTaskInfoChanged " + mPrimary + " " + mSecondary);
- }
- if (Transitions.ENABLE_SHELL_TRANSITIONS) return;
- final boolean primaryIsEmpty = mPrimary.topActivityType == ACTIVITY_TYPE_UNDEFINED;
- final boolean secondaryIsEmpty = mSecondary.topActivityType == ACTIVITY_TYPE_UNDEFINED;
- final boolean secondaryImpliesMinimize = mSecondary.topActivityType == ACTIVITY_TYPE_HOME
- || (mSecondary.topActivityType == ACTIVITY_TYPE_RECENTS
- && mSplitScreenController.isHomeStackResizable());
- if (primaryIsEmpty == primaryWasEmpty && secondaryWasEmpty == secondaryIsEmpty
- && secondaryImpliedMinimize == secondaryImpliesMinimize) {
- // No relevant changes
- return;
- }
- if (primaryIsEmpty || secondaryIsEmpty) {
- // At-least one of the splits is empty which means we are currently transitioning
- // into or out-of split-screen mode.
- if (DEBUG) {
- Log.d(TAG, " at-least one split empty " + mPrimary.topActivityType
- + " " + mSecondary.topActivityType);
- }
- if (mSplitScreenController.isDividerVisible()) {
- // Was in split-mode, which means we are leaving split, so continue that.
- // This happens when the stack in the primary-split is dismissed.
- if (DEBUG) {
- Log.d(TAG, " was in split, so this means leave it "
- + mPrimary.topActivityType + " " + mSecondary.topActivityType);
- }
- mSplitScreenController.startDismissSplit(false /* toPrimaryTask */);
- } else if (!primaryIsEmpty && primaryWasEmpty && secondaryWasEmpty) {
- // Wasn't in split-mode (both were empty), but now that the primary split is
- // populated, we should fully enter split by moving everything else into secondary.
- // This just tells window-manager to reparent things, the UI will respond
- // when it gets new task info for the secondary split.
- if (DEBUG) {
- Log.d(TAG, " was not in split, but primary is populated, so enter it");
- }
- mSplitScreenController.startEnterSplit();
- }
- } else if (secondaryImpliesMinimize) {
- // Workaround for b/172686383, we can't rely on the sync bounds change transaction for
- // the home task to finish before the last updateChildTaskSurface() call even if it's
- // queued on the sync transaction queue, so ensure that the home task surface is updated
- // again before we minimize
- final ArrayList<RunningTaskInfo> tasks = new ArrayList<>();
- mSplitScreenController.getWmProxy().getHomeAndRecentsTasks(tasks,
- mSplitScreenController.getSecondaryRoot());
- for (int i = 0; i < tasks.size(); i++) {
- final RunningTaskInfo taskInfo = tasks.get(i);
- final SurfaceControl leash = mLeashByTaskId.get(taskInfo.taskId);
- if (leash != null) {
- updateChildTaskSurface(taskInfo, leash, false /* firstAppeared */);
- }
- }
-
- // Both splits are populated but the secondary split has a home/recents stack on top,
- // so enter minimized mode.
- mSplitScreenController.ensureMinimizedSplit();
- } else {
- // Both splits are populated by normal activities, so make sure we aren't minimized.
- mSplitScreenController.ensureNormalSplit();
- }
- }
-
- @Override
- public void attachChildSurfaceToTask(int taskId, SurfaceControl.Builder b) {
- b.setParent(findTaskSurface(taskId));
- }
-
- @Override
- public void reparentChildSurfaceToTask(int taskId, SurfaceControl sc,
- SurfaceControl.Transaction t) {
- t.reparent(sc, findTaskSurface(taskId));
- }
-
- private SurfaceControl findTaskSurface(int taskId) {
- if (!mLeashByTaskId.contains(taskId)) {
- throw new IllegalArgumentException("There is no surface for taskId=" + taskId);
- }
- return mLeashByTaskId.get(taskId);
- }
-
- @Override
- public void dump(@NonNull PrintWriter pw, String prefix) {
- final String innerPrefix = prefix + " ";
- final String childPrefix = innerPrefix + " ";
- pw.println(prefix + this);
- pw.println(innerPrefix + "mSplitScreenSupported=" + mSplitScreenSupported);
- if (mPrimary != null) pw.println(innerPrefix + "mPrimary.taskId=" + mPrimary.taskId);
- if (mSecondary != null) pw.println(innerPrefix + "mSecondary.taskId=" + mSecondary.taskId);
- }
-
- @Override
- public String toString() {
- return TAG;
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenTransitions.java
deleted file mode 100644
index b1fa2ac..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenTransitions.java
+++ /dev/null
@@ -1,348 +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.wm.shell.legacysplitscreen;
-
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
-import static android.view.WindowManager.TRANSIT_CHANGE;
-import static android.view.WindowManager.TRANSIT_CLOSE;
-import static android.view.WindowManager.TRANSIT_FIRST_CUSTOM;
-import static android.view.WindowManager.TRANSIT_OPEN;
-import static android.view.WindowManager.TRANSIT_TO_BACK;
-import static android.view.WindowManager.TRANSIT_TO_FRONT;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ValueAnimator;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.app.ActivityManager;
-import android.app.WindowConfiguration;
-import android.graphics.Rect;
-import android.os.IBinder;
-import android.view.SurfaceControl;
-import android.view.WindowManager;
-import android.window.TransitionInfo;
-import android.window.TransitionRequestInfo;
-import android.window.WindowContainerTransaction;
-
-import com.android.wm.shell.common.TransactionPool;
-import com.android.wm.shell.common.annotations.ExternalThread;
-import com.android.wm.shell.transition.Transitions;
-
-import java.util.ArrayList;
-
-/** Plays transition animations for split-screen */
-public class LegacySplitScreenTransitions implements Transitions.TransitionHandler {
- private static final String TAG = "SplitScreenTransitions";
-
- public static final int TRANSIT_SPLIT_DISMISS_SNAP = TRANSIT_FIRST_CUSTOM + 10;
-
- private final TransactionPool mTransactionPool;
- private final Transitions mTransitions;
- private final LegacySplitScreenController mSplitScreen;
- private final LegacySplitScreenTaskListener mListener;
-
- private IBinder mPendingDismiss = null;
- private boolean mDismissFromSnap = false;
- private IBinder mPendingEnter = null;
- private IBinder mAnimatingTransition = null;
-
- /** Keeps track of currently running animations */
- private final ArrayList<Animator> mAnimations = new ArrayList<>();
-
- private Transitions.TransitionFinishCallback mFinishCallback = null;
- private SurfaceControl.Transaction mFinishTransaction;
-
- LegacySplitScreenTransitions(@NonNull TransactionPool pool, @NonNull Transitions transitions,
- @NonNull LegacySplitScreenController splitScreen,
- @NonNull LegacySplitScreenTaskListener listener) {
- mTransactionPool = pool;
- mTransitions = transitions;
- mSplitScreen = splitScreen;
- mListener = listener;
- }
-
- @Override
- public WindowContainerTransaction handleRequest(@NonNull IBinder transition,
- @Nullable TransitionRequestInfo request) {
- WindowContainerTransaction out = null;
- final ActivityManager.RunningTaskInfo triggerTask = request.getTriggerTask();
- final @WindowManager.TransitionType int type = request.getType();
- if (mSplitScreen.isDividerVisible()) {
- // try to handle everything while in split-screen
- out = new WindowContainerTransaction();
- if (triggerTask != null) {
- final boolean shouldDismiss =
- // if we close the primary-docked task, then leave split-screen since there
- // is nothing behind it.
- ((type == TRANSIT_CLOSE || type == TRANSIT_TO_BACK)
- && triggerTask.parentTaskId == mListener.mPrimary.taskId)
- // if an activity that is not supported in multi window mode is launched,
- // we also need to leave split-screen.
- || ((type == TRANSIT_OPEN || type == TRANSIT_TO_FRONT)
- && !triggerTask.supportsMultiWindow);
- // In both cases, dismiss the primary
- if (shouldDismiss) {
- WindowManagerProxy.buildDismissSplit(out, mListener,
- mSplitScreen.getSplitLayout(), true /* dismiss */);
- if (type == TRANSIT_OPEN || type == TRANSIT_TO_FRONT) {
- out.reorder(triggerTask.token, true /* onTop */);
- }
- mPendingDismiss = transition;
- }
- }
- } else if (triggerTask != null) {
- // Not in split mode, so look for an open with a trigger task.
- if ((type == TRANSIT_OPEN || type == TRANSIT_TO_FRONT)
- && triggerTask.configuration.windowConfiguration.getWindowingMode()
- == WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
- out = new WindowContainerTransaction();
- mSplitScreen.prepareEnterSplitTransition(out);
- mPendingEnter = transition;
- }
- }
- return out;
- }
-
- // TODO(shell-transitions): real animations
- private void startExampleAnimation(@NonNull SurfaceControl leash, boolean show) {
- final float end = show ? 1.f : 0.f;
- final float start = 1.f - end;
- final SurfaceControl.Transaction transaction = mTransactionPool.acquire();
- final ValueAnimator va = ValueAnimator.ofFloat(start, end);
- va.setDuration(500);
- va.addUpdateListener(animation -> {
- float fraction = animation.getAnimatedFraction();
- transaction.setAlpha(leash, start * (1.f - fraction) + end * fraction);
- transaction.apply();
- });
- final Runnable finisher = () -> {
- transaction.setAlpha(leash, end);
- transaction.apply();
- mTransactionPool.release(transaction);
- mTransitions.getMainExecutor().execute(() -> {
- mAnimations.remove(va);
- onFinish();
- });
- };
- va.addListener(new Animator.AnimatorListener() {
- @Override
- public void onAnimationStart(Animator animation) { }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- finisher.run();
- }
-
- @Override
- public void onAnimationCancel(Animator animation) {
- finisher.run();
- }
-
- @Override
- public void onAnimationRepeat(Animator animation) { }
- });
- mAnimations.add(va);
- mTransitions.getAnimExecutor().execute(va::start);
- }
-
- // TODO(shell-transitions): real animations
- private void startExampleResizeAnimation(@NonNull SurfaceControl leash,
- @NonNull Rect startBounds, @NonNull Rect endBounds) {
- final SurfaceControl.Transaction transaction = mTransactionPool.acquire();
- final ValueAnimator va = ValueAnimator.ofFloat(0.f, 1.f);
- va.setDuration(500);
- va.addUpdateListener(animation -> {
- float fraction = animation.getAnimatedFraction();
- transaction.setWindowCrop(leash,
- (int) (startBounds.width() * (1.f - fraction) + endBounds.width() * fraction),
- (int) (startBounds.height() * (1.f - fraction)
- + endBounds.height() * fraction));
- transaction.setPosition(leash,
- startBounds.left * (1.f - fraction) + endBounds.left * fraction,
- startBounds.top * (1.f - fraction) + endBounds.top * fraction);
- transaction.apply();
- });
- final Runnable finisher = () -> {
- transaction.setWindowCrop(leash, 0, 0);
- transaction.setPosition(leash, endBounds.left, endBounds.top);
- transaction.apply();
- mTransactionPool.release(transaction);
- mTransitions.getMainExecutor().execute(() -> {
- mAnimations.remove(va);
- onFinish();
- });
- };
- va.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- finisher.run();
- }
-
- @Override
- public void onAnimationCancel(Animator animation) {
- finisher.run();
- }
- });
- mAnimations.add(va);
- mTransitions.getAnimExecutor().execute(va::start);
- }
-
- @Override
- public boolean startAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
- @NonNull SurfaceControl.Transaction startTransaction,
- @NonNull SurfaceControl.Transaction finishTransaction,
- @NonNull Transitions.TransitionFinishCallback finishCallback) {
- if (transition != mPendingDismiss && transition != mPendingEnter) {
- // If we're not in split-mode, just abort
- if (!mSplitScreen.isDividerVisible()) return false;
- // Check to see if HOME is involved
- for (int i = info.getChanges().size() - 1; i >= 0; --i) {
- final TransitionInfo.Change change = info.getChanges().get(i);
- if (change.getTaskInfo() == null
- || change.getTaskInfo().getActivityType() != ACTIVITY_TYPE_HOME) continue;
- if (change.getMode() == TRANSIT_OPEN || change.getMode() == TRANSIT_TO_FRONT) {
- mSplitScreen.ensureMinimizedSplit();
- } else if (change.getMode() == TRANSIT_CLOSE
- || change.getMode() == TRANSIT_TO_BACK) {
- mSplitScreen.ensureNormalSplit();
- }
- }
- // Use normal animations.
- return false;
- }
-
- mFinishCallback = finishCallback;
- mFinishTransaction = mTransactionPool.acquire();
- mAnimatingTransition = transition;
-
- // Play fade animations
- for (int i = info.getChanges().size() - 1; i >= 0; --i) {
- final TransitionInfo.Change change = info.getChanges().get(i);
- final SurfaceControl leash = change.getLeash();
- final int mode = info.getChanges().get(i).getMode();
-
- if (mode == TRANSIT_CHANGE) {
- if (change.getParent() != null) {
- // This is probably reparented, so we want the parent to be immediately visible
- final TransitionInfo.Change parentChange = info.getChange(change.getParent());
- startTransaction.show(parentChange.getLeash());
- startTransaction.setAlpha(parentChange.getLeash(), 1.f);
- // and then animate this layer outside the parent (since, for example, this is
- // the home task animating from fullscreen to part-screen).
- startTransaction.reparent(leash, info.getRootLeash());
- startTransaction.setLayer(leash, info.getChanges().size() - i);
- // build the finish reparent/reposition
- mFinishTransaction.reparent(leash, parentChange.getLeash());
- mFinishTransaction.setPosition(leash,
- change.getEndRelOffset().x, change.getEndRelOffset().y);
- }
- // TODO(shell-transitions): screenshot here
- final Rect startBounds = new Rect(change.getStartAbsBounds());
- final boolean isHome = change.getTaskInfo() != null
- && change.getTaskInfo().getActivityType() == ACTIVITY_TYPE_HOME;
- if (mPendingDismiss == transition && mDismissFromSnap && !isHome) {
- // Home is special since it doesn't move during fling. Everything else, though,
- // when dismissing from snap, the top/left is at 0,0.
- startBounds.offsetTo(0, 0);
- }
- final Rect endBounds = new Rect(change.getEndAbsBounds());
- startBounds.offset(-info.getRootOffset().x, -info.getRootOffset().y);
- endBounds.offset(-info.getRootOffset().x, -info.getRootOffset().y);
- startExampleResizeAnimation(leash, startBounds, endBounds);
- }
- if (change.getParent() != null) {
- continue;
- }
-
- if (transition == mPendingEnter
- && mListener.mPrimary.token.equals(change.getContainer())
- || mListener.mSecondary.token.equals(change.getContainer())) {
- startTransaction.setWindowCrop(leash, change.getStartAbsBounds().width(),
- change.getStartAbsBounds().height());
- if (mListener.mPrimary.token.equals(change.getContainer())) {
- // Move layer to top since we want it above the oversized home task during
- // animation even though home task is on top in hierarchy.
- startTransaction.setLayer(leash, info.getChanges().size() + 1);
- }
- }
- boolean isOpening = Transitions.isOpeningType(info.getType());
- if (isOpening && (mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT)) {
- // fade in
- startExampleAnimation(leash, true /* show */);
- } else if (!isOpening && (mode == TRANSIT_CLOSE || mode == TRANSIT_TO_BACK)) {
- // fade out
- if (transition == mPendingDismiss && mDismissFromSnap) {
- // Dismissing via snap-to-top/bottom means that the dismissed task is already
- // not-visible (usually cropped to oblivion) so immediately set its alpha to 0
- // and don't animate it so it doesn't pop-in when reparented.
- startTransaction.setAlpha(leash, 0.f);
- } else {
- startExampleAnimation(leash, false /* show */);
- }
- }
- }
- if (transition == mPendingEnter) {
- // If entering, check if we should enter into minimized or normal split
- boolean homeIsVisible = false;
- for (int i = info.getChanges().size() - 1; i >= 0; --i) {
- final TransitionInfo.Change change = info.getChanges().get(i);
- if (change.getTaskInfo() == null
- || change.getTaskInfo().getActivityType() != ACTIVITY_TYPE_HOME) {
- continue;
- }
- homeIsVisible = change.getMode() == TRANSIT_OPEN
- || change.getMode() == TRANSIT_TO_FRONT
- || change.getMode() == TRANSIT_CHANGE;
- break;
- }
- mSplitScreen.finishEnterSplitTransition(homeIsVisible);
- }
- startTransaction.apply();
- onFinish();
- return true;
- }
-
- @ExternalThread
- void dismissSplit(LegacySplitScreenTaskListener tiles, LegacySplitDisplayLayout layout,
- boolean dismissOrMaximize, boolean snapped) {
- final WindowContainerTransaction wct = new WindowContainerTransaction();
- WindowManagerProxy.buildDismissSplit(wct, tiles, layout, dismissOrMaximize);
- mTransitions.getMainExecutor().execute(() -> {
- mDismissFromSnap = snapped;
- mPendingDismiss = mTransitions.startTransition(TRANSIT_SPLIT_DISMISS_SNAP, wct, this);
- });
- }
-
- private void onFinish() {
- if (!mAnimations.isEmpty()) return;
- mFinishTransaction.apply();
- mTransactionPool.release(mFinishTransaction);
- mFinishTransaction = null;
- mFinishCallback.onTransitionFinished(null /* wct */, null /* wctCB */);
- mFinishCallback = null;
- if (mAnimatingTransition == mPendingEnter) {
- mPendingEnter = null;
- }
- if (mAnimatingTransition == mPendingDismiss) {
- mSplitScreen.onDismissSplit();
- mPendingDismiss = null;
- }
- mDismissFromSnap = false;
- mAnimatingTransition = null;
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/MinimizedDockShadow.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/MinimizedDockShadow.java
deleted file mode 100644
index 1e9223c..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/MinimizedDockShadow.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.legacysplitscreen;
-
-import android.annotation.Nullable;
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.LinearGradient;
-import android.graphics.Paint;
-import android.graphics.Shader;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.WindowManager;
-
-import com.android.wm.shell.R;
-
-/**
- * Shadow for the minimized dock state on homescreen.
- */
-public class MinimizedDockShadow extends View {
-
- private final Paint mShadowPaint = new Paint();
-
- private int mDockSide = WindowManager.DOCKED_INVALID;
-
- public MinimizedDockShadow(Context context, @Nullable AttributeSet attrs) {
- super(context, attrs);
- }
-
- void setDockSide(int dockSide) {
- if (dockSide != mDockSide) {
- mDockSide = dockSide;
- updatePaint(getLeft(), getTop(), getRight(), getBottom());
- invalidate();
- }
- }
-
- private void updatePaint(int left, int top, int right, int bottom) {
- int startColor = mContext.getResources().getColor(
- R.color.minimize_dock_shadow_start, null);
- int endColor = mContext.getResources().getColor(
- R.color.minimize_dock_shadow_end, null);
- final int middleColor = Color.argb(
- (Color.alpha(startColor) + Color.alpha(endColor)) / 2, 0, 0, 0);
- final int quarter = Color.argb(
- (int) (Color.alpha(startColor) * 0.25f + Color.alpha(endColor) * 0.75f),
- 0, 0, 0);
- if (mDockSide == WindowManager.DOCKED_TOP) {
- mShadowPaint.setShader(new LinearGradient(
- 0, 0, 0, bottom - top,
- new int[] { startColor, middleColor, quarter, endColor },
- new float[] { 0f, 0.35f, 0.6f, 1f }, Shader.TileMode.CLAMP));
- } else if (mDockSide == WindowManager.DOCKED_LEFT) {
- mShadowPaint.setShader(new LinearGradient(
- 0, 0, right - left, 0,
- new int[] { startColor, middleColor, quarter, endColor },
- new float[] { 0f, 0.35f, 0.6f, 1f }, Shader.TileMode.CLAMP));
- } else if (mDockSide == WindowManager.DOCKED_RIGHT) {
- mShadowPaint.setShader(new LinearGradient(
- right - left, 0, 0, 0,
- new int[] { startColor, middleColor, quarter, endColor },
- new float[] { 0f, 0.35f, 0.6f, 1f }, Shader.TileMode.CLAMP));
- }
- }
-
- @Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- super.onLayout(changed, left, top, right, bottom);
- if (changed) {
- updatePaint(left, top, right, bottom);
- invalidate();
- }
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- canvas.drawRect(0, 0, getWidth(), getHeight(), mShadowPaint);
- }
-
- @Override
- public boolean hasOverlappingRendering() {
- return false;
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/WindowManagerProxy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/WindowManagerProxy.java
deleted file mode 100644
index e42e43b..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/WindowManagerProxy.java
+++ /dev/null
@@ -1,386 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.legacysplitscreen;
-
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
-import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
-import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
-import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
-import static android.view.Display.DEFAULT_DISPLAY;
-
-import android.annotation.NonNull;
-import android.app.ActivityManager;
-import android.app.ActivityTaskManager;
-import android.graphics.Rect;
-import android.os.RemoteException;
-import android.util.Log;
-import android.view.Display;
-import android.view.SurfaceControl;
-import android.view.WindowManagerGlobal;
-import android.window.TaskOrganizer;
-import android.window.WindowContainerToken;
-import android.window.WindowContainerTransaction;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.util.ArrayUtils;
-import com.android.wm.shell.common.SyncTransactionQueue;
-import com.android.wm.shell.transition.Transitions;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Proxy to simplify calls into window manager/activity manager
- */
-class WindowManagerProxy {
-
- private static final String TAG = "WindowManagerProxy";
- private static final int[] HOME_AND_RECENTS = {ACTIVITY_TYPE_HOME, ACTIVITY_TYPE_RECENTS};
- private static final int[] CONTROLLED_ACTIVITY_TYPES = {
- ACTIVITY_TYPE_STANDARD,
- ACTIVITY_TYPE_HOME,
- ACTIVITY_TYPE_RECENTS,
- ACTIVITY_TYPE_UNDEFINED
- };
- private static final int[] CONTROLLED_WINDOWING_MODES = {
- WINDOWING_MODE_FULLSCREEN,
- WINDOWING_MODE_SPLIT_SCREEN_SECONDARY,
- WINDOWING_MODE_UNDEFINED
- };
-
- @GuardedBy("mDockedRect")
- private final Rect mDockedRect = new Rect();
-
- private final Rect mTmpRect1 = new Rect();
-
- @GuardedBy("mDockedRect")
- private final Rect mTouchableRegion = new Rect();
-
- private final SyncTransactionQueue mSyncTransactionQueue;
- private final TaskOrganizer mTaskOrganizer;
-
- WindowManagerProxy(SyncTransactionQueue syncQueue, TaskOrganizer taskOrganizer) {
- mSyncTransactionQueue = syncQueue;
- mTaskOrganizer = taskOrganizer;
- }
-
- void dismissOrMaximizeDocked(final LegacySplitScreenTaskListener tiles,
- LegacySplitDisplayLayout layout, final boolean dismissOrMaximize) {
- if (Transitions.ENABLE_SHELL_TRANSITIONS) {
- tiles.mSplitScreenController.startDismissSplit(!dismissOrMaximize, true /* snapped */);
- } else {
- applyDismissSplit(tiles, layout, dismissOrMaximize);
- }
- }
-
- public void setResizing(final boolean resizing) {
- try {
- ActivityTaskManager.getService().setSplitScreenResizing(resizing);
- } catch (RemoteException e) {
- Log.w(TAG, "Error calling setDockedStackResizing: " + e);
- }
- }
-
- /** Sets a touch region */
- public void setTouchRegion(Rect region) {
- try {
- synchronized (mDockedRect) {
- mTouchableRegion.set(region);
- }
- WindowManagerGlobal.getWindowManagerService().setDockedTaskDividerTouchRegion(
- mTouchableRegion);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to set touchable region: " + e);
- }
- }
-
- void applyResizeSplits(int position, LegacySplitDisplayLayout splitLayout) {
- WindowContainerTransaction t = new WindowContainerTransaction();
- splitLayout.resizeSplits(position, t);
- applySyncTransaction(t);
- }
-
- boolean getHomeAndRecentsTasks(List<ActivityManager.RunningTaskInfo> out,
- WindowContainerToken parent) {
- boolean resizable = false;
- List<ActivityManager.RunningTaskInfo> rootTasks = parent == null
- ? mTaskOrganizer.getRootTasks(Display.DEFAULT_DISPLAY, HOME_AND_RECENTS)
- : mTaskOrganizer.getChildTasks(parent, HOME_AND_RECENTS);
- for (int i = 0, n = rootTasks.size(); i < n; ++i) {
- final ActivityManager.RunningTaskInfo ti = rootTasks.get(i);
- out.add(ti);
- if (ti.topActivityType == ACTIVITY_TYPE_HOME) {
- resizable = ti.isResizeable;
- }
- }
- return resizable;
- }
-
- /**
- * Assign a fixed override-bounds to home tasks that reflect their geometry while the primary
- * split is minimized. This actually "sticks out" of the secondary split area, but when in
- * minimized mode, the secondary split gets a 'negative' crop to expose it.
- */
- boolean applyHomeTasksMinimized(LegacySplitDisplayLayout layout, WindowContainerToken parent,
- @NonNull WindowContainerTransaction wct) {
- // Resize the home/recents stacks to the larger minimized-state size
- final Rect homeBounds;
- final ArrayList<ActivityManager.RunningTaskInfo> homeStacks = new ArrayList<>();
- boolean isHomeResizable = getHomeAndRecentsTasks(homeStacks, parent);
- if (isHomeResizable) {
- homeBounds = layout.calcResizableMinimizedHomeStackBounds();
- } else {
- // home is not resizable, so lock it to its inherent orientation size.
- homeBounds = new Rect(0, 0, 0, 0);
- for (int i = homeStacks.size() - 1; i >= 0; --i) {
- if (homeStacks.get(i).topActivityType == ACTIVITY_TYPE_HOME) {
- final int orient = homeStacks.get(i).configuration.orientation;
- final boolean displayLandscape = layout.mDisplayLayout.isLandscape();
- final boolean isLandscape = orient == ORIENTATION_LANDSCAPE
- || (orient == ORIENTATION_UNDEFINED && displayLandscape);
- homeBounds.right = isLandscape == displayLandscape
- ? layout.mDisplayLayout.width() : layout.mDisplayLayout.height();
- homeBounds.bottom = isLandscape == displayLandscape
- ? layout.mDisplayLayout.height() : layout.mDisplayLayout.width();
- break;
- }
- }
- }
- for (int i = homeStacks.size() - 1; i >= 0; --i) {
- // For non-resizable homes, the minimized size is actually the fullscreen-size. As a
- // result, we don't minimize for recents since it only shows half-size screenshots.
- if (!isHomeResizable) {
- if (homeStacks.get(i).topActivityType == ACTIVITY_TYPE_RECENTS) {
- continue;
- }
- wct.setWindowingMode(homeStacks.get(i).token, WINDOWING_MODE_FULLSCREEN);
- }
- wct.setBounds(homeStacks.get(i).token, homeBounds);
- }
- layout.mTiles.mHomeBounds.set(homeBounds);
- return isHomeResizable;
- }
-
- /** @see #buildEnterSplit */
- boolean applyEnterSplit(LegacySplitScreenTaskListener tiles, LegacySplitDisplayLayout layout) {
- // Set launchtile first so that any stack created after
- // getAllRootTaskInfos and before reparent (even if unlikely) are placed
- // correctly.
- WindowContainerTransaction wct = new WindowContainerTransaction();
- wct.setLaunchRoot(tiles.mSecondary.token, CONTROLLED_WINDOWING_MODES,
- CONTROLLED_ACTIVITY_TYPES);
- final boolean isHomeResizable = buildEnterSplit(wct, tiles, layout);
- applySyncTransaction(wct);
- return isHomeResizable;
- }
-
- /**
- * Finishes entering split-screen by reparenting all FULLSCREEN tasks into the secondary split.
- * This assumes there is already something in the primary split since that is usually what
- * triggers a call to this. In the same transaction, this overrides the home task bounds via
- * {@link #applyHomeTasksMinimized}.
- *
- * @return whether the home stack is resizable
- */
- boolean buildEnterSplit(WindowContainerTransaction outWct, LegacySplitScreenTaskListener tiles,
- LegacySplitDisplayLayout layout) {
- List<ActivityManager.RunningTaskInfo> rootTasks =
- mTaskOrganizer.getRootTasks(DEFAULT_DISPLAY, null /* activityTypes */);
- if (rootTasks.isEmpty()) {
- return false;
- }
- ActivityManager.RunningTaskInfo topHomeTask = null;
- for (int i = rootTasks.size() - 1; i >= 0; --i) {
- final ActivityManager.RunningTaskInfo rootTask = rootTasks.get(i);
- // Check whether the task can be moved to split secondary.
- if (!rootTask.supportsMultiWindow && rootTask.topActivityType != ACTIVITY_TYPE_HOME) {
- continue;
- }
- // Only move split controlling tasks to split secondary.
- final int windowingMode = rootTask.getWindowingMode();
- if (!ArrayUtils.contains(CONTROLLED_WINDOWING_MODES, windowingMode)
- || !ArrayUtils.contains(CONTROLLED_ACTIVITY_TYPES, rootTask.getActivityType())
- // Excludes split screen secondary due to it's the root we're reparenting to.
- || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) {
- continue;
- }
- // Since this iterates from bottom to top, update topHomeTask for every fullscreen task
- // so it will be left with the status of the top one.
- topHomeTask = isHomeOrRecentTask(rootTask) ? rootTask : null;
- outWct.reparent(rootTask.token, tiles.mSecondary.token, true /* onTop */);
- }
- // Move the secondary split-forward.
- outWct.reorder(tiles.mSecondary.token, true /* onTop */);
- boolean isHomeResizable = applyHomeTasksMinimized(layout, null /* parent */,
- outWct);
- if (topHomeTask != null && !Transitions.ENABLE_SHELL_TRANSITIONS) {
- // Translate/update-crop of secondary out-of-band with sync transaction -- Until BALST
- // is enabled, this temporarily syncs the home surface position with offset until
- // sync transaction finishes.
- outWct.setBoundsChangeTransaction(topHomeTask.token, tiles.mHomeBounds);
- }
- return isHomeResizable;
- }
-
- static boolean isHomeOrRecentTask(ActivityManager.RunningTaskInfo ti) {
- final int atype = ti.getActivityType();
- return atype == ACTIVITY_TYPE_HOME || atype == ACTIVITY_TYPE_RECENTS;
- }
-
- /** @see #buildDismissSplit */
- void applyDismissSplit(LegacySplitScreenTaskListener tiles, LegacySplitDisplayLayout layout,
- boolean dismissOrMaximize) {
- // TODO(task-org): Once task-org is more complete, consider using Appeared/Vanished
- // plus specific APIs to clean this up.
- final WindowContainerTransaction wct = new WindowContainerTransaction();
- // Set launch root first so that any task created after getChildContainers and
- // before reparent (pretty unlikely) are put into fullscreen.
- wct.setLaunchRoot(tiles.mSecondary.token, null, null);
- buildDismissSplit(wct, tiles, layout, dismissOrMaximize);
- applySyncTransaction(wct);
- }
-
- /**
- * Reparents all tile members back to their display and resets home task override bounds.
- * @param dismissOrMaximize When {@code true} this resolves the split by closing the primary
- * split (thus resulting in the top of the secondary split becoming
- * fullscreen. {@code false} resolves the other way.
- */
- static void buildDismissSplit(WindowContainerTransaction outWct,
- LegacySplitScreenTaskListener tiles, LegacySplitDisplayLayout layout,
- boolean dismissOrMaximize) {
- // TODO(task-org): Once task-org is more complete, consider using Appeared/Vanished
- // plus specific APIs to clean this up.
- final TaskOrganizer taskOrg = tiles.getTaskOrganizer();
- List<ActivityManager.RunningTaskInfo> primaryChildren =
- taskOrg.getChildTasks(tiles.mPrimary.token, null /* activityTypes */);
- List<ActivityManager.RunningTaskInfo> secondaryChildren =
- taskOrg.getChildTasks(tiles.mSecondary.token, null /* activityTypes */);
- // In some cases (eg. non-resizable is launched), system-server will leave split-screen.
- // as a result, the above will not capture any tasks; yet, we need to clean-up the
- // home task bounds.
- List<ActivityManager.RunningTaskInfo> freeHomeAndRecents =
- taskOrg.getRootTasks(DEFAULT_DISPLAY, HOME_AND_RECENTS);
- // Filter out the root split tasks
- freeHomeAndRecents.removeIf(p -> p.token.equals(tiles.mSecondary.token)
- || p.token.equals(tiles.mPrimary.token));
-
- if (primaryChildren.isEmpty() && secondaryChildren.isEmpty()
- && freeHomeAndRecents.isEmpty()) {
- return;
- }
- if (dismissOrMaximize) {
- // Dismissing, so move all primary split tasks first
- for (int i = primaryChildren.size() - 1; i >= 0; --i) {
- outWct.reparent(primaryChildren.get(i).token, null /* parent */,
- true /* onTop */);
- }
- boolean homeOnTop = false;
- // Don't need to worry about home tasks because they are already in the "proper"
- // order within the secondary split.
- for (int i = secondaryChildren.size() - 1; i >= 0; --i) {
- final ActivityManager.RunningTaskInfo ti = secondaryChildren.get(i);
- outWct.reparent(ti.token, null /* parent */, true /* onTop */);
- if (isHomeOrRecentTask(ti)) {
- outWct.setBounds(ti.token, null);
- outWct.setWindowingMode(ti.token, WINDOWING_MODE_UNDEFINED);
- if (i == 0) {
- homeOnTop = true;
- }
- }
- }
- if (homeOnTop && !Transitions.ENABLE_SHELL_TRANSITIONS) {
- // Translate/update-crop of secondary out-of-band with sync transaction -- instead
- // play this in sync with new home-app frame because until BALST is enabled this
- // shows up on screen before the syncTransaction returns.
- // We only have access to the secondary root surface, though, so in order to
- // position things properly, we have to take into account the existing negative
- // offset/crop of the minimized-home task.
- final boolean landscape = layout.mDisplayLayout.isLandscape();
- final int posX = landscape ? layout.mSecondary.left - tiles.mHomeBounds.left
- : layout.mSecondary.left;
- final int posY = landscape ? layout.mSecondary.top
- : layout.mSecondary.top - tiles.mHomeBounds.top;
- final SurfaceControl.Transaction sft = new SurfaceControl.Transaction();
- sft.setPosition(tiles.mSecondarySurface, posX, posY);
- final Rect crop = new Rect(0, 0, layout.mDisplayLayout.width(),
- layout.mDisplayLayout.height());
- crop.offset(-posX, -posY);
- sft.setWindowCrop(tiles.mSecondarySurface, crop);
- outWct.setBoundsChangeTransaction(tiles.mSecondary.token, sft);
- }
- } else {
- // Maximize, so move non-home secondary split first
- for (int i = secondaryChildren.size() - 1; i >= 0; --i) {
- if (isHomeOrRecentTask(secondaryChildren.get(i))) {
- continue;
- }
- outWct.reparent(secondaryChildren.get(i).token, null /* parent */,
- true /* onTop */);
- }
- // Find and place home tasks in-between. This simulates the fact that there was
- // nothing behind the primary split's tasks.
- for (int i = secondaryChildren.size() - 1; i >= 0; --i) {
- final ActivityManager.RunningTaskInfo ti = secondaryChildren.get(i);
- if (isHomeOrRecentTask(ti)) {
- outWct.reparent(ti.token, null /* parent */, true /* onTop */);
- // reset bounds and mode too
- outWct.setBounds(ti.token, null);
- outWct.setWindowingMode(ti.token, WINDOWING_MODE_UNDEFINED);
- }
- }
- for (int i = primaryChildren.size() - 1; i >= 0; --i) {
- outWct.reparent(primaryChildren.get(i).token, null /* parent */,
- true /* onTop */);
- }
- }
- for (int i = freeHomeAndRecents.size() - 1; i >= 0; --i) {
- outWct.setBounds(freeHomeAndRecents.get(i).token, null);
- outWct.setWindowingMode(freeHomeAndRecents.get(i).token, WINDOWING_MODE_UNDEFINED);
- }
- // Reset focusable to true
- outWct.setFocusable(tiles.mPrimary.token, true /* focusable */);
- }
-
- /**
- * Utility to apply a sync transaction serially with other sync transactions.
- *
- * @see SyncTransactionQueue#queue
- */
- void applySyncTransaction(WindowContainerTransaction wct) {
- mSyncTransactionQueue.queue(wct);
- }
-
- /**
- * @see SyncTransactionQueue#queueIfWaiting
- */
- boolean queueSyncTransactionIfWaiting(WindowContainerTransaction wct) {
- return mSyncTransactionQueue.queueIfWaiting(wct);
- }
-
- /**
- * @see SyncTransactionQueue#runInSync
- */
- void runInSync(SyncTransactionQueue.TransactionRunnable runnable) {
- mSyncTransactionQueue.runInSync(runnable);
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
index 179b725..1d8ac2b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
@@ -39,6 +39,7 @@
import android.util.Slog;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityManager;
+import android.window.DisplayAreaInfo;
import android.window.WindowContainerTransaction;
import androidx.annotation.NonNull;
@@ -659,11 +660,11 @@
}
/**
- * Handles rotation based on OnDisplayChangingListener callback
+ * Handles display change based on OnDisplayChangingListener callback
*/
@Override
- public void onRotateDisplay(int displayId, int fromRotation, int toRotation,
- WindowContainerTransaction wct) {
+ public void onDisplayChange(int displayId, int fromRotation, int toRotation,
+ DisplayAreaInfo newDisplayAreaInfo, WindowContainerTransaction wct) {
if (!isInitialized()) {
return;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java
index c0734e9..3b3091a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java
@@ -44,11 +44,6 @@
}
/**
- * Hides the PIP menu.
- */
- default void hidePipMenu(Runnable onStartCallback, Runnable onEndCallback) {}
-
- /**
* Called when configuration is changed.
*/
default void onConfigurationChanged(Configuration newConfig) {
@@ -125,6 +120,23 @@
default void removePipExclusionBoundsChangeListener(Consumer<Rect> listener) { }
/**
+ * Called when the visibility of keyguard is changed.
+ * @param showing {@code true} if keyguard is now showing, {@code false} otherwise.
+ * @param animating {@code true} if system is animating between keyguard and surface behind,
+ * this only makes sense when showing is {@code false}.
+ */
+ default void onKeyguardVisibilityChanged(boolean showing, boolean animating) { }
+
+ /**
+ * Called when the dismissing animation keyguard and surfaces behind is finished.
+ * See also {@link #onKeyguardVisibilityChanged(boolean, boolean)}.
+ *
+ * TODO(b/206741900) deprecate this path once we're able to animate the PiP window as part of
+ * keyguard dismiss animation.
+ */
+ default void onKeyguardDismissAnimationFinished() { }
+
+ /**
* Dump the current state and information if need.
*
* @param pw The stream to dump information to.
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 b114d81..b3eb0e1 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
@@ -969,6 +969,17 @@
mDeferredAnimEndTransaction = null;
}
+ /** Explicitly set the visibility of PiP window. */
+ public void setPipVisibility(boolean visible) {
+ if (!isInPip()) {
+ return;
+ }
+ final SurfaceControl.Transaction tx =
+ mSurfaceControlTransactionFactory.getTransaction();
+ mSurfaceTransactionHelper.alpha(tx, mLeash, visible ? 1f : 0f);
+ tx.apply();
+ }
+
@Override
public void onDisplayConfigurationChanged(int displayId, Configuration newConfig) {
mCurrentRotation = newConfig.windowConfiguration.getRotation();
@@ -1285,7 +1296,8 @@
*/
public void scheduleOffsetPip(Rect originalBounds, int offset, int duration,
Consumer<Rect> updateBoundsCallback) {
- if (mPipTransitionState.shouldBlockResizeRequest()) {
+ if (mPipTransitionState.shouldBlockResizeRequest()
+ || mPipTransitionState.getInSwipePipToHomeTransition()) {
return;
}
if (mWaitForFixedRotation) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
index dfd34f8..9adfbfe 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
@@ -336,11 +336,27 @@
// (likely a remote like launcher), so don't fire the finish-callback here -- wait until
// the exit transition is merged.
if ((mExitTransition == null || isAnimatingLocally()) && mFinishCallback != null) {
- WindowContainerTransaction wct = new WindowContainerTransaction();
- prepareFinishResizeTransaction(taskInfo, destinationBounds,
- direction, wct);
- if (tx != null) {
- wct.setBoundsChangeTransaction(taskInfo.token, tx);
+ WindowContainerTransaction wct = null;
+ if (isOutPipDirection(direction)) {
+ // Only need to reset surface properties. The server-side operations were already
+ // done at the start.
+ if (tx != null) {
+ mFinishTransaction.merge(tx);
+ }
+ } else {
+ wct = new WindowContainerTransaction();
+ if (isInPipDirection(direction)) {
+ // If we are animating from fullscreen using a bounds animation, then reset the
+ // activity windowing mode, and set the task bounds to the final bounds
+ wct.setActivityWindowingMode(taskInfo.token, WINDOWING_MODE_UNDEFINED);
+ wct.scheduleFinishEnterPip(taskInfo.token, destinationBounds);
+ wct.setBounds(taskInfo.token, destinationBounds);
+ } else {
+ wct.setBounds(taskInfo.token, null /* bounds */);
+ }
+ if (tx != null) {
+ wct.setBoundsChangeTransaction(taskInfo.token, tx);
+ }
}
final SurfaceControl leash = mPipOrganizer.getSurfaceControl();
final int displayRotation = taskInfo.getConfiguration().windowConfiguration
@@ -876,27 +892,4 @@
mPipMenuController.movePipMenu(null, null, destinationBounds);
mPipMenuController.updateMenuBounds(destinationBounds);
}
-
- private void prepareFinishResizeTransaction(TaskInfo taskInfo, Rect destinationBounds,
- @PipAnimationController.TransitionDirection int direction,
- WindowContainerTransaction wct) {
- Rect taskBounds = null;
- if (isInPipDirection(direction)) {
- // If we are animating from fullscreen using a bounds animation, then reset the
- // activity windowing mode set by WM, and set the task bounds to the final bounds
- taskBounds = destinationBounds;
- wct.setActivityWindowingMode(taskInfo.token, WINDOWING_MODE_UNDEFINED);
- wct.scheduleFinishEnterPip(taskInfo.token, destinationBounds);
- } else if (isOutPipDirection(direction)) {
- // If we are animating to fullscreen, then we need to reset the override bounds
- // on the task to ensure that the task "matches" the parent's bounds.
- taskBounds = (direction == TRANSITION_DIRECTION_LEAVE_PIP)
- ? null : destinationBounds;
- wct.setWindowingMode(taskInfo.token, getOutPipWindowingMode());
- // Simply reset the activity mode set prior to the animation running.
- wct.setActivityWindowingMode(taskInfo.token, WINDOWING_MODE_UNDEFINED);
- }
-
- wct.setBounds(taskInfo.token, taskBounds);
- }
}
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 492b5d9..60b406c 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
@@ -129,6 +129,8 @@
protected PinnedStackListenerForwarder.PinnedTaskListener mPinnedTaskListener =
new PipControllerPinnedTaskListener();
+ private boolean mIsKeyguardShowingOrAnimating;
+
private interface PipAnimationListener {
/**
* Notifies the listener that the Pip animation is started.
@@ -154,7 +156,7 @@
* Handler for display rotation changes.
*/
private final DisplayChangeController.OnDisplayChangingListener mRotationController = (
- int displayId, int fromRotation, int toRotation, WindowContainerTransaction t) -> {
+ displayId, fromRotation, toRotation, newDisplayAreaInfo, t) -> {
if (mPipTransitionController.handleRotateDisplay(fromRotation, toRotation, t)) {
return;
}
@@ -613,6 +615,33 @@
}
/**
+ * If {@param keyguardShowing} is {@code false} and {@param animating} is {@code true},
+ * we would wait till the dismissing animation of keyguard and surfaces behind to be
+ * finished first to reset the visibility of PiP window.
+ * See also {@link #onKeyguardDismissAnimationFinished()}
+ */
+ private void onKeyguardVisibilityChanged(boolean keyguardShowing, boolean animating) {
+ if (!mPipTaskOrganizer.isInPip()) {
+ return;
+ }
+ if (keyguardShowing) {
+ mIsKeyguardShowingOrAnimating = true;
+ hidePipMenu(null /* onStartCallback */, null /* onEndCallback */);
+ mPipTaskOrganizer.setPipVisibility(false);
+ } else if (!animating) {
+ mIsKeyguardShowingOrAnimating = false;
+ mPipTaskOrganizer.setPipVisibility(true);
+ }
+ }
+
+ private void onKeyguardDismissAnimationFinished() {
+ if (mPipTaskOrganizer.isInPip()) {
+ mIsKeyguardShowingOrAnimating = false;
+ mPipTaskOrganizer.setPipVisibility(true);
+ }
+ }
+
+ /**
* Sets a customized touch gesture that replaces the default one.
*/
public void setTouchGesture(PipTouchGesture gesture) {
@@ -623,7 +652,9 @@
* Sets both shelf visibility and its height.
*/
private void setShelfHeight(boolean visible, int height) {
- setShelfHeightLocked(visible, height);
+ if (!mIsKeyguardShowingOrAnimating) {
+ setShelfHeightLocked(visible, height);
+ }
}
private void setShelfHeightLocked(boolean visible, int height) {
@@ -854,13 +885,6 @@
}
@Override
- public void hidePipMenu(Runnable onStartCallback, Runnable onEndCallback) {
- mMainExecutor.execute(() -> {
- PipController.this.hidePipMenu(onStartCallback, onEndCallback);
- });
- }
-
- @Override
public void expandPip() {
mMainExecutor.execute(() -> {
PipController.this.expandPip();
@@ -938,6 +962,18 @@
}
@Override
+ public void onKeyguardVisibilityChanged(boolean showing, boolean animating) {
+ mMainExecutor.execute(() -> {
+ PipController.this.onKeyguardVisibilityChanged(showing, animating);
+ });
+ }
+
+ @Override
+ public void onKeyguardDismissAnimationFinished() {
+ mMainExecutor.execute(PipController.this::onKeyguardDismissAnimationFinished);
+ }
+
+ @Override
public void dump(PrintWriter pw) {
try {
mMainExecutor.executeBlocking(() -> {
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 6390c89..1958157 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
@@ -282,7 +282,7 @@
&& mSplitScreenControllerOptional.get().isTaskInSplitScreen(taskInfo.taskId);
mFocusedTaskAllowSplitScreen = isSplitScreen
|| (taskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN
- && taskInfo.supportsSplitScreenMultiWindow
+ && taskInfo.supportsMultiWindow
&& taskInfo.topActivityType != WindowConfiguration.ACTIVITY_TYPE_HOME);
}
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 21d5d40..a2eadcd 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
@@ -29,7 +29,6 @@
import android.content.res.Resources;
import android.graphics.Insets;
import android.graphics.Rect;
-import android.os.SystemClock;
import android.util.ArraySet;
import android.util.Size;
import android.view.Gravity;
@@ -66,7 +65,7 @@
@NonNull PipSnapAlgorithm pipSnapAlgorithm) {
super(context, tvPipBoundsState, pipSnapAlgorithm);
this.mTvPipBoundsState = tvPipBoundsState;
- this.mKeepClearAlgorithm = new TvPipKeepClearAlgorithm(SystemClock::uptimeMillis);
+ this.mKeepClearAlgorithm = new TvPipKeepClearAlgorithm();
reloadResources(context);
}
@@ -80,7 +79,6 @@
res.getDimensionPixelSize(R.dimen.pip_keep_clear_area_padding));
mKeepClearAlgorithm.setMaxRestrictedDistanceFraction(
res.getFraction(R.fraction.config_pipMaxRestrictedMoveDistance, 1, 1));
- mKeepClearAlgorithm.setStashDuration(res.getInteger(R.integer.config_pipStashDuration));
}
@Override
@@ -104,7 +102,7 @@
updateGravityOnExpandToggled(Gravity.NO_GRAVITY, true);
}
mTvPipBoundsState.setTvPipExpanded(isPipExpanded);
- return getTvPipBounds().getBounds();
+ return adjustBoundsForTemporaryDecor(getTvPipPlacement().getBounds());
}
/** Returns the current bounds adjusted to the new aspect ratio, if valid. */
@@ -114,13 +112,27 @@
ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
"%s: getAdjustedDestinationBounds: %f", TAG, newAspectRatio);
}
- return getTvPipBounds().getBounds();
+ return adjustBoundsForTemporaryDecor(getTvPipPlacement().getBounds());
+ }
+
+ Rect adjustBoundsForTemporaryDecor(Rect bounds) {
+ Rect boundsWithDecor = new Rect(bounds);
+ Insets decorInset = mTvPipBoundsState.getPipMenuTemporaryDecorInsets();
+ Insets pipDecorReverseInsets = Insets.subtract(Insets.NONE, decorInset);
+ boundsWithDecor.inset(decorInset);
+ Gravity.apply(mTvPipBoundsState.getTvPipGravity(),
+ boundsWithDecor.width(), boundsWithDecor.height(), bounds, boundsWithDecor);
+
+ // remove temporary decoration again
+ boundsWithDecor.inset(pipDecorReverseInsets);
+ return boundsWithDecor;
}
/**
* Calculates the PiP bounds.
*/
- public Placement getTvPipBounds() {
+ @NonNull
+ public Placement getTvPipPlacement() {
final Size pipSize = getPipSize();
final Rect displayBounds = mTvPipBoundsState.getDisplayBounds();
final Size screenSize = new Size(displayBounds.width(), displayBounds.height());
@@ -153,8 +165,6 @@
mKeepClearAlgorithm.setStashOffset(mTvPipBoundsState.getStashOffset());
mKeepClearAlgorithm.setPipPermanentDecorInsets(
mTvPipBoundsState.getPipMenuPermanentDecorInsets());
- mKeepClearAlgorithm.setPipTemporaryDecorInsets(
- mTvPipBoundsState.getPipMenuTemporaryDecorInsets());
final Placement placement = mKeepClearAlgorithm.calculatePipPosition(
pipSize,
@@ -407,8 +417,4 @@
TAG, expandedSize.getWidth(), expandedSize.getHeight());
}
}
-
- void keepUnstashedForCurrentKeepClearAreas() {
- mKeepClearAlgorithm.keepUnstashedForCurrentKeepClearAreas();
- }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsController.java
new file mode 100644
index 0000000..3a6ce81
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsController.java
@@ -0,0 +1,253 @@
+/*
+ * 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.tv;
+
+import static com.android.wm.shell.pip.PipBoundsState.STASH_TYPE_NONE;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Rect;
+import android.os.Handler;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.protolog.common.ProtoLog;
+import com.android.wm.shell.R;
+import com.android.wm.shell.pip.tv.TvPipKeepClearAlgorithm.Placement;
+import com.android.wm.shell.protolog.ShellProtoLogGroup;
+
+import java.util.Objects;
+import java.util.function.Supplier;
+
+/**
+ * Controller managing the PiP's position.
+ * Manages debouncing of PiP movements and scheduling of unstashing.
+ */
+public class TvPipBoundsController {
+ private static final boolean DEBUG = false;
+ private static final String TAG = "TvPipBoundsController";
+
+ /**
+ * Time the calculated PiP position needs to be stable before PiP is moved there,
+ * to avoid erratic movement.
+ * Some changes will cause the PiP to be repositioned immediately, such as changes to
+ * unrestricted keep clear areas.
+ */
+ @VisibleForTesting
+ static final long POSITION_DEBOUNCE_TIMEOUT_MILLIS = 300L;
+
+ private final Context mContext;
+ private final Supplier<Long> mClock;
+ private final Handler mMainHandler;
+ private final TvPipBoundsState mTvPipBoundsState;
+ private final TvPipBoundsAlgorithm mTvPipBoundsAlgorithm;
+
+ @Nullable
+ private PipBoundsListener mListener;
+
+ private int mResizeAnimationDuration;
+ private int mStashDurationMs;
+ private Rect mCurrentPlacementBounds;
+ private Rect mPipTargetBounds;
+
+ private final Runnable mApplyPendingPlacementRunnable = this::applyPendingPlacement;
+ private boolean mPendingStash;
+ private Placement mPendingPlacement;
+ private int mPendingPlacementAnimationDuration;
+ private Runnable mUnstashRunnable;
+
+ public TvPipBoundsController(
+ Context context,
+ Supplier<Long> clock,
+ Handler mainHandler,
+ TvPipBoundsState tvPipBoundsState,
+ TvPipBoundsAlgorithm tvPipBoundsAlgorithm) {
+ mContext = context;
+ mClock = clock;
+ mMainHandler = mainHandler;
+ mTvPipBoundsState = tvPipBoundsState;
+ mTvPipBoundsAlgorithm = tvPipBoundsAlgorithm;
+
+ loadConfigurations();
+ }
+
+ private void loadConfigurations() {
+ final Resources res = mContext.getResources();
+ mResizeAnimationDuration = res.getInteger(R.integer.config_pipResizeAnimationDuration);
+ mStashDurationMs = res.getInteger(R.integer.config_pipStashDuration);
+ }
+
+ void setListener(PipBoundsListener listener) {
+ mListener = listener;
+ }
+
+ /**
+ * Update the PiP bounds based on the state of the PiP, decors, and keep clear areas.
+ * Unless {@code immediate} is {@code true}, the PiP does not move immediately to avoid
+ * keep clear areas, but waits for a new position to stay uncontested for
+ * {@link #POSITION_DEBOUNCE_TIMEOUT_MILLIS} before moving to it.
+ * Temporary decor changes are applied immediately.
+ *
+ * @param stayAtAnchorPosition If true, PiP will be placed at the anchor position
+ * @param disallowStashing If true, PiP will not be placed off-screen in a stashed position
+ * @param animationDuration Duration of the animation to the new position
+ * @param immediate If true, PiP will move immediately to avoid keep clear areas
+ */
+ @VisibleForTesting
+ void recalculatePipBounds(boolean stayAtAnchorPosition, boolean disallowStashing,
+ int animationDuration, boolean immediate) {
+ final Placement placement = mTvPipBoundsAlgorithm.getTvPipPlacement();
+
+ final int stashType = disallowStashing ? STASH_TYPE_NONE : placement.getStashType();
+ mTvPipBoundsState.setStashed(stashType);
+ if (stayAtAnchorPosition) {
+ cancelScheduledPlacement();
+ applyPlacementBounds(placement.getAnchorBounds(), animationDuration);
+ } else if (disallowStashing) {
+ cancelScheduledPlacement();
+ applyPlacementBounds(placement.getUnstashedBounds(), animationDuration);
+ } else if (immediate) {
+ cancelScheduledPlacement();
+ applyPlacementBounds(placement.getBounds(), animationDuration);
+ scheduleUnstashIfNeeded(placement);
+ } else {
+ applyPlacementBounds(mCurrentPlacementBounds, animationDuration);
+ schedulePinnedStackPlacement(placement, animationDuration);
+ }
+ }
+
+ private void schedulePinnedStackPlacement(@NonNull final Placement placement,
+ int animationDuration) {
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: schedulePinnedStackPlacement() - pip bounds: %s",
+ TAG, placement.getBounds().toShortString());
+ }
+
+ if (mPendingPlacement != null && Objects.equals(mPendingPlacement.getBounds(),
+ placement.getBounds())) {
+ mPendingStash = mPendingStash || placement.getTriggerStash();
+ return;
+ }
+
+ mPendingStash = placement.getStashType() != STASH_TYPE_NONE
+ && (mPendingStash || placement.getTriggerStash());
+
+ mMainHandler.removeCallbacks(mApplyPendingPlacementRunnable);
+ mPendingPlacement = placement;
+ mPendingPlacementAnimationDuration = animationDuration;
+ mMainHandler.postAtTime(mApplyPendingPlacementRunnable,
+ mClock.get() + POSITION_DEBOUNCE_TIMEOUT_MILLIS);
+ }
+
+ private void scheduleUnstashIfNeeded(final Placement placement) {
+ if (mUnstashRunnable != null) {
+ mMainHandler.removeCallbacks(mUnstashRunnable);
+ mUnstashRunnable = null;
+ }
+ if (placement.getUnstashDestinationBounds() != null) {
+ mUnstashRunnable = () -> {
+ applyPlacementBounds(placement.getUnstashDestinationBounds(),
+ mResizeAnimationDuration);
+ mUnstashRunnable = null;
+ };
+ mMainHandler.postAtTime(mUnstashRunnable, mClock.get() + mStashDurationMs);
+ }
+ }
+
+ private void applyPendingPlacement() {
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: applyPendingPlacement()", TAG);
+ }
+ if (mPendingPlacement != null) {
+ if (mPendingStash) {
+ mPendingStash = false;
+ scheduleUnstashIfNeeded(mPendingPlacement);
+ }
+
+ if (mUnstashRunnable != null) {
+ // currently stashed, use stashed pos
+ applyPlacementBounds(mPendingPlacement.getBounds(),
+ mPendingPlacementAnimationDuration);
+ } else {
+ applyPlacementBounds(mPendingPlacement.getUnstashedBounds(),
+ mPendingPlacementAnimationDuration);
+ }
+ }
+
+ mPendingPlacement = null;
+ }
+
+ void onPipDismissed() {
+ mCurrentPlacementBounds = null;
+ mPipTargetBounds = null;
+ cancelScheduledPlacement();
+ }
+
+ private void cancelScheduledPlacement() {
+ mMainHandler.removeCallbacks(mApplyPendingPlacementRunnable);
+ mPendingPlacement = null;
+
+ if (mUnstashRunnable != null) {
+ mMainHandler.removeCallbacks(mUnstashRunnable);
+ mUnstashRunnable = null;
+ }
+ }
+
+ private void applyPlacementBounds(Rect bounds, int animationDuration) {
+ if (bounds == null) {
+ return;
+ }
+
+ mCurrentPlacementBounds = bounds;
+ Rect adjustedBounds = mTvPipBoundsAlgorithm.adjustBoundsForTemporaryDecor(bounds);
+ movePipTo(adjustedBounds, animationDuration);
+ }
+
+ /** Animates the PiP to the given bounds with the given animation duration. */
+ private void movePipTo(Rect bounds, int animationDuration) {
+ if (Objects.equals(mPipTargetBounds, bounds)) {
+ return;
+ }
+
+ mPipTargetBounds = bounds;
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: movePipTo() - new pip bounds: %s", TAG, bounds.toShortString());
+ }
+
+ if (mListener != null) {
+ mListener.onPipTargetBoundsChange(bounds, animationDuration);
+ }
+ }
+
+ /**
+ * Interface being notified of changes to the PiP bounds as calculated by
+ * @link TvPipBoundsController}.
+ */
+ public interface PipBoundsListener {
+ /**
+ * Called when the calculated PiP bounds are changing.
+ *
+ * @param newTargetBounds The new bounds of the PiP.
+ * @param animationDuration The animation duration for the PiP movement.
+ */
+ void onPipTargetBoundsChange(Rect newTargetBounds, int animationDuration);
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java
index 7667794..fa48def 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java
@@ -25,12 +25,10 @@
import android.app.PendingIntent;
import android.app.RemoteAction;
import android.app.TaskInfo;
-import android.content.ComponentName;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Rect;
-import android.os.Handler;
import android.os.RemoteException;
import android.view.Gravity;
@@ -46,25 +44,24 @@
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.pip.PipAnimationController;
import com.android.wm.shell.pip.PipAppOpsListener;
-import com.android.wm.shell.pip.PipBoundsState;
import com.android.wm.shell.pip.PipMediaController;
import com.android.wm.shell.pip.PipParamsChangedForwarder;
import com.android.wm.shell.pip.PipTaskOrganizer;
import com.android.wm.shell.pip.PipTransitionController;
-import com.android.wm.shell.pip.tv.TvPipKeepClearAlgorithm.Placement;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.List;
+import java.util.Objects;
import java.util.Set;
/**
* Manages the picture-in-picture (PIP) UI and states.
*/
public class TvPipController implements PipTransitionController.PipTransitionCallback,
- TvPipMenuController.Delegate, TvPipNotificationController.Delegate,
- DisplayController.OnDisplaysChangedListener {
+ TvPipBoundsController.PipBoundsListener, TvPipMenuController.Delegate,
+ TvPipNotificationController.Delegate, DisplayController.OnDisplaysChangedListener {
private static final String TAG = "TvPipController";
static final boolean DEBUG = false;
@@ -98,19 +95,18 @@
private final TvPipBoundsState mTvPipBoundsState;
private final TvPipBoundsAlgorithm mTvPipBoundsAlgorithm;
+ private final TvPipBoundsController mTvPipBoundsController;
private final PipAppOpsListener mAppOpsListener;
private final PipTaskOrganizer mPipTaskOrganizer;
private final PipMediaController mPipMediaController;
private final TvPipNotificationController mPipNotificationController;
private final TvPipMenuController mTvPipMenuController;
private final ShellExecutor mMainExecutor;
- private final Handler mMainHandler;
private final TvPipImpl mImpl = new TvPipImpl();
private @State int mState = STATE_NO_PIP;
private int mPreviousGravity = TvPipBoundsState.DEFAULT_TV_GRAVITY;
private int mPinnedTaskId = NONEXISTENT_TASK_ID;
- private Runnable mUnstashRunnable;
private RemoteAction mCloseAction;
// How long the shell will wait for the app to close the PiP if a custom action is set.
@@ -123,6 +119,7 @@
Context context,
TvPipBoundsState tvPipBoundsState,
TvPipBoundsAlgorithm tvPipBoundsAlgorithm,
+ TvPipBoundsController tvPipBoundsController,
PipAppOpsListener pipAppOpsListener,
PipTaskOrganizer pipTaskOrganizer,
PipTransitionController pipTransitionController,
@@ -133,12 +130,12 @@
PipParamsChangedForwarder pipParamsChangedForwarder,
DisplayController displayController,
WindowManagerShellWrapper wmShell,
- ShellExecutor mainExecutor,
- Handler mainHandler) {
+ ShellExecutor mainExecutor) {
return new TvPipController(
context,
tvPipBoundsState,
tvPipBoundsAlgorithm,
+ tvPipBoundsController,
pipAppOpsListener,
pipTaskOrganizer,
pipTransitionController,
@@ -149,14 +146,14 @@
pipParamsChangedForwarder,
displayController,
wmShell,
- mainExecutor,
- mainHandler).mImpl;
+ mainExecutor).mImpl;
}
private TvPipController(
Context context,
TvPipBoundsState tvPipBoundsState,
TvPipBoundsAlgorithm tvPipBoundsAlgorithm,
+ TvPipBoundsController tvPipBoundsController,
PipAppOpsListener pipAppOpsListener,
PipTaskOrganizer pipTaskOrganizer,
PipTransitionController pipTransitionController,
@@ -167,16 +164,16 @@
PipParamsChangedForwarder pipParamsChangedForwarder,
DisplayController displayController,
WindowManagerShellWrapper wmShell,
- ShellExecutor mainExecutor,
- Handler mainHandler) {
+ ShellExecutor mainExecutor) {
mContext = context;
mMainExecutor = mainExecutor;
- mMainHandler = mainHandler;
mTvPipBoundsState = tvPipBoundsState;
mTvPipBoundsState.setDisplayId(context.getDisplayId());
mTvPipBoundsState.setDisplayLayout(new DisplayLayout(context, context.getDisplay()));
mTvPipBoundsAlgorithm = tvPipBoundsAlgorithm;
+ mTvPipBoundsController = tvPipBoundsController;
+ mTvPipBoundsController.setListener(this);
mPipMediaController = pipMediaController;
@@ -227,7 +224,7 @@
/**
* Starts the process if bringing up the Pip menu if by issuing a command to move Pip
* task/window to the "Menu" position. We'll show the actual Menu UI (eg. actions) once the Pip
- * task/window is properly positioned in {@link #onPipTransitionFinished(ComponentName, int)}.
+ * task/window is properly positioned in {@link #onPipTransitionFinished(int)}.
*/
@Override
public void showPictureInPictureMenu() {
@@ -256,7 +253,6 @@
"%s: closeMenu(), state before=%s", TAG, stateToName(mState));
}
setState(STATE_PIP);
- mTvPipBoundsAlgorithm.keepUnstashedForCurrentKeepClearAreas();
updatePinnedStackBounds();
}
@@ -331,68 +327,35 @@
public void onKeepClearAreasChanged(int displayId, Set<Rect> restricted,
Set<Rect> unrestricted) {
if (mTvPipBoundsState.getDisplayId() == displayId) {
+ boolean unrestrictedAreasChanged = !Objects.equals(unrestricted,
+ mTvPipBoundsState.getUnrestrictedKeepClearAreas());
mTvPipBoundsState.setKeepClearAreas(restricted, unrestricted);
- updatePinnedStackBounds();
+ updatePinnedStackBounds(mResizeAnimationDuration, unrestrictedAreasChanged);
}
}
private void updatePinnedStackBounds() {
- updatePinnedStackBounds(mResizeAnimationDuration);
+ updatePinnedStackBounds(mResizeAnimationDuration, true);
}
/**
* Update the PiP bounds based on the state of the PiP and keep clear areas.
- * Animates to the current PiP bounds, and schedules unstashing the PiP if necessary.
*/
- private void updatePinnedStackBounds(int animationDuration) {
+ private void updatePinnedStackBounds(int animationDuration, boolean immediate) {
if (mState == STATE_NO_PIP) {
return;
}
-
final boolean stayAtAnchorPosition = mTvPipMenuController.isInMoveMode();
final boolean disallowStashing = mState == STATE_PIP_MENU || stayAtAnchorPosition;
- final Placement placement = mTvPipBoundsAlgorithm.getTvPipBounds();
-
- int stashType =
- disallowStashing ? PipBoundsState.STASH_TYPE_NONE : placement.getStashType();
- mTvPipBoundsState.setStashed(stashType);
-
- if (stayAtAnchorPosition) {
- movePinnedStackTo(placement.getAnchorBounds());
- } else if (disallowStashing) {
- movePinnedStackTo(placement.getUnstashedBounds());
- } else {
- movePinnedStackTo(placement.getBounds());
- }
-
- if (mUnstashRunnable != null) {
- mMainHandler.removeCallbacks(mUnstashRunnable);
- mUnstashRunnable = null;
- }
- if (!disallowStashing && placement.getUnstashDestinationBounds() != null) {
- mUnstashRunnable = () -> {
- movePinnedStackTo(placement.getUnstashDestinationBounds(), animationDuration);
- };
- mMainHandler.postAtTime(mUnstashRunnable, placement.getUnstashTime());
- }
+ mTvPipBoundsController.recalculatePipBounds(stayAtAnchorPosition, disallowStashing,
+ animationDuration, immediate);
}
- /** Animates the PiP to the given bounds. */
- private void movePinnedStackTo(Rect bounds) {
- movePinnedStackTo(bounds, mResizeAnimationDuration);
- }
-
- /** Animates the PiP to the given bounds with the given animation duration. */
- private void movePinnedStackTo(Rect bounds, int animationDuration) {
- if (DEBUG) {
- ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
- "%s: movePinnedStack() - new pip bounds: %s", TAG, bounds.toShortString());
- }
- mPipTaskOrganizer.scheduleAnimateResizePip(bounds,
- animationDuration, rect -> {
- mTvPipMenuController.updateExpansionState();
- });
- mTvPipMenuController.onPipTransitionStarted(bounds);
+ @Override
+ public void onPipTargetBoundsChange(Rect newTargetBounds, int animationDuration) {
+ mPipTaskOrganizer.scheduleAnimateResizePip(newTargetBounds,
+ animationDuration, rect -> mTvPipMenuController.updateExpansionState());
+ mTvPipMenuController.onPipTransitionStarted(newTargetBounds);
}
/**
@@ -431,7 +394,7 @@
@Override
public void closeEduText() {
- updatePinnedStackBounds(mEduTextWindowExitAnimationDurationMs);
+ updatePinnedStackBounds(mEduTextWindowExitAnimationDurationMs, false);
}
private void registerSessionListenerForCurrentUser() {
@@ -473,6 +436,7 @@
mPipNotificationController.dismiss();
mTvPipMenuController.closeMenu();
mTvPipBoundsState.resetTvPipState();
+ mTvPipBoundsController.onPipDismissed();
setState(STATE_NO_PIP);
mPinnedTaskId = NONEXISTENT_TASK_ID;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipKeepClearAlgorithm.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipKeepClearAlgorithm.kt
index 07dccd5..1e54436 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipKeepClearAlgorithm.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipKeepClearAlgorithm.kt
@@ -33,17 +33,14 @@
import kotlin.math.roundToInt
private const val DEFAULT_PIP_MARGINS = 48
-private const val DEFAULT_STASH_DURATION = 5000L
private const val RELAX_DEPTH = 1
private const val DEFAULT_MAX_RESTRICTED_DISTANCE_FRACTION = 0.15
/**
* This class calculates an appropriate position for a Picture-In-Picture (PiP) window, taking
* into account app defined keep clear areas.
- *
- * @param clock A function returning a current timestamp (in milliseconds)
*/
-class TvPipKeepClearAlgorithm(private val clock: () -> Long) {
+class TvPipKeepClearAlgorithm() {
/**
* Result of the positioning algorithm.
*
@@ -51,17 +48,17 @@
* @param anchorBounds The bounds of the PiP anchor position
* (where the PiP would be placed if there were no keep clear areas)
* @param stashType Where the PiP has been stashed, if at all
- * @param unstashDestinationBounds If stashed, the PiP should move to this position after
- * [stashDuration] has passed.
- * @param unstashTime If stashed, the time at which the PiP should move
- * to [unstashDestinationBounds]
+ * @param unstashDestinationBounds If stashed, the PiP should move to this position when
+ * unstashing.
+ * @param triggerStash Whether this placement should trigger the PiP to stash, or extend
+ * the unstash timeout if already stashed.
*/
data class Placement(
val bounds: Rect,
val anchorBounds: Rect,
@PipBoundsState.StashType val stashType: Int = STASH_TYPE_NONE,
val unstashDestinationBounds: Rect? = null,
- val unstashTime: Long = 0L
+ val triggerStash: Boolean = false
) {
/** Bounds to use if the PiP should not be stashed. */
fun getUnstashedBounds() = unstashDestinationBounds ?: bounds
@@ -79,12 +76,6 @@
/** The distance the PiP peeks into the screen when stashed */
var stashOffset = DEFAULT_PIP_MARGINS
- /**
- * How long (in milliseconds) the PiP should stay stashed for after the last time the
- * keep clear areas causing the PiP to stash have changed.
- */
- var stashDuration = DEFAULT_STASH_DURATION
-
/** The fraction of screen width/height restricted keep clear areas can move the PiP */
var maxRestrictedDistanceFraction = DEFAULT_MAX_RESTRICTED_DISTANCE_FRACTION
@@ -93,14 +84,10 @@
private var transformedMovementBounds = Rect()
private var lastAreasOverlappingUnstashPosition: Set<Rect> = emptySet()
- private var lastStashTime: Long = Long.MIN_VALUE
/** Spaces around the PiP that we should leave space for when placing the PiP. Permanent PiP
* decorations are relevant for calculating intersecting keep clear areas */
private var pipPermanentDecorInsets = Insets.NONE
- /** Spaces around the PiP that we should leave space for when placing the PiP. Temporary PiP
- * decorations are not relevant for calculating intersecting keep clear areas */
- private var pipTemporaryDecorInsets = Insets.NONE
/**
* Calculates the position the PiP should be placed at, taking into consideration the
@@ -113,8 +100,8 @@
* always try to respect these areas.
*
* If no free space the PiP is allowed to move to can be found, a stashed position is returned
- * as [Placement.bounds], along with a position to move to once [Placement.unstashTime] has
- * passed as [Placement.unstashDestinationBounds].
+ * as [Placement.bounds], along with a position to move to when the PiP unstashes
+ * as [Placement.unstashDestinationBounds].
*
* @param pipSize The size of the PiP window
* @param restrictedAreas The restricted keep clear areas
@@ -130,13 +117,11 @@
val transformedUnrestrictedAreas = transformAndFilterAreas(unrestrictedAreas)
val pipSizeWithAllDecors = addDecors(pipSize)
- val pipAnchorBoundsWithAllDecors =
+ val pipAnchorBoundsWithDecors =
getNormalPipAnchorBounds(pipSizeWithAllDecors, transformedMovementBounds)
- val pipAnchorBoundsWithPermanentDecors =
- removeTemporaryDecorsTransformed(pipAnchorBoundsWithAllDecors)
val result = calculatePipPositionTransformed(
- pipAnchorBoundsWithPermanentDecors,
+ pipAnchorBoundsWithDecors,
transformedRestrictedAreas,
transformedUnrestrictedAreas
)
@@ -152,7 +137,7 @@
anchorBounds,
getStashType(pipBounds, unstashedDestBounds),
unstashedDestBounds,
- result.unstashTime
+ result.triggerStash
)
}
@@ -213,26 +198,13 @@
!lastAreasOverlappingUnstashPosition.containsAll(areasOverlappingUnstashPosition)
lastAreasOverlappingUnstashPosition = areasOverlappingUnstashPosition
- val now = clock()
- if (areasOverlappingUnstashPositionChanged) {
- lastStashTime = now
- }
-
- // If overlapping areas haven't changed and the stash duration has passed, we can
- // place the PiP at the unstash position
- val unstashTime = lastStashTime + stashDuration
- if (now >= unstashTime) {
- return Placement(unstashBounds, pipAnchorBounds)
- }
-
- // Otherwise, we'll stash it close to the unstash position
val stashedBounds = getNearbyStashedPosition(unstashBounds, keepClearAreas)
return Placement(
stashedBounds,
pipAnchorBounds,
getStashType(stashedBounds, unstashBounds),
unstashBounds,
- unstashTime
+ areasOverlappingUnstashPositionChanged
)
}
@@ -439,14 +411,6 @@
}
/**
- * Prevents the PiP from being stashed for the current set of keep clear areas.
- * The PiP may stash again if keep clear areas change.
- */
- fun keepUnstashedForCurrentKeepClearAreas() {
- lastStashTime = Long.MIN_VALUE
- }
-
- /**
* Updates the size of the screen.
*
* @param size The new size of the screen
@@ -492,10 +456,6 @@
pipPermanentDecorInsets = insets
}
- fun setPipTemporaryDecorInsets(insets: Insets) {
- pipTemporaryDecorInsets = insets
- }
-
/**
* @param open Whether this event marks the opening of an occupied segment
* @param pos The coordinate of this event
@@ -790,7 +750,6 @@
private fun addDecors(size: Size): Size {
val bounds = Rect(0, 0, size.width, size.height)
bounds.inset(pipPermanentDecorInsets)
- bounds.inset(pipTemporaryDecorInsets)
return Size(bounds.width(), bounds.height())
}
@@ -805,19 +764,6 @@
return bounds
}
- /**
- * Removes the space that was reserved for temporary decorations around the PiP
- * @param bounds the bounds (in base case) to remove the insets from
- */
- private fun removeTemporaryDecorsTransformed(bounds: Rect): Rect {
- if (pipTemporaryDecorInsets == Insets.NONE) return bounds
-
- val reverseInsets = Insets.subtract(Insets.NONE, pipTemporaryDecorInsets)
- val boundsInScreenSpace = fromTransformedSpace(bounds)
- boundsInScreenSpace.inset(reverseInsets)
- return toTransformedSpace(boundsInScreenSpace)
- }
-
private fun Rect.offsetCopy(dx: Int, dy: Int) = Rect(this).apply { offset(dx, dy) }
private fun Rect.intersectsX(other: Rect) = right >= other.left && left <= other.right
private fun Rect.intersectsY(other: Rect) = bottom >= other.top && top <= other.bottom
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java
index 132c044..4ce45e1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java
@@ -209,7 +209,7 @@
ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
"%s: showMovementMenuOnly()", TAG);
}
- mInMoveMode = true;
+ setInMoveMode(true);
mCloseAfterExitMoveMenu = true;
showMenuInternal();
}
@@ -219,7 +219,7 @@
if (DEBUG) {
ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, "%s: showMenu()", TAG);
}
- mInMoveMode = false;
+ setInMoveMode(false);
mCloseAfterExitMoveMenu = false;
showMenuInternal();
}
@@ -293,6 +293,17 @@
return mInMoveMode;
}
+ private void setInMoveMode(boolean moveMode) {
+ if (mInMoveMode == moveMode) {
+ return;
+ }
+
+ mInMoveMode = moveMode;
+ if (mDelegate != null) {
+ mDelegate.onInMoveModeChanged();
+ }
+ }
+
@Override
public void onEnterMoveMode() {
if (DEBUG) {
@@ -300,7 +311,7 @@
"%s: onEnterMoveMode - %b, close when exiting move menu: %b", TAG, mInMoveMode,
mCloseAfterExitMoveMenu);
}
- mInMoveMode = true;
+ setInMoveMode(true);
mPipMenuView.showMoveMenu(mDelegate.getPipGravity());
}
@@ -312,13 +323,13 @@
mCloseAfterExitMoveMenu);
}
if (mCloseAfterExitMoveMenu) {
- mInMoveMode = false;
+ setInMoveMode(false);
mCloseAfterExitMoveMenu = false;
closeMenu();
return true;
}
if (mInMoveMode) {
- mInMoveMode = false;
+ setInMoveMode(false);
mPipMenuView.showButtonsMenu();
return true;
}
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 6274d6f..5671fec 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
@@ -83,6 +83,7 @@
import android.view.SurfaceControl;
import android.view.SurfaceSession;
import android.view.WindowManager;
+import android.window.DisplayAreaInfo;
import android.window.RemoteTransition;
import android.window.TransitionInfo;
import android.window.TransitionRequestInfo;
@@ -980,6 +981,9 @@
updateUnfoldBounds();
return;
}
+ // Clear the divider remote animating flag as the divider will be re-rendered to apply
+ // the new rotation config.
+ mIsDividerRemoteAnimating = false;
mSplitLayout.update(null /* t */);
onLayoutSizeChanged(mSplitLayout);
}
@@ -1112,7 +1116,7 @@
final SurfaceControl.Transaction transaction = mTransactionPool.acquire();
mDividerFadeInAnimator = ValueAnimator.ofFloat(0f, 1f);
mDividerFadeInAnimator.addUpdateListener(animation -> {
- if (dividerLeash == null) {
+ if (dividerLeash == null || !dividerLeash.isValid()) {
mDividerFadeInAnimator.cancel();
return;
}
@@ -1122,7 +1126,7 @@
mDividerFadeInAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
- if (dividerLeash == null) {
+ if (dividerLeash == null || !dividerLeash.isValid()) {
mDividerFadeInAnimator.cancel();
return;
}
@@ -1315,7 +1319,7 @@
if (displayId != DEFAULT_DISPLAY) {
return;
}
- mDisplayController.addDisplayChangingController(this::onRotateDisplay);
+ mDisplayController.addDisplayChangingController(this::onDisplayChange);
}
@Override
@@ -1326,14 +1330,17 @@
mDisplayLayout.set(mDisplayController.getDisplayLayout(displayId));
}
- private void onRotateDisplay(int displayId, int fromRotation, int toRotation,
- WindowContainerTransaction wct) {
+ private void onDisplayChange(int displayId, int fromRotation, int toRotation,
+ @Nullable DisplayAreaInfo newDisplayAreaInfo, WindowContainerTransaction wct) {
if (!mMainStage.isActive()) return;
// Only do this when shell transition
if (!ENABLE_SHELL_TRANSITIONS) return;
mDisplayLayout.rotateTo(mContext.getResources(), toRotation);
mSplitLayout.rotateTo(toRotation, mDisplayLayout.stableInsets());
+ if (newDisplayAreaInfo != null) {
+ mSplitLayout.updateConfiguration(newDisplayAreaInfo.configuration);
+ }
updateWindowBounds(mSplitLayout, wct);
updateUnfoldBounds();
}
@@ -1441,8 +1448,9 @@
// Enter overview panel, so start recent transition.
mSplitTransitions.setRecentTransition(transition,
request.getRemoteTransition());
- } else {
- // Occluded by the other fullscreen task, so dismiss both.
+ } else if (mSplitTransitions.mPendingRecent == null) {
+ // If split-task is not controlled by recents animation
+ // and occluded by the other fullscreen task, dismiss both.
prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, out);
mSplitTransitions.setDismissTransition(transition,
STAGE_TYPE_UNDEFINED, EXIT_REASON_UNKNOWN);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
index d89ddd2..8cee4f1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
@@ -35,6 +35,8 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
@@ -53,6 +55,7 @@
import android.os.Trace;
import android.os.UserHandle;
import android.util.ArrayMap;
+import android.util.DisplayMetrics;
import android.util.Slog;
import android.view.ContextThemeWrapper;
import android.view.SurfaceControl;
@@ -68,7 +71,6 @@
import com.android.internal.protolog.common.ProtoLog;
import com.android.launcher3.icons.BaseIconFactory;
import com.android.launcher3.icons.IconProvider;
-import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
@@ -102,7 +104,7 @@
*/
private static final float NO_BACKGROUND_SCALE = 192f / 160;
private final Context mContext;
- private final IconProvider mIconProvider;
+ private final HighResIconProvider mHighResIconProvider;
private int mIconSize;
private int mDefaultIconSize;
@@ -115,12 +117,10 @@
private final Handler mSplashscreenWorkerHandler;
@VisibleForTesting
final ColorCache mColorCache;
- private final ShellExecutor mSplashScreenExecutor;
- SplashscreenContentDrawer(Context context, IconProvider iconProvider, TransactionPool pool,
- ShellExecutor splashScreenExecutor) {
+ SplashscreenContentDrawer(Context context, IconProvider iconProvider, TransactionPool pool) {
mContext = context;
- mIconProvider = iconProvider;
+ mHighResIconProvider = new HighResIconProvider(mContext, iconProvider);
mTransactionPool = pool;
// Initialize Splashscreen worker thread
@@ -131,7 +131,6 @@
shellSplashscreenWorkerThread.start();
mSplashscreenWorkerHandler = shellSplashscreenWorkerThread.getThreadHandler();
mColorCache = new ColorCache(mContext, mSplashscreenWorkerHandler);
- mSplashScreenExecutor = splashScreenExecutor;
}
/**
@@ -416,18 +415,16 @@
|| mTmpAttrs.mIconBgColor == mThemeColor) {
mFinalIconSize *= NO_BACKGROUND_SCALE;
}
- createIconDrawable(iconDrawable, false);
+ createIconDrawable(iconDrawable, false /* legacy */, false /* loadInDetail */);
} else {
final float iconScale = (float) mIconSize / (float) mDefaultIconSize;
final int densityDpi = mContext.getResources().getConfiguration().densityDpi;
final int scaledIconDpi =
(int) (0.5f + iconScale * densityDpi * NO_BACKGROUND_SCALE);
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "getIcon");
- iconDrawable = mIconProvider.getIcon(mActivityInfo, scaledIconDpi);
+ iconDrawable = mHighResIconProvider.getIcon(
+ mActivityInfo, densityDpi, scaledIconDpi);
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
- if (iconDrawable == null) {
- iconDrawable = mContext.getPackageManager().getDefaultActivityIcon();
- }
if (!processAdaptiveIcon(iconDrawable)) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_STARTING_WINDOW,
"The icon is not an AdaptiveIconDrawable");
@@ -437,7 +434,8 @@
scaledIconDpi, mFinalIconSize);
final Bitmap bitmap = factory.createScaledBitmapWithoutShadow(iconDrawable);
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
- createIconDrawable(new BitmapDrawable(bitmap), true);
+ createIconDrawable(new BitmapDrawable(bitmap), true,
+ mHighResIconProvider.mLoadInDetail);
}
}
@@ -450,14 +448,16 @@
}
}
- private void createIconDrawable(Drawable iconDrawable, boolean legacy) {
+ private void createIconDrawable(Drawable iconDrawable, boolean legacy,
+ boolean loadInDetail) {
if (legacy) {
mFinalIconDrawables = SplashscreenIconDrawableFactory.makeLegacyIconDrawable(
- iconDrawable, mDefaultIconSize, mFinalIconSize, mSplashscreenWorkerHandler);
+ iconDrawable, mDefaultIconSize, mFinalIconSize, loadInDetail,
+ mSplashscreenWorkerHandler);
} else {
mFinalIconDrawables = SplashscreenIconDrawableFactory.makeIconDrawable(
mTmpAttrs.mIconBgColor, mThemeColor, iconDrawable, mDefaultIconSize,
- mFinalIconSize, mSplashscreenWorkerHandler);
+ mFinalIconSize, loadInDetail, mSplashscreenWorkerHandler);
}
}
@@ -506,11 +506,11 @@
// Using AdaptiveIconDrawable here can help keep the shape consistent with the
// current settings.
mFinalIconSize = (int) (0.5f + mIconSize * noBgScale);
- createIconDrawable(iconForeground, false);
+ createIconDrawable(iconForeground, false, mHighResIconProvider.mLoadInDetail);
} else {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_STARTING_WINDOW,
"processAdaptiveIcon: draw whole icon");
- createIconDrawable(iconDrawable, false);
+ createIconDrawable(iconDrawable, false, mHighResIconProvider.mLoadInDetail);
}
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
return true;
@@ -1015,4 +1015,77 @@
playAnimation.run();
}
}
+
+ /**
+ * When loading a BitmapDrawable object with specific density, there will decode the image based
+ * on the density from display metrics, so even when load with higher override density, the
+ * final intrinsic size of a BitmapDrawable can still not big enough to draw on expect size.
+ *
+ * So here we use a standalone IconProvider object to load the Drawable object for higher
+ * density, and the resources object won't affect the entire system.
+ *
+ */
+ private static class HighResIconProvider {
+ private final Context mSharedContext;
+ private final IconProvider mSharedIconProvider;
+ private boolean mLoadInDetail;
+
+ // only create standalone icon provider when the density dpi is low.
+ private Context mStandaloneContext;
+ private IconProvider mStandaloneIconProvider;
+
+ HighResIconProvider(Context context, IconProvider sharedIconProvider) {
+ mSharedContext = context;
+ mSharedIconProvider = sharedIconProvider;
+ }
+
+ Drawable getIcon(ActivityInfo activityInfo, int currentDpi, int iconDpi) {
+ mLoadInDetail = false;
+ Drawable drawable;
+ if (currentDpi < iconDpi && currentDpi < DisplayMetrics.DENSITY_XHIGH) {
+ drawable = loadFromStandalone(activityInfo, currentDpi, iconDpi);
+ } else {
+ drawable = mSharedIconProvider.getIcon(activityInfo, iconDpi);
+ }
+
+ if (drawable == null) {
+ drawable = mSharedContext.getPackageManager().getDefaultActivityIcon();
+ }
+ return drawable;
+ }
+
+ private Drawable loadFromStandalone(ActivityInfo activityInfo, int currentDpi,
+ int iconDpi) {
+ if (mStandaloneContext == null) {
+ final Configuration defConfig = mSharedContext.getResources().getConfiguration();
+ mStandaloneContext = mSharedContext.createConfigurationContext(defConfig);
+ mStandaloneIconProvider = new IconProvider(mStandaloneContext);
+ }
+ Resources resources;
+ try {
+ resources = mStandaloneContext.getPackageManager()
+ .getResourcesForApplication(activityInfo.applicationInfo);
+ } catch (PackageManager.NameNotFoundException | Resources.NotFoundException exc) {
+ resources = null;
+ }
+ if (resources != null) {
+ updateResourcesDpi(resources, iconDpi);
+ }
+ final Drawable drawable = mStandaloneIconProvider.getIcon(activityInfo, iconDpi);
+ mLoadInDetail = true;
+ // reset density dpi
+ if (resources != null) {
+ updateResourcesDpi(resources, currentDpi);
+ }
+ return drawable;
+ }
+
+ private void updateResourcesDpi(Resources resources, int densityDpi) {
+ final Configuration config = resources.getConfiguration();
+ final DisplayMetrics displayMetrics = resources.getDisplayMetrics();
+ config.densityDpi = densityDpi;
+ displayMetrics.densityDpi = densityDpi;
+ resources.updateConfiguration(config, displayMetrics);
+ }
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java
index 5f52071..7f6bfd2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java
@@ -62,7 +62,7 @@
*/
static Drawable[] makeIconDrawable(@ColorInt int backgroundColor, @ColorInt int themeColor,
@NonNull Drawable foregroundDrawable, int srcIconSize, int iconSize,
- Handler splashscreenWorkerHandler) {
+ boolean loadInDetail, Handler splashscreenWorkerHandler) {
Drawable foreground;
Drawable background = null;
boolean drawBackground =
@@ -74,13 +74,13 @@
// If the icon is Adaptive, we already use the icon background.
drawBackground = false;
foreground = new ImmobileIconDrawable(foregroundDrawable,
- srcIconSize, iconSize, splashscreenWorkerHandler);
+ srcIconSize, iconSize, loadInDetail, splashscreenWorkerHandler);
} else {
// Adaptive icon don't handle transparency so we draw the background of the adaptive
// icon with the same color as the window background color instead of using two layers
foreground = new ImmobileIconDrawable(
new AdaptiveForegroundDrawable(foregroundDrawable),
- srcIconSize, iconSize, splashscreenWorkerHandler);
+ srcIconSize, iconSize, loadInDetail, splashscreenWorkerHandler);
}
if (drawBackground) {
@@ -91,9 +91,9 @@
}
static Drawable[] makeLegacyIconDrawable(@NonNull Drawable iconDrawable, int srcIconSize,
- int iconSize, Handler splashscreenWorkerHandler) {
+ int iconSize, boolean loadInDetail, Handler splashscreenWorkerHandler) {
return new Drawable[]{new ImmobileIconDrawable(iconDrawable, srcIconSize, iconSize,
- splashscreenWorkerHandler)};
+ loadInDetail, splashscreenWorkerHandler)};
}
/**
@@ -106,11 +106,16 @@
private final Matrix mMatrix = new Matrix();
private Bitmap mIconBitmap;
- ImmobileIconDrawable(Drawable drawable, int srcIconSize, int iconSize,
+ ImmobileIconDrawable(Drawable drawable, int srcIconSize, int iconSize, boolean loadInDetail,
Handler splashscreenWorkerHandler) {
- final float scale = (float) iconSize / srcIconSize;
- mMatrix.setScale(scale, scale);
- splashscreenWorkerHandler.post(() -> preDrawIcon(drawable, srcIconSize));
+ // This icon has lower density, don't scale it.
+ if (loadInDetail) {
+ splashscreenWorkerHandler.post(() -> preDrawIcon(drawable, iconSize));
+ } else {
+ final float scale = (float) iconSize / srcIconSize;
+ mMatrix.setScale(scale, scale);
+ splashscreenWorkerHandler.post(() -> preDrawIcon(drawable, srcIconSize));
+ }
}
private void preDrawIcon(Drawable drawable, int size) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
index 464ab1a..54d62ed 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
@@ -153,8 +153,7 @@
mContext = context;
mDisplayManager = mContext.getSystemService(DisplayManager.class);
mSplashScreenExecutor = splashScreenExecutor;
- mSplashscreenContentDrawer = new SplashscreenContentDrawer(mContext, iconProvider, pool,
- mSplashScreenExecutor);
+ mSplashscreenContentDrawer = new SplashscreenContentDrawer(mContext, iconProvider, pool);
mSplashScreenExecutor.execute(() -> mChoreographer = Choreographer.getInstance());
mWindowManagerGlobal = WindowManagerGlobal.getInstance();
mDisplayManager.getDisplay(DEFAULT_DISPLAY);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
index 98eee7b..de0f47f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
@@ -23,6 +23,7 @@
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
+import static android.window.TransitionInfo.FLAG_IS_INPUT_METHOD;
import static android.window.TransitionInfo.FLAG_IS_WALLPAPER;
import static android.window.TransitionInfo.FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT;
@@ -287,12 +288,14 @@
finishT.setAlpha(leash, 1.f);
}
} else if (mode == TRANSIT_CLOSE || mode == TRANSIT_TO_BACK) {
- // Wallpaper is a bit of an anomaly: it's visibility is tied to other WindowStates.
- // As a result, we actually can't hide it's WindowToken because there may not be a
- // transition associated with it becoming visible again. Fortunately, since it is
- // always z-ordered to the back, we don't have to worry about it flickering to the
- // front during reparenting, so the hide here isn't necessary for it.
- if ((change.getFlags() & FLAG_IS_WALLPAPER) == 0) {
+ // Wallpaper/IME are anomalies: their visibility is tied to other WindowStates.
+ // As a result, we actually can't hide their WindowTokens because there may not be a
+ // transition associated with them becoming visible again. Fortunately, since
+ // wallpapers are always z-ordered to the back, we don't have to worry about it
+ // flickering to the front during reparenting. Similarly, the IME is reparented to
+ // the associated app, so its visibility is coupled. So, an explicit hide is not
+ // needed visually anyways.
+ if ((change.getFlags() & (FLAG_IS_WALLPAPER | FLAG_IS_INPUT_METHOD)) == 0) {
finishT.hide(leash);
}
}
@@ -309,13 +312,14 @@
if (info.getRootLeash().isValid()) {
t.show(info.getRootLeash());
}
+ final int numChanges = info.getChanges().size();
// Put animating stuff above this line and put static stuff below it.
- int zSplitLine = info.getChanges().size();
+ final int zSplitLine = numChanges + 1;
// changes should be ordered top-to-bottom in z
- for (int i = info.getChanges().size() - 1; i >= 0; --i) {
+ for (int i = numChanges - 1; i >= 0; --i) {
final TransitionInfo.Change change = info.getChanges().get(i);
final SurfaceControl leash = change.getLeash();
- final int mode = info.getChanges().get(i).getMode();
+ final int mode = change.getMode();
// Don't reparent anything that isn't independent within its parents
if (!TransitionInfo.isIndependent(change, info)) {
@@ -329,26 +333,31 @@
t.setPosition(leash, change.getStartAbsBounds().left - info.getRootOffset().x,
change.getStartAbsBounds().top - info.getRootOffset().y);
}
+ final int layer;
// Put all the OPEN/SHOW on top
- if (mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT) {
+ if ((change.getFlags() & FLAG_IS_WALLPAPER) != 0) {
+ // Wallpaper is always at the bottom.
+ layer = 0;
+ } else if (mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT) {
if (isOpening) {
// put on top
- t.setLayer(leash, zSplitLine + info.getChanges().size() - i);
+ layer = zSplitLine + numChanges - i;
} else {
// put on bottom
- t.setLayer(leash, zSplitLine - i);
+ layer = zSplitLine - i;
}
} else if (mode == TRANSIT_CLOSE || mode == TRANSIT_TO_BACK) {
if (isOpening) {
// put on bottom and leave visible
- t.setLayer(leash, zSplitLine - i);
+ layer = zSplitLine - i;
} else {
// put on top
- t.setLayer(leash, zSplitLine + info.getChanges().size() - i);
+ layer = zSplitLine + numChanges - i;
}
} else { // CHANGE or other
- t.setLayer(leash, zSplitLine + info.getChanges().size() - i);
+ layer = zSplitLine + numChanges - i;
}
+ t.setLayer(leash, layer);
}
}
@@ -626,8 +635,9 @@
if (wct == null) {
wct = new WindowContainerTransaction();
}
- mDisplayController.getChangeController().dispatchOnRotateDisplay(wct,
- change.getDisplayId(), change.getStartRotation(), change.getEndRotation());
+ mDisplayController.getChangeController().dispatchOnDisplayChange(wct,
+ change.getDisplayId(), change.getStartRotation(), change.getEndRotation(),
+ null /* newDisplayAreaInfo */);
}
}
active.mToken = mOrganizer.startTransition(
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java
index af78f2d..8e45e7d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java
@@ -127,7 +127,8 @@
@Override
public WindowContainerTransaction handleRequest(@NonNull IBinder transition,
@NonNull TransitionRequestInfo request) {
- if (request.getType() == TRANSIT_CHANGE && request.getDisplayChange() != null) {
+ if (request.getType() == TRANSIT_CHANGE && request.getDisplayChange() != null
+ && request.getDisplayChange().isPhysicalDisplayChanged()) {
mTransition = transition;
return new WindowContainerTransaction();
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt
deleted file mode 100644
index c9cab39..0000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt
+++ /dev/null
@@ -1,115 +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.wm.shell.flicker.apppairs
-
-import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.annotation.Group1
-import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.wm.shell.flicker.appPairsDividerIsInvisibleAtEnd
-import com.android.wm.shell.flicker.helpers.AppPairsHelper
-import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.resetMultiWindowConfig
-import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.setSupportsNonResizableMultiWindow
-import org.junit.After
-import org.junit.Before
-import org.junit.FixMethodOrder
-import org.junit.Ignore
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/**
- * Test cold launch app from launcher. When the device doesn't support non-resizable in multi window
- * {@link Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW}, app pairs should not pair
- * non-resizable apps.
- *
- * To run this test: `atest WMShellFlickerTests:AppPairsTestCannotPairNonResizeableApps`
- */
-@RequiresDevice
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Group1
-class AppPairsTestCannotPairNonResizeableApps(
- testSpec: FlickerTestParameter
-) : AppPairsTransition(testSpec) {
-
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- super.transition(this)
- transitions {
- nonResizeableApp?.launchViaIntent(wmHelper)
- // TODO pair apps through normal UX flow
- executeShellCommand(
- composePairsCommand(primaryTaskId, nonResizeableTaskId, pair = true))
- nonResizeableApp?.run { wmHelper.waitForFullScreenApp(nonResizeableApp.component) }
- }
- }
-
- @Before
- override fun setup() {
- super.setup()
- setSupportsNonResizableMultiWindow(instrumentation, -1)
- }
-
- @After
- override fun teardown() {
- super.teardown()
- resetMultiWindowConfig(instrumentation)
- }
-
- @Ignore
- @Test
- override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
-
- @Ignore
- @Test
- override fun statusBarLayerRotatesScales() = super.statusBarLayerRotatesScales()
-
- @Ignore
- @Test
- override fun navBarLayerIsVisible() = super.navBarLayerIsVisible()
-
- @Ignore
- @Test
- fun appPairsDividerIsInvisibleAtEnd() = testSpec.appPairsDividerIsInvisibleAtEnd()
-
- @Ignore
- @Test
- fun onlyResizeableAppWindowVisible() {
- val nonResizeableApp = nonResizeableApp
- require(nonResizeableApp != null) {
- "Non resizeable app not initialized"
- }
- testSpec.assertWmEnd {
- isAppWindowVisible(nonResizeableApp.component)
- isAppWindowInvisible(primaryApp.component)
- }
- }
-
- companion object {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): List<FlickerTestParameter> {
- return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
- repetitions = AppPairsHelper.TEST_REPETITIONS)
- }
- }
-}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestPairPrimaryAndSecondaryApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestPairPrimaryAndSecondaryApps.kt
deleted file mode 100644
index 60c32c99..0000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestPairPrimaryAndSecondaryApps.kt
+++ /dev/null
@@ -1,104 +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.wm.shell.flicker.apppairs
-
-import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.annotation.Group1
-import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.wm.shell.flicker.APP_PAIR_SPLIT_DIVIDER_COMPONENT
-import com.android.wm.shell.flicker.appPairsDividerIsVisibleAtEnd
-import com.android.wm.shell.flicker.helpers.AppPairsHelper
-import com.android.wm.shell.flicker.helpers.AppPairsHelper.Companion.waitAppsShown
-import org.junit.FixMethodOrder
-import org.junit.Ignore
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/**
- * Test cold launch app from launcher.
- * To run this test: `atest WMShellFlickerTests:AppPairsTestPairPrimaryAndSecondaryApps`
- */
-@RequiresDevice
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Group1
-class AppPairsTestPairPrimaryAndSecondaryApps(
- testSpec: FlickerTestParameter
-) : AppPairsTransition(testSpec) {
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- super.transition(this)
- transitions {
- // TODO pair apps through normal UX flow
- executeShellCommand(
- composePairsCommand(primaryTaskId, secondaryTaskId, pair = true))
- waitAppsShown(primaryApp, secondaryApp)
- }
- }
-
- @Ignore
- @Test
- override fun navBarLayerIsVisible() = super.navBarLayerIsVisible()
-
- @Ignore
- @Test
- override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
-
- @Ignore
- @Test
- override fun statusBarLayerRotatesScales() = super.statusBarLayerRotatesScales()
-
- @Ignore
- @Test
- fun appPairsDividerIsVisibleAtEnd() = testSpec.appPairsDividerIsVisibleAtEnd()
-
- @Ignore
- @Test
- fun bothAppWindowsVisible() {
- testSpec.assertWmEnd {
- isAppWindowVisible(primaryApp.component)
- isAppWindowVisible(secondaryApp.component)
- }
- }
-
- @Ignore
- @Test
- fun appsEndingBounds() {
- testSpec.assertLayersEnd {
- val dividerRegion = layer(APP_PAIR_SPLIT_DIVIDER_COMPONENT).visibleRegion.region
- visibleRegion(primaryApp.component)
- .coversExactly(appPairsHelper.getPrimaryBounds(dividerRegion))
- visibleRegion(secondaryApp.component)
- .coversExactly(appPairsHelper.getSecondaryBounds(dividerRegion))
- }
- }
-
- companion object {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): List<FlickerTestParameter> {
- return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
- repetitions = AppPairsHelper.TEST_REPETITIONS)
- }
- }
-}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestSupportPairNonResizeableApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestSupportPairNonResizeableApps.kt
deleted file mode 100644
index 24869a8..0000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestSupportPairNonResizeableApps.kt
+++ /dev/null
@@ -1,128 +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.wm.shell.flicker.apppairs
-
-import android.view.Display
-import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.annotation.Group1
-import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.traces.common.WindowManagerConditionsFactory
-import com.android.wm.shell.flicker.appPairsDividerIsVisibleAtEnd
-import com.android.wm.shell.flicker.helpers.AppPairsHelper
-import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.resetMultiWindowConfig
-import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.setSupportsNonResizableMultiWindow
-import org.junit.After
-import org.junit.Before
-import org.junit.FixMethodOrder
-import org.junit.Ignore
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/**
- * Test cold launch app from launcher. When the device supports non-resizable in multi window
- * {@link Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW}, app pairs can pair
- * non-resizable apps.
- *
- * To run this test: `atest WMShellFlickerTests:AppPairsTestSupportPairNonResizeableApps`
- */
-@RequiresDevice
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Group1
-class AppPairsTestSupportPairNonResizeableApps(
- testSpec: FlickerTestParameter
-) : AppPairsTransition(testSpec) {
-
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- super.transition(this)
- transitions {
- nonResizeableApp?.launchViaIntent(wmHelper)
- // TODO pair apps through normal UX flow
- executeShellCommand(
- composePairsCommand(primaryTaskId, nonResizeableTaskId, pair = true))
- val waitConditions = mutableListOf(
- WindowManagerConditionsFactory.isWindowVisible(primaryApp.component),
- WindowManagerConditionsFactory.isLayerVisible(primaryApp.component),
- WindowManagerConditionsFactory.isAppTransitionIdle(Display.DEFAULT_DISPLAY))
-
- nonResizeableApp?.let {
- waitConditions.add(
- WindowManagerConditionsFactory.isWindowVisible(nonResizeableApp.component))
- waitConditions.add(
- WindowManagerConditionsFactory.isLayerVisible(nonResizeableApp.component))
- }
- wmHelper.waitFor(*waitConditions.toTypedArray())
- }
- }
-
- @Before
- override fun setup() {
- super.setup()
- setSupportsNonResizableMultiWindow(instrumentation, 1)
- }
-
- @After
- override fun teardown() {
- super.teardown()
- resetMultiWindowConfig(instrumentation)
- }
-
- @Ignore
- @Test
- override fun navBarLayerIsVisible() = super.navBarLayerIsVisible()
-
- @Ignore
- @Test
- override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
-
- @Ignore
- @Test
- override fun statusBarLayerRotatesScales() = super.statusBarLayerRotatesScales()
-
- @Ignore
- @Test
- fun appPairsDividerIsVisibleAtEnd() = testSpec.appPairsDividerIsVisibleAtEnd()
-
- @Ignore
- @Test
- fun bothAppWindowVisible() {
- val nonResizeableApp = nonResizeableApp
- require(nonResizeableApp != null) {
- "Non resizeable app not initialized"
- }
- testSpec.assertWmEnd {
- isAppWindowVisible(nonResizeableApp.component)
- isAppWindowVisible(primaryApp.component)
- }
- }
-
- companion object {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): List<FlickerTestParameter> {
- return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
- repetitions = AppPairsHelper.TEST_REPETITIONS)
- }
- }
-}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt
deleted file mode 100644
index 007415d..0000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt
+++ /dev/null
@@ -1,121 +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.wm.shell.flicker.apppairs
-
-import android.os.SystemClock
-import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.annotation.Group1
-import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.wm.shell.flicker.APP_PAIR_SPLIT_DIVIDER_COMPONENT
-import com.android.wm.shell.flicker.appPairsDividerIsInvisibleAtEnd
-import com.android.wm.shell.flicker.helpers.AppPairsHelper
-import com.android.wm.shell.flicker.helpers.AppPairsHelper.Companion.waitAppsShown
-import org.junit.FixMethodOrder
-import org.junit.Ignore
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/**
- * Test cold launch app from launcher.
- * To run this test: `atest WMShellFlickerTests:AppPairsTestUnpairPrimaryAndSecondaryApps`
- */
-@RequiresDevice
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Group1
-class AppPairsTestUnpairPrimaryAndSecondaryApps(
- testSpec: FlickerTestParameter
-) : AppPairsTransition(testSpec) {
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- super.transition(this)
- setup {
- eachRun {
- executeShellCommand(
- composePairsCommand(primaryTaskId, secondaryTaskId, pair = true))
- waitAppsShown(primaryApp, secondaryApp)
- }
- }
- transitions {
- // TODO pair apps through normal UX flow
- executeShellCommand(
- composePairsCommand(primaryTaskId, secondaryTaskId, pair = false))
- SystemClock.sleep(AppPairsHelper.TIMEOUT_MS)
- }
- }
-
- @Ignore
- @Test
- override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
-
- @Ignore
- @Test
- override fun statusBarLayerRotatesScales() = super.statusBarLayerRotatesScales()
-
- @Ignore
- @Test
- fun appPairsDividerIsInvisibleAtEnd() = testSpec.appPairsDividerIsInvisibleAtEnd()
-
- @Ignore
- @Test
- fun bothAppWindowsInvisible() {
- testSpec.assertWmEnd {
- isAppWindowInvisible(primaryApp.component)
- isAppWindowInvisible(secondaryApp.component)
- }
- }
-
- @Ignore
- @Test
- fun appsStartingBounds() {
- testSpec.assertLayersStart {
- val dividerRegion = layer(APP_PAIR_SPLIT_DIVIDER_COMPONENT).visibleRegion.region
- visibleRegion(primaryApp.component)
- .coversExactly(appPairsHelper.getPrimaryBounds(dividerRegion))
- visibleRegion(secondaryApp.component)
- .coversExactly(appPairsHelper.getSecondaryBounds(dividerRegion))
- }
- }
-
- @Ignore
- @Test
- fun appsEndingBounds() {
- testSpec.assertLayersEnd {
- notContains(primaryApp.component)
- notContains(secondaryApp.component)
- }
- }
-
- @Ignore
- @Test
- override fun navBarLayerIsVisible() = super.navBarLayerIsVisible()
-
- companion object {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): List<FlickerTestParameter> {
- return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
- repetitions = AppPairsHelper.TEST_REPETITIONS)
- }
- }
-}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTransition.kt
deleted file mode 100644
index 3e17948..0000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTransition.kt
+++ /dev/null
@@ -1,178 +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.wm.shell.flicker.apppairs
-
-import android.app.Instrumentation
-import android.content.Context
-import android.system.helpers.ActivityHelper
-import androidx.test.platform.app.InstrumentationRegistry
-import com.android.server.wm.flicker.FlickerBuilderProvider
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
-import com.android.server.wm.flicker.navBarLayerIsVisible
-import com.android.server.wm.flicker.navBarLayerRotatesAndScales
-import com.android.server.wm.flicker.navBarWindowIsVisible
-import com.android.server.wm.flicker.statusBarLayerIsVisible
-import com.android.server.wm.flicker.statusBarLayerRotatesScales
-import com.android.server.wm.flicker.statusBarWindowIsVisible
-import com.android.server.wm.traces.parser.toFlickerComponent
-import com.android.wm.shell.flicker.helpers.AppPairsHelper
-import com.android.wm.shell.flicker.helpers.BaseAppHelper
-import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.getDevEnableNonResizableMultiWindow
-import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.setDevEnableNonResizableMultiWindow
-import com.android.wm.shell.flicker.helpers.SplitScreenHelper
-import com.android.wm.shell.flicker.testapp.Components
-import org.junit.After
-import org.junit.Before
-import org.junit.Ignore
-import org.junit.Test
-
-abstract class AppPairsTransition(protected val testSpec: FlickerTestParameter) {
- protected val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
- protected val context: Context = instrumentation.context
- protected val activityHelper = ActivityHelper.getInstance()
- protected val appPairsHelper = AppPairsHelper(instrumentation,
- Components.SplitScreenActivity.LABEL,
- Components.SplitScreenActivity.COMPONENT.toFlickerComponent())
-
- protected val primaryApp = SplitScreenHelper.getPrimary(instrumentation)
- protected val secondaryApp = SplitScreenHelper.getSecondary(instrumentation)
- protected open val nonResizeableApp: SplitScreenHelper? =
- SplitScreenHelper.getNonResizeable(instrumentation)
- protected var primaryTaskId = ""
- protected var secondaryTaskId = ""
- protected var nonResizeableTaskId = ""
- private var prevDevEnableNonResizableMultiWindow = 0
-
- @Before
- open fun setup() {
- prevDevEnableNonResizableMultiWindow = getDevEnableNonResizableMultiWindow(context)
- if (prevDevEnableNonResizableMultiWindow != 0) {
- // Turn off the development option
- setDevEnableNonResizableMultiWindow(context, 0)
- }
- }
-
- @After
- open fun teardown() {
- setDevEnableNonResizableMultiWindow(context, prevDevEnableNonResizableMultiWindow)
- }
-
- @FlickerBuilderProvider
- fun buildFlicker(): FlickerBuilder {
- return FlickerBuilder(instrumentation).apply {
- transition(this)
- }
- }
-
- internal open val transition: FlickerBuilder.() -> Unit
- get() = {
- setup {
- test {
- device.wakeUpAndGoToHomeScreen()
- }
- eachRun {
- this.setRotation(testSpec.startRotation)
- primaryApp.launchViaIntent(wmHelper)
- secondaryApp.launchViaIntent(wmHelper)
- nonResizeableApp?.launchViaIntent(wmHelper)
- updateTasksId()
- }
- }
- teardown {
- eachRun {
- executeShellCommand(composePairsCommand(
- primaryTaskId, secondaryTaskId, pair = false))
- executeShellCommand(composePairsCommand(
- primaryTaskId, nonResizeableTaskId, pair = false))
- primaryApp.exit(wmHelper)
- secondaryApp.exit(wmHelper)
- nonResizeableApp?.exit(wmHelper)
- }
- }
- }
-
- protected fun updateTasksId() {
- primaryTaskId = getTaskIdForActivity(
- primaryApp.component.packageName, primaryApp.component.className).toString()
- secondaryTaskId = getTaskIdForActivity(
- secondaryApp.component.packageName, secondaryApp.component.className).toString()
- val nonResizeableApp = nonResizeableApp
- if (nonResizeableApp != null) {
- nonResizeableTaskId = getTaskIdForActivity(
- nonResizeableApp.component.packageName,
- nonResizeableApp.component.className).toString()
- }
- }
-
- private fun getTaskIdForActivity(pkgName: String, activityName: String): Int {
- return activityHelper.getTaskIdForActivity(pkgName, activityName)
- }
-
- internal fun executeShellCommand(cmd: String) {
- BaseAppHelper.executeShellCommand(instrumentation, cmd)
- }
-
- internal fun composePairsCommand(
- primaryApp: String,
- secondaryApp: String,
- pair: Boolean
- ): String = buildString {
- // dumpsys activity service SystemUIService WMShell {pair|unpair} ${TASK_ID_1} ${TASK_ID_2}
- append("dumpsys activity service SystemUIService WMShell ")
- if (pair) {
- append("pair ")
- } else {
- append("unpair ")
- }
- append("$primaryApp $secondaryApp")
- }
-
- @Ignore
- @Test
- open fun navBarLayerIsVisible() {
- testSpec.navBarLayerIsVisible()
- }
-
- @Ignore
- @Test
- open fun statusBarLayerIsVisible() {
- testSpec.statusBarLayerIsVisible()
- }
-
- @Ignore
- @Test
- open fun navBarWindowIsVisible() {
- testSpec.navBarWindowIsVisible()
- }
-
- @Ignore
- @Test
- open fun statusBarWindowIsVisible() {
- testSpec.statusBarWindowIsVisible()
- }
-
- @Ignore
- @Test
- open fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales()
-
- @Ignore
- @Test
- open fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales()
-}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/OWNERS b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/OWNERS
deleted file mode 100644
index 8446b37..0000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# window manager > wm shell > Split Screen
-# Bug component: 928697
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt
deleted file mode 100644
index b0c3ba2..0000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.flicker.apppairs
-
-import android.view.Surface
-import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.annotation.Group1
-import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.setRotation
-import com.android.wm.shell.flicker.appPairsDividerIsVisibleAtEnd
-import com.android.wm.shell.flicker.appPairsPrimaryBoundsIsVisibleAtEnd
-import com.android.wm.shell.flicker.appPairsSecondaryBoundsIsVisibleAtEnd
-import com.android.wm.shell.flicker.helpers.AppPairsHelper.Companion.waitAppsShown
-import com.android.wm.shell.flicker.helpers.SplitScreenHelper
-import org.junit.FixMethodOrder
-import org.junit.Ignore
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/**
- * Test open apps to app pairs and rotate.
- * To run this test: `atest WMShellFlickerTests:RotateTwoLaunchedAppsInAppPairsMode`
- */
-@RequiresDevice
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Group1
-class RotateTwoLaunchedAppsInAppPairsMode(
- testSpec: FlickerTestParameter
-) : RotateTwoLaunchedAppsTransition(testSpec) {
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- super.transition(this)
- transitions {
- executeShellCommand(composePairsCommand(
- primaryTaskId, secondaryTaskId, true /* pair */))
- waitAppsShown(primaryApp, secondaryApp)
- setRotation(testSpec.endRotation)
- }
- }
-
- @Ignore
- @Test
- override fun navBarLayerIsVisible() = super.navBarLayerIsVisible()
-
- @Ignore
- @Test
- override fun statusBarLayerIsVisible() = super.statusBarLayerIsVisible()
-
- @Ignore
- @Test
- fun bothAppWindowsVisible() {
- testSpec.assertWmEnd {
- isAppWindowVisible(primaryApp.component)
- isAppWindowVisible(secondaryApp.component)
- }
- }
-
- @Ignore
- @Test
- fun appPairsDividerIsVisibleAtEnd() = testSpec.appPairsDividerIsVisibleAtEnd()
-
- @Ignore
- @Test
- fun appPairsPrimaryBoundsIsVisibleAtEnd() =
- testSpec.appPairsPrimaryBoundsIsVisibleAtEnd(testSpec.endRotation,
- primaryApp.component)
-
- @Ignore
- @Test
- fun appPairsSecondaryBoundsIsVisibleAtEnd() =
- testSpec.appPairsSecondaryBoundsIsVisibleAtEnd(testSpec.endRotation,
- secondaryApp.component)
-
- @Ignore
- @Test
- override fun statusBarLayerRotatesScales() = super.statusBarLayerRotatesScales()
-
- companion object {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<FlickerTestParameter> {
- return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
- repetitions = SplitScreenHelper.TEST_REPETITIONS,
- supportedRotations = listOf(Surface.ROTATION_90, Surface.ROTATION_270)
- )
- }
- }
-}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt
deleted file mode 100644
index ae56c77..0000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.flicker.apppairs
-
-import android.view.Surface
-import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.annotation.Group1
-import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.setRotation
-import com.android.wm.shell.flicker.appPairsDividerIsVisibleAtEnd
-import com.android.wm.shell.flicker.appPairsPrimaryBoundsIsVisibleAtEnd
-import com.android.wm.shell.flicker.appPairsSecondaryBoundsIsVisibleAtEnd
-import com.android.wm.shell.flicker.helpers.AppPairsHelper.Companion.waitAppsShown
-import com.android.wm.shell.flicker.helpers.SplitScreenHelper
-import org.junit.FixMethodOrder
-import org.junit.Ignore
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/**
- * Test open apps to app pairs and rotate.
- * To run this test: `atest WMShellFlickerTests:RotateTwoLaunchedAppsRotateAndEnterAppPairsMode`
- */
-@RequiresDevice
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Group1
-class RotateTwoLaunchedAppsRotateAndEnterAppPairsMode(
- testSpec: FlickerTestParameter
-) : RotateTwoLaunchedAppsTransition(testSpec) {
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- super.transition(this)
- transitions {
- this.setRotation(testSpec.endRotation)
- executeShellCommand(
- composePairsCommand(primaryTaskId, secondaryTaskId, pair = true))
- waitAppsShown(primaryApp, secondaryApp)
- }
- }
-
- @Ignore
- @Test
- fun appPairsDividerIsVisibleAtEnd() = testSpec.appPairsDividerIsVisibleAtEnd()
-
- @Ignore
- @Test
- override fun navBarWindowIsVisible() = super.navBarWindowIsVisible()
-
- @Ignore
- @Test
- override fun navBarLayerIsVisible() = super.navBarLayerIsVisible()
-
- @Ignore
- @Test
- override fun statusBarWindowIsVisible() = super.statusBarWindowIsVisible()
-
- @Ignore
- @Test
- override fun statusBarLayerIsVisible() = super.statusBarLayerIsVisible()
-
- @Ignore
- @Test
- override fun statusBarLayerRotatesScales() = super.statusBarLayerRotatesScales()
-
- @Ignore
- @Test
- fun bothAppWindowsVisible() {
- testSpec.assertWmEnd {
- isAppWindowVisible(primaryApp.component)
- isAppWindowVisible(secondaryApp.component)
- }
- }
-
- @Ignore
- @Test
- fun appPairsPrimaryBoundsIsVisibleAtEnd() =
- testSpec.appPairsPrimaryBoundsIsVisibleAtEnd(testSpec.endRotation,
- primaryApp.component)
-
- @Ignore
- @Test
- fun appPairsSecondaryBoundsIsVisibleAtEnd() =
- testSpec.appPairsSecondaryBoundsIsVisibleAtEnd(testSpec.endRotation,
- secondaryApp.component)
-
- companion object {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<FlickerTestParameter> {
- return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
- repetitions = SplitScreenHelper.TEST_REPETITIONS,
- supportedRotations = listOf(Surface.ROTATION_90, Surface.ROTATION_270)
- )
- }
- }
-}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsTransition.kt
deleted file mode 100644
index b1f1c9e..0000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsTransition.kt
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.flicker.apppairs
-
-import android.view.Surface
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
-import com.android.wm.shell.flicker.helpers.BaseAppHelper.Companion.isShellTransitionsEnabled
-import com.android.wm.shell.flicker.helpers.SplitScreenHelper
-import org.junit.Assume.assumeFalse
-import org.junit.Before
-import org.junit.Ignore
-import org.junit.Test
-
-abstract class RotateTwoLaunchedAppsTransition(
- testSpec: FlickerTestParameter
-) : AppPairsTransition(testSpec) {
- override val nonResizeableApp: SplitScreenHelper?
- get() = null
-
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- setup {
- test {
- device.wakeUpAndGoToHomeScreen()
- this.setRotation(Surface.ROTATION_0)
- primaryApp.launchViaIntent(wmHelper)
- secondaryApp.launchViaIntent(wmHelper)
- updateTasksId()
- }
- }
- teardown {
- eachRun {
- executeShellCommand(composePairsCommand(
- primaryTaskId, secondaryTaskId, pair = false))
- primaryApp.exit(wmHelper)
- secondaryApp.exit(wmHelper)
- }
- }
- }
-
- @Before
- override fun setup() {
- // AppPairs hasn't been updated to Shell Transition. There will be conflict on rotation.
- assumeFalse(isShellTransitionsEnabled())
- super.setup()
- }
-
- @Ignore
- @Test
- override fun navBarLayerIsVisible() {
- super.navBarLayerIsVisible()
- }
-
- @Ignore
- @Test
- override fun navBarLayerRotatesAndScales() {
- super.navBarLayerRotatesAndScales()
- }
-}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/SplitScreenHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/SplitScreenHelper.kt
index 0ec9b2d..b902e5d 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/SplitScreenHelper.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/SplitScreenHelper.kt
@@ -17,7 +17,6 @@
package com.android.wm.shell.flicker.helpers
import android.app.Instrumentation
-import android.content.res.Resources
import com.android.server.wm.traces.common.FlickerComponentName
import com.android.server.wm.traces.parser.toFlickerComponent
import com.android.wm.shell.flicker.testapp.Components
@@ -32,11 +31,6 @@
const val TEST_REPETITIONS = 1
const val TIMEOUT_MS = 3_000L
- // TODO: remove all legacy split screen flicker tests when legacy split screen is fully
- // deprecated.
- fun isUsingLegacySplit(): Boolean =
- Resources.getSystem().getBoolean(com.android.internal.R.bool.config_useLegacySplit)
-
fun getPrimary(instrumentation: Instrumentation): SplitScreenHelper =
SplitScreenHelper(instrumentation,
Components.SplitScreenActivity.LABEL,
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenDockActivity.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenDockActivity.kt
deleted file mode 100644
index c86a122..0000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenDockActivity.kt
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.flicker.legacysplitscreen
-
-import android.platform.test.annotations.Presubmit
-import android.view.Surface
-import android.view.WindowManagerPolicyConstants
-import androidx.test.filters.FlakyTest
-import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.annotation.Group4
-import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.launchSplitScreen
-import com.android.server.wm.flicker.navBarWindowIsVisible
-import com.android.server.wm.flicker.statusBarWindowIsVisible
-import com.android.server.wm.traces.common.FlickerComponentName
-import com.android.wm.shell.flicker.dockedStackDividerBecomesVisible
-import com.android.wm.shell.flicker.dockedStackPrimaryBoundsIsVisibleAtEnd
-import com.android.wm.shell.flicker.helpers.SplitScreenHelper
-import org.junit.FixMethodOrder
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/**
- * Test open activity and dock to primary split screen
- * To run this test: `atest WMShellFlickerTests:EnterSplitScreenDockActivity`
- */
-@Presubmit
-@RequiresDevice
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Group4
-class EnterSplitScreenDockActivity(
- testSpec: FlickerTestParameter
-) : LegacySplitScreenTransition(testSpec) {
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- super.transition(this)
- transitions {
- device.launchSplitScreen(wmHelper)
- }
- }
-
- override val ignoredWindows: List<FlickerComponentName>
- get() = listOf(LAUNCHER_COMPONENT, LIVE_WALLPAPER_COMPONENT,
- splitScreenApp.component, FlickerComponentName.SPLASH_SCREEN,
- FlickerComponentName.SNAPSHOT, LAUNCHER_COMPONENT)
-
- @Presubmit
- @Test
- fun dockedStackPrimaryBoundsIsVisibleAtEnd() =
- testSpec.dockedStackPrimaryBoundsIsVisibleAtEnd(testSpec.startRotation,
- splitScreenApp.component)
-
- @Presubmit
- @Test
- fun dockedStackDividerBecomesVisible() = testSpec.dockedStackDividerBecomesVisible()
-
- @Presubmit
- @Test
- fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible()
-
- @Presubmit
- @Test
- fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible()
-
- @Presubmit
- @Test
- fun appWindowIsVisible() {
- testSpec.assertWmEnd {
- isAppWindowVisible(splitScreenApp.component)
- }
- }
-
- @FlakyTest
- @Test
- override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
- super.visibleLayersShownMoreThanOneConsecutiveEntry()
-
- @Presubmit
- @Test
- override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
- super.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
- companion object {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<FlickerTestParameter> {
- return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
- repetitions = SplitScreenHelper.TEST_REPETITIONS,
- supportedRotations = listOf(Surface.ROTATION_0), // bugId = 179116910
- supportedNavigationModes = listOf(
- WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY)
- )
- }
- }
-}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenFromDetachedRecentTask.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenFromDetachedRecentTask.kt
deleted file mode 100644
index 2f9244b..0000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenFromDetachedRecentTask.kt
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.flicker.legacysplitscreen
-
-import android.platform.test.annotations.Presubmit
-import android.view.Surface
-import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.annotation.Group4
-import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.launchSplitScreen
-import com.android.server.wm.traces.common.FlickerComponentName
-import com.android.wm.shell.flicker.dockedStackDividerIsVisibleAtEnd
-import com.android.wm.shell.flicker.helpers.SplitScreenHelper
-import org.junit.FixMethodOrder
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/**
- * Test enter split screen from a detached recent task
- *
- * To run this test: `atest WMShellFlickerTests:EnterSplitScreenFromDetachedRecentTask`
- */
-@RequiresDevice
-@RunWith(Parameterized::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@Group4
-class EnterSplitScreenFromDetachedRecentTask(
- testSpec: FlickerTestParameter
-) : LegacySplitScreenTransition(testSpec) {
-
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- cleanSetup(this)
- setup {
- eachRun {
- splitScreenApp.launchViaIntent(wmHelper)
- // Press back to remove the task, but it should still be shown in recent.
- device.pressBack()
- }
- }
- transitions {
- device.launchSplitScreen(wmHelper)
- }
- }
-
- override val ignoredWindows: List<FlickerComponentName>
- get() = listOf(LAUNCHER_COMPONENT,
- FlickerComponentName.SPLASH_SCREEN,
- FlickerComponentName.SNAPSHOT,
- splitScreenApp.component)
-
- @Presubmit
- @Test
- fun dockedStackDividerIsVisibleAtEnd() = testSpec.dockedStackDividerIsVisibleAtEnd()
-
- @Presubmit
- @Test
- fun appWindowIsVisible() {
- testSpec.assertWmEnd {
- isAppWindowVisible(splitScreenApp.component)
- }
- }
-
- @Presubmit
- @Test
- override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
- super.visibleLayersShownMoreThanOneConsecutiveEntry()
-
- @Presubmit
- @Test
- override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
- super.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
- companion object {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<FlickerTestParameter> {
- return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
- repetitions = SplitScreenHelper.TEST_REPETITIONS,
- supportedRotations = listOf(Surface.ROTATION_0) // bugId = 179116910
- )
- }
- }
-}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenLaunchToSide.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenLaunchToSide.kt
deleted file mode 100644
index 1740c3e..0000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenLaunchToSide.kt
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.flicker.legacysplitscreen
-
-import android.platform.test.annotations.Presubmit
-import android.view.Surface
-import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.annotation.Group4
-import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.launchSplitScreen
-import com.android.server.wm.flicker.helpers.reopenAppFromOverview
-import com.android.server.wm.flicker.navBarWindowIsVisible
-import com.android.server.wm.flicker.statusBarWindowIsVisible
-import com.android.server.wm.traces.common.FlickerComponentName
-import com.android.wm.shell.flicker.dockedStackDividerBecomesVisible
-import com.android.wm.shell.flicker.dockedStackPrimaryBoundsIsVisibleAtEnd
-import com.android.wm.shell.flicker.dockedStackSecondaryBoundsIsVisibleAtEnd
-import com.android.wm.shell.flicker.helpers.SplitScreenHelper
-import org.junit.FixMethodOrder
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/**
- * Test open activity to primary split screen and dock secondary activity to side
- * To run this test: `atest WMShellFlickerTests:EnterSplitScreenLaunchToSide`
- */
-@RequiresDevice
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Group4
-class EnterSplitScreenLaunchToSide(
- testSpec: FlickerTestParameter
-) : LegacySplitScreenTransition(testSpec) {
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- super.transition(this)
- transitions {
- device.launchSplitScreen(wmHelper)
- device.reopenAppFromOverview(wmHelper)
- }
- }
-
- override val ignoredWindows: List<FlickerComponentName>
- get() = listOf(LAUNCHER_COMPONENT, splitScreenApp.component,
- secondaryApp.component, FlickerComponentName.SPLASH_SCREEN,
- FlickerComponentName.SNAPSHOT)
-
- @Presubmit
- @Test
- fun dockedStackPrimaryBoundsIsVisibleAtEnd() =
- testSpec.dockedStackPrimaryBoundsIsVisibleAtEnd(testSpec.startRotation,
- splitScreenApp.component)
-
- @Presubmit
- @Test
- fun dockedStackSecondaryBoundsIsVisibleAtEnd() =
- testSpec.dockedStackSecondaryBoundsIsVisibleAtEnd(testSpec.startRotation,
- secondaryApp.component)
-
- @Presubmit
- @Test
- fun dockedStackDividerBecomesVisible() = testSpec.dockedStackDividerBecomesVisible()
-
- @Presubmit
- @Test
- fun appWindowBecomesVisible() {
- testSpec.assertWm {
- // when the app is launched, first the activity becomes visible, then the
- // SnapshotStartingWindow appears and then the app window becomes visible.
- // Because we log WM once per frame, sometimes the activity and the window
- // become visible in the same entry, sometimes not, thus it is not possible to
- // assert the visibility of the activity here
- this.isAppWindowInvisible(secondaryApp.component)
- .then()
- // during re-parenting, the window may disappear and reappear from the
- // trace, this occurs because we log only 1x per frame
- .notContains(secondaryApp.component, isOptional = true)
- .then()
- .isAppWindowVisible(secondaryApp.component)
- }
- }
-
- @Presubmit
- @Test
- fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible()
-
- @Presubmit
- @Test
- fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible()
-
- @Presubmit
- @Test
- override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
- super.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
- companion object {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<FlickerTestParameter> {
- return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
- repetitions = SplitScreenHelper.TEST_REPETITIONS,
- supportedRotations = listOf(Surface.ROTATION_0) // bugId = 175687842
- )
- }
- }
-}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenNotSupportNonResizable.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenNotSupportNonResizable.kt
deleted file mode 100644
index 4c063b9..0000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenNotSupportNonResizable.kt
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.flicker.legacysplitscreen
-
-import android.platform.test.annotations.Presubmit
-import android.view.Surface
-import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.annotation.Group4
-import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.canSplitScreen
-import com.android.server.wm.traces.common.FlickerComponentName
-import com.android.wm.shell.flicker.dockedStackDividerNotExistsAtEnd
-import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.resetMultiWindowConfig
-import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.setSupportsNonResizableMultiWindow
-import com.android.wm.shell.flicker.helpers.SplitScreenHelper
-import org.junit.After
-import org.junit.Assert
-import org.junit.Before
-import org.junit.FixMethodOrder
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/**
- * Test enter split screen from non-resizable activity. When the device doesn't support
- * non-resizable in multi window, there should be no button to enter split screen for non-resizable
- * activity.
- *
- * To run this test: `atest WMShellFlickerTests:EnterSplitScreenNotSupportNonResizable`
- */
-@RequiresDevice
-@RunWith(Parameterized::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@Group4
-class EnterSplitScreenNotSupportNonResizable(
- testSpec: FlickerTestParameter
-) : LegacySplitScreenTransition(testSpec) {
-
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- cleanSetup(this)
- setup {
- eachRun {
- nonResizeableApp.launchViaIntent(wmHelper)
- }
- }
- transitions {
- if (device.canSplitScreen(wmHelper)) {
- Assert.fail("Non-resizeable app should not enter split screen")
- }
- }
- }
-
- override val ignoredWindows: List<FlickerComponentName>
- get() = listOf(LAUNCHER_COMPONENT,
- FlickerComponentName.SPLASH_SCREEN,
- FlickerComponentName.SNAPSHOT,
- nonResizeableApp.component,
- splitScreenApp.component)
-
- @Before
- override fun setup() {
- super.setup()
- setSupportsNonResizableMultiWindow(instrumentation, -1)
- }
-
- @After
- override fun teardown() {
- super.teardown()
- resetMultiWindowConfig(instrumentation)
- }
-
- @Presubmit
- @Test
- fun dockedStackDividerNotExistsAtEnd() = testSpec.dockedStackDividerNotExistsAtEnd()
-
- @Presubmit
- @Test
- override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
- super.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
- companion object {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<FlickerTestParameter> {
- return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
- repetitions = SplitScreenHelper.TEST_REPETITIONS,
- supportedRotations = listOf(Surface.ROTATION_0)) // b/178685668
- }
- }
-}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenSupportNonResizable.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenSupportNonResizable.kt
deleted file mode 100644
index f75dee6..0000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenSupportNonResizable.kt
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.flicker.legacysplitscreen
-
-import android.platform.test.annotations.Presubmit
-import android.view.Surface
-import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.annotation.Group2
-import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.launchSplitScreen
-import com.android.server.wm.traces.common.FlickerComponentName
-import com.android.wm.shell.flicker.dockedStackDividerIsVisibleAtEnd
-import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.resetMultiWindowConfig
-import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.setSupportsNonResizableMultiWindow
-import com.android.wm.shell.flicker.helpers.SplitScreenHelper
-import org.junit.After
-import org.junit.Before
-import org.junit.FixMethodOrder
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/**
- * Test enter split screen from non-resizable activity. When the device supports
- * non-resizable in multi window, there should be a button to enter split screen for non-resizable
- * activity.
- *
- * To run this test: `atest WMShellFlickerTests:EnterSplitScreenSupportNonResizable`
- */
-@RequiresDevice
-@RunWith(Parameterized::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@Group2
-class EnterSplitScreenSupportNonResizable(
- testSpec: FlickerTestParameter
-) : LegacySplitScreenTransition(testSpec) {
-
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- cleanSetup(this)
- setup {
- eachRun {
- nonResizeableApp.launchViaIntent(wmHelper)
- }
- }
- transitions {
- device.launchSplitScreen(wmHelper)
- }
- }
-
- override val ignoredWindows: List<FlickerComponentName>
- get() = listOf(LAUNCHER_COMPONENT,
- FlickerComponentName.SPLASH_SCREEN,
- FlickerComponentName.SNAPSHOT,
- nonResizeableApp.component,
- splitScreenApp.component)
-
- @Before
- override fun setup() {
- super.setup()
- setSupportsNonResizableMultiWindow(instrumentation, 1)
- }
-
- @After
- override fun teardown() {
- super.teardown()
- resetMultiWindowConfig(instrumentation)
- }
-
- @Presubmit
- @Test
- fun dockedStackDividerIsVisibleAtEnd() = testSpec.dockedStackDividerIsVisibleAtEnd()
-
- @Presubmit
- @Test
- fun appWindowIsVisible() {
- testSpec.assertWmEnd {
- isAppWindowVisible(nonResizeableApp.component)
- }
- }
-
- @Presubmit
- @Test
- override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
- super.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
- companion object {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<FlickerTestParameter> {
- return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
- repetitions = SplitScreenHelper.TEST_REPETITIONS,
- supportedRotations = listOf(Surface.ROTATION_0)) // b/178685668
- }
- }
-}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottom.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottom.kt
deleted file mode 100644
index ef7d65e..0000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottom.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.wm.shell.flicker.legacysplitscreen
-
-import android.view.Surface
-import androidx.test.filters.FlakyTest
-import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.annotation.Group2
-import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.exitSplitScreenFromBottom
-import com.android.server.wm.flicker.helpers.launchSplitScreen
-import com.android.server.wm.flicker.navBarWindowIsVisible
-import com.android.server.wm.flicker.statusBarWindowIsVisible
-import com.android.server.wm.traces.common.FlickerComponentName
-import com.android.wm.shell.flicker.DOCKED_STACK_DIVIDER_COMPONENT
-import com.android.wm.shell.flicker.helpers.SplitScreenHelper
-import org.junit.FixMethodOrder
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/**
- * Test open resizeable activity split in primary, and drag divider to bottom exit split screen
- * To run this test: `atest WMShellFlickerTests:ExitLegacySplitScreenFromBottom`
- */
-@RequiresDevice
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Group2
-class ExitLegacySplitScreenFromBottom(
- testSpec: FlickerTestParameter
-) : LegacySplitScreenTransition(testSpec) {
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- super.transition(this)
- setup {
- eachRun {
- splitScreenApp.launchViaIntent(wmHelper)
- device.launchSplitScreen(wmHelper)
- }
- }
- teardown {
- eachRun {
- splitScreenApp.exit(wmHelper)
- }
- }
- transitions {
- device.exitSplitScreenFromBottom(wmHelper)
- }
- }
-
- override val ignoredWindows: List<FlickerComponentName>
- get() = listOf(LAUNCHER_COMPONENT, FlickerComponentName.SPLASH_SCREEN,
- splitScreenApp.component, secondaryApp.component,
- FlickerComponentName.SNAPSHOT)
-
- @FlakyTest
- @Test
- fun layerBecomesInvisible() {
- testSpec.assertLayers {
- this.isVisible(DOCKED_STACK_DIVIDER_COMPONENT)
- .then()
- .isInvisible(DOCKED_STACK_DIVIDER_COMPONENT)
- }
- }
-
- @FlakyTest
- @Test
- fun appWindowBecomesInVisible() {
- testSpec.assertWm {
- this.isAppWindowVisible(secondaryApp.component)
- .then()
- .isAppWindowInvisible(secondaryApp.component)
- }
- }
-
- @FlakyTest
- @Test
- fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible()
-
- @FlakyTest
- @Test
- fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible()
-
- @FlakyTest
- @Test
- override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
- super.visibleLayersShownMoreThanOneConsecutiveEntry()
-
- @FlakyTest
- @Test
- override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
- super.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
- companion object {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<FlickerTestParameter> {
- return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
- repetitions = SplitScreenHelper.TEST_REPETITIONS,
- supportedRotations = listOf(Surface.ROTATION_0) // b/175687842
- )
- }
- }
-}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitPrimarySplitScreenShowSecondaryFullscreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitPrimarySplitScreenShowSecondaryFullscreen.kt
deleted file mode 100644
index d913a6d..0000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitPrimarySplitScreenShowSecondaryFullscreen.kt
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.flicker.legacysplitscreen
-
-import android.platform.test.annotations.Presubmit
-import android.view.Surface
-import androidx.test.filters.FlakyTest
-import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.annotation.Group2
-import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.launchSplitScreen
-import com.android.server.wm.flicker.helpers.reopenAppFromOverview
-import com.android.server.wm.flicker.navBarWindowIsVisible
-import com.android.server.wm.flicker.statusBarWindowIsVisible
-import com.android.server.wm.traces.common.FlickerComponentName
-import com.android.wm.shell.flicker.dockedStackDividerNotExistsAtEnd
-import com.android.wm.shell.flicker.helpers.SplitScreenHelper
-import org.junit.FixMethodOrder
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/**
- * Test dock activity to primary split screen, and open secondary to side, exit primary split
- * and test secondary activity become full screen.
- * To run this test: `atest WMShellFlickerTests:ExitPrimarySplitScreenShowSecondaryFullscreen`
- */
-@RequiresDevice
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Group2
-class ExitPrimarySplitScreenShowSecondaryFullscreen(
- testSpec: FlickerTestParameter
-) : LegacySplitScreenTransition(testSpec) {
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- super.transition(this)
- teardown {
- eachRun {
- secondaryApp.exit(wmHelper)
- }
- }
- transitions {
- splitScreenApp.launchViaIntent(wmHelper)
- secondaryApp.launchViaIntent(wmHelper)
- device.launchSplitScreen(wmHelper)
- device.reopenAppFromOverview(wmHelper)
- // TODO(b/175687842) Can not find Split screen divider, use exit() instead
- splitScreenApp.exit(wmHelper)
- }
- }
-
- override val ignoredWindows: List<FlickerComponentName>
- get() = listOf(LAUNCHER_COMPONENT, FlickerComponentName.SPLASH_SCREEN,
- splitScreenApp.component, secondaryApp.component,
- FlickerComponentName.SNAPSHOT)
-
- @Presubmit
- @Test
- fun dockedStackDividerNotExistsAtEnd() = testSpec.dockedStackDividerNotExistsAtEnd()
-
- @FlakyTest
- @Test
- fun layerBecomesInvisible() {
- testSpec.assertLayers {
- this.isVisible(splitScreenApp.component)
- .then()
- .isInvisible(splitScreenApp.component)
- }
- }
-
- @FlakyTest
- @Test
- fun appWindowBecomesInVisible() {
- testSpec.assertWm {
- this.isAppWindowVisible(splitScreenApp.component)
- .then()
- .isAppWindowInvisible(splitScreenApp.component)
- }
- }
-
- @Presubmit
- @Test
- fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible()
-
- @Presubmit
- @Test
- fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible()
-
- @Presubmit
- @Test
- override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
- super.visibleLayersShownMoreThanOneConsecutiveEntry()
-
- @Presubmit
- @Test
- override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
- super.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
- companion object {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<FlickerTestParameter> {
- return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
- repetitions = SplitScreenHelper.TEST_REPETITIONS,
- supportedRotations = listOf(Surface.ROTATION_0) // bugId = 179116910
- )
- }
- }
-}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentNotSupportNonResizable.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentNotSupportNonResizable.kt
deleted file mode 100644
index f3ff7b1..0000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentNotSupportNonResizable.kt
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.flicker.legacysplitscreen
-
-import android.platform.test.annotations.Presubmit
-import android.view.Surface
-import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.annotation.Group2
-import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.launchSplitScreen
-import com.android.server.wm.traces.common.FlickerComponentName
-import com.android.wm.shell.flicker.DOCKED_STACK_DIVIDER_COMPONENT
-import com.android.wm.shell.flicker.dockedStackDividerNotExistsAtEnd
-import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.resetMultiWindowConfig
-import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.setSupportsNonResizableMultiWindow
-import com.android.wm.shell.flicker.helpers.SplitScreenHelper
-import org.junit.After
-import org.junit.Before
-import org.junit.FixMethodOrder
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/**
- * Test launch non-resizable activity via intent in split screen mode. When the device does not
- * support non-resizable in multi window, it should trigger exit split screen.
- * To run this test: `atest WMShellFlickerTests:LegacySplitScreenFromIntentNotSupportNonResizable`
- */
-@RequiresDevice
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Group2
-class LegacySplitScreenFromIntentNotSupportNonResizable(
- testSpec: FlickerTestParameter
-) : LegacySplitScreenTransition(testSpec) {
-
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- cleanSetup(this)
- setup {
- eachRun {
- splitScreenApp.launchViaIntent(wmHelper)
- device.launchSplitScreen(wmHelper)
- }
- }
- transitions {
- nonResizeableApp.launchViaIntent(wmHelper)
- wmHelper.waitForAppTransitionIdle()
- }
- }
-
- override val ignoredWindows: List<FlickerComponentName>
- get() = listOf(DOCKED_STACK_DIVIDER_COMPONENT, LAUNCHER_COMPONENT, LETTERBOX_COMPONENT,
- nonResizeableApp.component, splitScreenApp.component,
- FlickerComponentName.SPLASH_SCREEN,
- FlickerComponentName.SNAPSHOT)
-
- @Before
- override fun setup() {
- super.setup()
- setSupportsNonResizableMultiWindow(instrumentation, -1)
- }
-
- @After
- override fun teardown() {
- super.teardown()
- resetMultiWindowConfig(instrumentation)
- }
-
- @Presubmit
- @Test
- fun resizableAppLayerBecomesInvisible() {
- testSpec.assertLayers {
- this.isVisible(splitScreenApp.component)
- .then()
- .isInvisible(splitScreenApp.component)
- }
- }
-
- @Presubmit
- @Test
- fun nonResizableAppLayerBecomesVisible() {
- testSpec.assertLayers {
- this.notContains(nonResizeableApp.component)
- .then()
- .isInvisible(nonResizeableApp.component)
- .then()
- .isVisible(nonResizeableApp.component)
- }
- }
-
- /**
- * Assets that [splitScreenApp] exists at the start of the trace and, once it becomes
- * invisible, it remains invisible until the end of the trace.
- */
- @Presubmit
- @Test
- fun resizableAppWindowBecomesInvisible() {
- testSpec.assertWm {
- // when the activity gets PAUSED the window may still be marked as visible
- // it will be updated in the next log entry. This occurs because we record 1x
- // per frame, thus ignore activity check here
- this.isAppWindowVisible(splitScreenApp.component)
- .then()
- // immediately after the window (after onResume and before perform relayout)
- // the activity is invisible. This may or not be logged, since we record 1x
- // per frame, thus ignore activity check here
- .isAppWindowInvisible(splitScreenApp.component)
- }
- }
-
- /**
- * Assets that [nonResizeableApp] doesn't exist at the start of the trace, then
- * [nonResizeableApp] is created (visible or not) and, once [nonResizeableApp] becomes
- * visible, it remains visible until the end of the trace.
- */
- @Presubmit
- @Test
- fun nonResizableAppWindowBecomesVisible() {
- testSpec.assertWm {
- this.notContains(nonResizeableApp.component)
- .then()
- // we log once per frame, upon logging, window may be visible or not depending
- // on what was processed until that moment. Both behaviors are correct
- .isAppWindowInvisible(nonResizeableApp.component, isOptional = true)
- .then()
- // immediately after the window (after onResume and before perform relayout)
- // the activity is invisible. This may or not be logged, since we record 1x
- // per frame, thus ignore activity check here
- .isAppWindowVisible(nonResizeableApp.component)
- }
- }
-
- /**
- * Asserts that both the app window and the activity are visible at the end of the trace
- */
- @Presubmit
- @Test
- fun nonResizableAppWindowBecomesVisibleAtEnd() {
- testSpec.assertWmEnd {
- isAppWindowVisible(nonResizeableApp.component)
- }
- }
-
- @Presubmit
- @Test
- fun dockedStackDividerNotExistsAtEnd() = testSpec.dockedStackDividerNotExistsAtEnd()
-
- @Presubmit
- @Test
- fun onlyNonResizableAppWindowIsVisibleAtEnd() {
- testSpec.assertWmEnd {
- isAppWindowInvisible(splitScreenApp.component)
- isAppWindowVisible(nonResizeableApp.component)
- }
- }
-
- @Presubmit
- @Test
- override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
- super.visibleLayersShownMoreThanOneConsecutiveEntry()
-
- @Presubmit
- @Test
- override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
- super.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
- companion object {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<FlickerTestParameter> {
- return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
- repetitions = SplitScreenHelper.TEST_REPETITIONS,
- supportedRotations = listOf(Surface.ROTATION_0)) // b/178685668
- }
- }
-}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentSupportNonResizable.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentSupportNonResizable.kt
deleted file mode 100644
index 42e707a..0000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentSupportNonResizable.kt
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.flicker.legacysplitscreen
-
-import android.platform.test.annotations.Presubmit
-import android.view.Surface
-import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.annotation.Group2
-import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.launchSplitScreen
-import com.android.server.wm.traces.common.FlickerComponentName
-import com.android.wm.shell.flicker.DOCKED_STACK_DIVIDER_COMPONENT
-import com.android.wm.shell.flicker.dockedStackDividerIsVisibleAtEnd
-import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.resetMultiWindowConfig
-import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.setSupportsNonResizableMultiWindow
-import com.android.wm.shell.flicker.helpers.SplitScreenHelper
-import org.junit.After
-import org.junit.Before
-import org.junit.FixMethodOrder
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/**
- * Test launch non-resizable activity via intent in split screen mode. When the device supports
- * non-resizable in multi window, it should show the non-resizable app in split screen.
- * To run this test: `atest WMShellFlickerTests:LegacySplitScreenFromIntentSupportNonResizable`
- */
-@RequiresDevice
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Group2
-class LegacySplitScreenFromIntentSupportNonResizable(
- testSpec: FlickerTestParameter
-) : LegacySplitScreenTransition(testSpec) {
-
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- cleanSetup(this)
- setup {
- eachRun {
- splitScreenApp.launchViaIntent(wmHelper)
- device.launchSplitScreen(wmHelper)
- }
- }
- transitions {
- nonResizeableApp.launchViaIntent(wmHelper)
- wmHelper.waitForAppTransitionIdle()
- }
- }
-
- override val ignoredWindows: List<FlickerComponentName>
- get() = listOf(DOCKED_STACK_DIVIDER_COMPONENT, LAUNCHER_COMPONENT, LETTERBOX_COMPONENT,
- nonResizeableApp.component, splitScreenApp.component,
- FlickerComponentName.SPLASH_SCREEN,
- FlickerComponentName.SNAPSHOT)
-
- @Before
- override fun setup() {
- super.setup()
- setSupportsNonResizableMultiWindow(instrumentation, 1)
- }
-
- @After
- override fun teardown() {
- super.teardown()
- resetMultiWindowConfig(instrumentation)
- }
-
- @Presubmit
- @Test
- fun nonResizableAppLayerBecomesVisible() {
- testSpec.assertLayers {
- this.isInvisible(nonResizeableApp.component)
- .then()
- .isVisible(nonResizeableApp.component)
- }
- }
-
- /**
- * Assets that [nonResizeableApp] doesn't exist at the start of the trace, then
- * [nonResizeableApp] is created (visible or not) and, once [nonResizeableApp] becomes
- * visible, it remains visible until the end of the trace.
- */
- @Presubmit
- @Test
- fun nonResizableAppWindowBecomesVisible() {
- testSpec.assertWm {
- this.notContains(nonResizeableApp.component)
- .then()
- // we log once per frame, upon logging, window may be visible or not depending
- // on what was processed until that moment. Both behaviors are correct
- .isAppWindowInvisible(nonResizeableApp.component, isOptional = true)
- .then()
- // immediately after the window (after onResume and before perform relayout)
- // the activity is invisible. This may or not be logged, since we record 1x
- // per frame, thus ignore activity check here
- .isAppWindowVisible(nonResizeableApp.component)
- }
- }
-
- @Presubmit
- @Test
- fun dockedStackDividerIsVisibleAtEnd() = testSpec.dockedStackDividerIsVisibleAtEnd()
-
- @Presubmit
- @Test
- fun bothAppsWindowsAreVisibleAtEnd() {
- testSpec.assertWmEnd {
- isAppWindowVisible(splitScreenApp.component)
- isAppWindowVisible(nonResizeableApp.component)
- }
- }
-
- @Presubmit
- @Test
- override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
- super.visibleLayersShownMoreThanOneConsecutiveEntry()
-
- @Presubmit
- @Test
- override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
- super.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
- companion object {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<FlickerTestParameter> {
- return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
- repetitions = SplitScreenHelper.TEST_REPETITIONS,
- supportedRotations = listOf(Surface.ROTATION_0)) // b/178685668
- }
- }
-}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentNotSupportNonResizable.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentNotSupportNonResizable.kt
deleted file mode 100644
index c1fba7d..0000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentNotSupportNonResizable.kt
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.flicker.legacysplitscreen
-
-import android.platform.test.annotations.Presubmit
-import android.view.Surface
-import androidx.test.filters.FlakyTest
-import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.annotation.Group2
-import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.launchSplitScreen
-import com.android.server.wm.flicker.helpers.reopenAppFromOverview
-import com.android.server.wm.traces.common.FlickerComponentName
-import com.android.wm.shell.flicker.DOCKED_STACK_DIVIDER_COMPONENT
-import com.android.wm.shell.flicker.dockedStackDividerNotExistsAtEnd
-import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.resetMultiWindowConfig
-import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.setSupportsNonResizableMultiWindow
-import com.android.wm.shell.flicker.helpers.SplitScreenHelper
-import org.junit.After
-import org.junit.Before
-import org.junit.FixMethodOrder
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/**
- * Test launch non-resizable activity via recent overview in split screen mode. When the device does
- * not support non-resizable in multi window, it should trigger exit split screen.
- * To run this test: `atest WMShellFlickerTests:LegacySplitScreenFromRecentNotSupportNonResizable`
- */
-@RequiresDevice
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Group2
-class LegacySplitScreenFromRecentNotSupportNonResizable(
- testSpec: FlickerTestParameter
-) : LegacySplitScreenTransition(testSpec) {
-
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- cleanSetup(this)
- setup {
- eachRun {
- nonResizeableApp.launchViaIntent(wmHelper)
- splitScreenApp.launchViaIntent(wmHelper)
- device.launchSplitScreen(wmHelper)
- }
- }
- transitions {
- device.reopenAppFromOverview(wmHelper)
- }
- }
-
- override val ignoredWindows: List<FlickerComponentName>
- get() = listOf(DOCKED_STACK_DIVIDER_COMPONENT, LAUNCHER_COMPONENT, LETTERBOX_COMPONENT,
- TOAST_COMPONENT, splitScreenApp.component, nonResizeableApp.component,
- FlickerComponentName.SPLASH_SCREEN,
- FlickerComponentName.SNAPSHOT)
-
- @Before
- override fun setup() {
- super.setup()
- setSupportsNonResizableMultiWindow(instrumentation, -1)
- }
-
- @After
- override fun teardown() {
- super.teardown()
- resetMultiWindowConfig(instrumentation)
- }
-
- @Presubmit
- @Test
- fun resizableAppLayerBecomesInvisible() {
- testSpec.assertLayers {
- this.isVisible(splitScreenApp.component)
- .then()
- .isInvisible(splitScreenApp.component)
- }
- }
-
- @Presubmit
- @Test
- fun nonResizableAppLayerBecomesVisible() {
- testSpec.assertLayers {
- this.isInvisible(nonResizeableApp.component)
- .then()
- .isVisible(nonResizeableApp.component)
- }
- }
-
- @Presubmit
- @Test
- fun resizableAppWindowBecomesInvisible() {
- testSpec.assertWm {
- // when the activity gets PAUSED the window may still be marked as visible
- // it will be updated in the next log entry. This occurs because we record 1x
- // per frame, thus ignore activity check here
- this.isAppWindowVisible(splitScreenApp.component)
- .then()
- // immediately after the window (after onResume and before perform relayout)
- // the activity is invisible. This may or not be logged, since we record 1x
- // per frame, thus ignore activity check here
- .isAppWindowInvisible(splitScreenApp.component)
- }
- }
-
- @FlakyTest
- @Test
- fun nonResizableAppWindowBecomesVisible() {
- testSpec.assertWm {
- this.isAppWindowInvisible(nonResizeableApp.component)
- .then()
- .isAppWindowVisible(nonResizeableApp.component)
- }
- }
-
- @Presubmit
- @Test
- fun dockedStackDividerNotExistsAtEnd() = testSpec.dockedStackDividerNotExistsAtEnd()
-
- @Presubmit
- @Test
- fun onlyNonResizableAppWindowIsVisibleAtEnd() {
- testSpec.assertWmEnd {
- isAppWindowInvisible(splitScreenApp.component)
- isAppWindowVisible(nonResizeableApp.component)
- }
- }
-
- @Presubmit
- @Test
- override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
- super.visibleLayersShownMoreThanOneConsecutiveEntry()
-
- @Presubmit
- @Test
- override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
- super.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
- companion object {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<FlickerTestParameter> {
- return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
- repetitions = SplitScreenHelper.TEST_REPETITIONS,
- supportedRotations = listOf(Surface.ROTATION_0)) // b/178685668
- }
- }
-}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentSupportNonResizable.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentSupportNonResizable.kt
deleted file mode 100644
index 6ac8683..0000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentSupportNonResizable.kt
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.flicker.legacysplitscreen
-
-import android.platform.test.annotations.Presubmit
-import android.view.Surface
-import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.annotation.Group2
-import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.launchSplitScreen
-import com.android.server.wm.flicker.helpers.reopenAppFromOverview
-import com.android.server.wm.traces.common.FlickerComponentName
-import com.android.wm.shell.flicker.DOCKED_STACK_DIVIDER_COMPONENT
-import com.android.wm.shell.flicker.dockedStackDividerIsVisibleAtEnd
-import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.resetMultiWindowConfig
-import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.setSupportsNonResizableMultiWindow
-import com.android.wm.shell.flicker.helpers.SplitScreenHelper
-import org.junit.After
-import org.junit.Before
-import org.junit.FixMethodOrder
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/**
- * Test launch non-resizable activity via recent overview in split screen mode. When the device
- * supports non-resizable in multi window, it should show the non-resizable app in split screen.
- * To run this test: `atest WMShellFlickerTests:LegacySplitScreenFromRecentSupportNonResizable`
- */
-@RequiresDevice
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Group2
-class LegacySplitScreenFromRecentSupportNonResizable(
- testSpec: FlickerTestParameter
-) : LegacySplitScreenTransition(testSpec) {
-
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- cleanSetup(this)
- setup {
- eachRun {
- nonResizeableApp.launchViaIntent(wmHelper)
- splitScreenApp.launchViaIntent(wmHelper)
- device.launchSplitScreen(wmHelper)
- }
- }
- transitions {
- device.reopenAppFromOverview(wmHelper)
- }
- }
-
- override val ignoredWindows: List<FlickerComponentName>
- get() = listOf(DOCKED_STACK_DIVIDER_COMPONENT, LAUNCHER_COMPONENT, LETTERBOX_COMPONENT,
- TOAST_COMPONENT, splitScreenApp.component, nonResizeableApp.component,
- FlickerComponentName.SPLASH_SCREEN,
- FlickerComponentName.SNAPSHOT)
-
- @Before
- override fun setup() {
- super.setup()
- setSupportsNonResizableMultiWindow(instrumentation, 1)
- }
-
- @After
- override fun teardown() {
- super.teardown()
- resetMultiWindowConfig(instrumentation)
- }
-
- @Presubmit
- @Test
- fun nonResizableAppLayerBecomesVisible() {
- testSpec.assertLayers {
- this.isInvisible(nonResizeableApp.component)
- .then()
- .isVisible(nonResizeableApp.component)
- }
- }
-
- @Presubmit
- @Test
- fun nonResizableAppWindowBecomesVisible() {
- testSpec.assertWm {
- // when the app is launched, first the activity becomes visible, then the
- // SnapshotStartingWindow appears and then the app window becomes visible.
- // Because we log WM once per frame, sometimes the activity and the window
- // become visible in the same entry, sometimes not, thus it is not possible to
- // assert the visibility of the activity here
- this.isAppWindowInvisible(nonResizeableApp.component)
- .then()
- // during re-parenting, the window may disappear and reappear from the
- // trace, this occurs because we log only 1x per frame
- .notContains(nonResizeableApp.component, isOptional = true)
- .then()
- // if the window reappears after re-parenting it will most likely not
- // be visible in the first log entry (because we log only 1x per frame)
- .isAppWindowInvisible(nonResizeableApp.component, isOptional = true)
- .then()
- .isAppWindowVisible(nonResizeableApp.component)
- }
- }
-
- @Presubmit
- @Test
- fun dockedStackDividerIsVisibleAtEnd() = testSpec.dockedStackDividerIsVisibleAtEnd()
-
- @Presubmit
- @Test
- fun bothAppsWindowsAreVisibleAtEnd() {
- testSpec.assertWmEnd {
- isAppWindowVisible(splitScreenApp.component)
- isAppWindowVisible(nonResizeableApp.component)
- }
- }
-
- @Presubmit
- @Test
- override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
- super.visibleLayersShownMoreThanOneConsecutiveEntry()
-
- @Presubmit
- @Test
- override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
- super.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
- companion object {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<FlickerTestParameter> {
- return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
- repetitions = SplitScreenHelper.TEST_REPETITIONS,
- supportedRotations = listOf(Surface.ROTATION_0)) // b/178685668
- }
- }
-}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenRotateTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenRotateTransition.kt
deleted file mode 100644
index b01f41c..0000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenRotateTransition.kt
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.flicker.legacysplitscreen
-
-import android.view.Surface
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.openQuickStepAndClearRecentAppsFromOverview
-import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
-
-abstract class LegacySplitScreenRotateTransition(
- testSpec: FlickerTestParameter
-) : LegacySplitScreenTransition(testSpec) {
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- setup {
- eachRun {
- device.wakeUpAndGoToHomeScreen()
- device.openQuickStepAndClearRecentAppsFromOverview(wmHelper)
- secondaryApp.launchViaIntent(wmHelper)
- splitScreenApp.launchViaIntent(wmHelper)
- }
- }
- teardown {
- eachRun {
- splitScreenApp.exit(wmHelper)
- secondaryApp.exit(wmHelper)
- this.setRotation(Surface.ROTATION_0)
- }
- }
- }
-}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt
deleted file mode 100644
index fb1004b..0000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt
+++ /dev/null
@@ -1,160 +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.wm.shell.flicker.legacysplitscreen
-
-import android.platform.test.annotations.Presubmit
-import android.view.Surface
-import androidx.test.filters.FlakyTest
-import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.annotation.Group2
-import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.entireScreenCovered
-import com.android.server.wm.flicker.helpers.exitSplitScreen
-import com.android.server.wm.flicker.helpers.launchSplitScreen
-import com.android.server.wm.flicker.helpers.openQuickStepAndClearRecentAppsFromOverview
-import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
-import com.android.server.wm.flicker.navBarLayerIsVisible
-import com.android.server.wm.flicker.navBarLayerRotatesAndScales
-import com.android.server.wm.flicker.navBarWindowIsVisible
-import com.android.server.wm.flicker.statusBarLayerIsVisible
-import com.android.server.wm.flicker.statusBarLayerRotatesScales
-import com.android.server.wm.flicker.statusBarWindowIsVisible
-import com.android.server.wm.traces.common.FlickerComponentName
-import com.android.wm.shell.flicker.dockedStackDividerBecomesInvisible
-import com.android.wm.shell.flicker.helpers.SimpleAppHelper
-import org.junit.FixMethodOrder
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/**
- * Test open app to split screen.
- * To run this test: `atest WMShellFlickerTests:LegacySplitScreenToLauncher`
- */
-@RequiresDevice
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Group2
-class LegacySplitScreenToLauncher(
- testSpec: FlickerTestParameter
-) : LegacySplitScreenTransition(testSpec) {
- private val testApp = SimpleAppHelper(instrumentation)
-
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- setup {
- test {
- device.wakeUpAndGoToHomeScreen()
- device.openQuickStepAndClearRecentAppsFromOverview(wmHelper)
- }
- eachRun {
- testApp.launchViaIntent(wmHelper)
- this.setRotation(testSpec.endRotation)
- device.launchSplitScreen(wmHelper)
- device.waitForIdle()
- }
- }
- teardown {
- eachRun {
- testApp.exit(wmHelper)
- }
- }
- transitions {
- device.exitSplitScreen()
- }
- }
-
- override val ignoredWindows: List<FlickerComponentName>
- get() = listOf(LAUNCHER_COMPONENT, FlickerComponentName.SPLASH_SCREEN,
- FlickerComponentName.SNAPSHOT)
-
- @Presubmit
- @Test
- fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible()
-
- @Presubmit
- @Test
- fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible()
-
- @Presubmit
- @Test
- fun navBarLayerIsVisible() = testSpec.navBarLayerIsVisible()
-
- @Presubmit
- @Test
- fun entireScreenCovered() = testSpec.entireScreenCovered()
-
- @Presubmit
- @Test
- fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales()
-
- @FlakyTest(bugId = 206753786)
- @Test
- fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales()
-
- @Presubmit
- @Test
- fun statusBarLayerIsVisible() = testSpec.statusBarLayerIsVisible()
-
- @FlakyTest
- @Test
- fun dockedStackDividerBecomesInvisible() = testSpec.dockedStackDividerBecomesInvisible()
-
- @FlakyTest
- @Test
- fun layerBecomesInvisible() {
- testSpec.assertLayers {
- this.isVisible(testApp.component)
- .then()
- .isInvisible(testApp.component)
- }
- }
-
- @FlakyTest
- @Test
- fun focusDoesNotChange() {
- testSpec.assertEventLog {
- this.focusDoesNotChange()
- }
- }
-
- @Presubmit
- @Test
- override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
- super.visibleLayersShownMoreThanOneConsecutiveEntry()
-
- @Presubmit
- @Test
- override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
- super.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
- companion object {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<FlickerTestParameter> {
- // b/161435597 causes the test not to work on 90 degrees
- return FlickerTestParameterFactory.getInstance()
- .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0))
- }
- }
-}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenTransition.kt
deleted file mode 100644
index a4a1f61..0000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenTransition.kt
+++ /dev/null
@@ -1,149 +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/LICENSE2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.flicker.legacysplitscreen
-
-import android.app.Instrumentation
-import android.content.Context
-import android.support.test.launcherhelper.LauncherStrategyFactory
-import android.view.Surface
-import androidx.test.filters.FlakyTest
-import androidx.test.platform.app.InstrumentationRegistry
-import com.android.server.wm.flicker.FlickerBuilderProvider
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.openQuickStepAndClearRecentAppsFromOverview
-import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
-import com.android.server.wm.traces.common.FlickerComponentName
-import com.android.wm.shell.flicker.helpers.BaseAppHelper.Companion.isShellTransitionsEnabled
-import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.getDevEnableNonResizableMultiWindow
-import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.setDevEnableNonResizableMultiWindow
-import com.android.wm.shell.flicker.helpers.SplitScreenHelper
-import org.junit.After
-import org.junit.Assume.assumeFalse
-import org.junit.Assume.assumeTrue
-import org.junit.Before
-import org.junit.Test
-
-abstract class LegacySplitScreenTransition(protected val testSpec: FlickerTestParameter) {
- protected val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
- protected val context: Context = instrumentation.context
- protected val splitScreenApp = SplitScreenHelper.getPrimary(instrumentation)
- protected val secondaryApp = SplitScreenHelper.getSecondary(instrumentation)
- protected val nonResizeableApp = SplitScreenHelper.getNonResizeable(instrumentation)
- protected val LAUNCHER_COMPONENT = FlickerComponentName("",
- LauncherStrategyFactory.getInstance(instrumentation)
- .launcherStrategy.supportedLauncherPackage)
- private var prevDevEnableNonResizableMultiWindow = 0
-
- @Before
- open fun setup() {
- // Only run legacy split tests when the system is using legacy split screen.
- assumeTrue(SplitScreenHelper.isUsingLegacySplit())
- // Legacy split is having some issue with Shell transition, and will be deprecated soon.
- assumeFalse(isShellTransitionsEnabled())
- prevDevEnableNonResizableMultiWindow = getDevEnableNonResizableMultiWindow(context)
- if (prevDevEnableNonResizableMultiWindow != 0) {
- // Turn off the development option
- setDevEnableNonResizableMultiWindow(context, 0)
- }
- }
-
- @After
- open fun teardown() {
- setDevEnableNonResizableMultiWindow(context, prevDevEnableNonResizableMultiWindow)
- }
-
- /**
- * List of windows that are ignored when verifying that visible elements appear on 2
- * consecutive entries in the trace.
- *
- * b/182720234
- */
- open val ignoredWindows: List<FlickerComponentName> = listOf(
- FlickerComponentName.SPLASH_SCREEN,
- FlickerComponentName.SNAPSHOT)
-
- protected open val transition: FlickerBuilder.() -> Unit
- get() = {
- setup {
- eachRun {
- device.wakeUpAndGoToHomeScreen()
- device.openQuickStepAndClearRecentAppsFromOverview(wmHelper)
- secondaryApp.launchViaIntent(wmHelper)
- splitScreenApp.launchViaIntent(wmHelper)
- this.setRotation(testSpec.startRotation)
- }
- }
- teardown {
- eachRun {
- secondaryApp.exit(wmHelper)
- splitScreenApp.exit(wmHelper)
- this.setRotation(Surface.ROTATION_0)
- }
- }
- }
-
- @FlickerBuilderProvider
- fun buildFlicker(): FlickerBuilder {
- return FlickerBuilder(instrumentation).apply {
- transition(this)
- }
- }
-
- internal open val cleanSetup: FlickerBuilder.() -> Unit
- get() = {
- setup {
- eachRun {
- device.wakeUpAndGoToHomeScreen()
- device.openQuickStepAndClearRecentAppsFromOverview(wmHelper)
- this.setRotation(testSpec.startRotation)
- }
- }
- teardown {
- eachRun {
- nonResizeableApp.exit(wmHelper)
- splitScreenApp.exit(wmHelper)
- device.pressHome()
- this.setRotation(Surface.ROTATION_0)
- }
- }
- }
-
- @FlakyTest(bugId = 178447631)
- @Test
- open fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
- testSpec.assertWm {
- this.visibleWindowsShownMoreThanOneConsecutiveEntry(ignoredWindows)
- }
- }
-
- @FlakyTest(bugId = 178447631)
- @Test
- open fun visibleLayersShownMoreThanOneConsecutiveEntry() {
- testSpec.assertLayers {
- this.visibleLayersShownMoreThanOneConsecutiveEntry(ignoredWindows)
- }
- }
-
- companion object {
- internal val LIVE_WALLPAPER_COMPONENT = FlickerComponentName("",
- "com.breel.wallpapers18.soundviz.wallpaper.variations.SoundVizWallpaperV2")
- internal val LETTERBOX_COMPONENT = FlickerComponentName("", "Letterbox")
- internal val TOAST_COMPONENT = FlickerComponentName("", "Toast")
- }
-}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OWNERS b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OWNERS
deleted file mode 100644
index 8446b37..0000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# window manager > wm shell > Split Screen
-# Bug component: 928697
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreen.kt
deleted file mode 100644
index 087b21c..0000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreen.kt
+++ /dev/null
@@ -1,122 +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.wm.shell.flicker.legacysplitscreen
-
-import android.platform.test.annotations.Presubmit
-import android.view.Surface
-import androidx.test.filters.FlakyTest
-import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.annotation.Group2
-import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.entireScreenCovered
-import com.android.server.wm.flicker.helpers.launchSplitScreen
-import com.android.server.wm.flicker.statusBarLayerIsVisible
-import com.android.server.wm.traces.common.FlickerComponentName
-import com.android.wm.shell.flicker.appPairsDividerBecomesVisible
-import com.android.wm.shell.flicker.helpers.SplitScreenHelper
-import org.junit.FixMethodOrder
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/**
- * Test open app to split screen.
- * To run this test: `atest WMShellFlickerTests:OpenAppToLegacySplitScreen`
- */
-@RequiresDevice
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Group2
-class OpenAppToLegacySplitScreen(
- testSpec: FlickerTestParameter
-) : LegacySplitScreenTransition(testSpec) {
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- super.transition(this)
- transitions {
- device.launchSplitScreen(wmHelper)
- wmHelper.waitForAppTransitionIdle()
- }
- }
-
- override val ignoredWindows: List<FlickerComponentName>
- get() = listOf(LAUNCHER_COMPONENT, splitScreenApp.component,
- FlickerComponentName.SPLASH_SCREEN,
- FlickerComponentName.SNAPSHOT)
-
- @FlakyTest
- @Test
- fun appWindowBecomesVisible() {
- testSpec.assertWm {
- this.isAppWindowInvisible(splitScreenApp.component)
- .then()
- .isAppWindowVisible(splitScreenApp.component)
- }
- }
-
- @Presubmit
- @Test
- fun entireScreenCovered() = testSpec.entireScreenCovered()
-
- @Presubmit
- @Test
- fun statusBarLayerIsVisible() = testSpec.statusBarLayerIsVisible()
-
- @Presubmit
- @Test
- fun appPairsDividerBecomesVisible() = testSpec.appPairsDividerBecomesVisible()
-
- @FlakyTest
- @Test
- fun layerBecomesVisible() {
- testSpec.assertLayers {
- this.isInvisible(splitScreenApp.component)
- .then()
- .isVisible(splitScreenApp.component)
- }
- }
-
- @Presubmit
- @Test
- fun focusChanges() {
- testSpec.assertEventLog {
- this.focusChanges(splitScreenApp.`package`,
- "recents_animation_input_consumer", "NexusLauncherActivity")
- }
- }
-
- @Presubmit
- @Test
- override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
- super.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
- companion object {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<FlickerTestParameter> {
- return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
- repetitions = SplitScreenHelper.TEST_REPETITIONS,
- supportedRotations = listOf(Surface.ROTATION_0) // bugId = 179116910
- )
- }
- }
-}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt
deleted file mode 100644
index e2da1a4..0000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt
+++ /dev/null
@@ -1,228 +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.wm.shell.flicker.legacysplitscreen
-
-import android.util.Rational
-import android.view.Surface
-import androidx.test.filters.FlakyTest
-import androidx.test.filters.RequiresDevice
-import androidx.test.uiautomator.By
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.annotation.Group2
-import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.entireScreenCovered
-import com.android.server.wm.flicker.helpers.ImeAppHelper
-import com.android.server.wm.flicker.helpers.WindowUtils
-import com.android.server.wm.flicker.helpers.launchSplitScreen
-import com.android.server.wm.flicker.helpers.resizeSplitScreen
-import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
-import com.android.server.wm.flicker.navBarLayerIsVisible
-import com.android.server.wm.flicker.navBarLayerRotatesAndScales
-import com.android.server.wm.flicker.navBarWindowIsVisible
-import com.android.server.wm.flicker.statusBarLayerIsVisible
-import com.android.server.wm.flicker.statusBarLayerRotatesScales
-import com.android.server.wm.flicker.statusBarWindowIsVisible
-import com.android.server.wm.traces.common.region.Region
-import com.android.server.wm.traces.parser.toFlickerComponent
-import com.android.wm.shell.flicker.DOCKED_STACK_DIVIDER_COMPONENT
-import com.android.wm.shell.flicker.helpers.SimpleAppHelper
-import com.android.wm.shell.flicker.testapp.Components
-import org.junit.FixMethodOrder
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/**
- * Test split screen resizing window transitions.
- * To run this test: `atest WMShellFlickerTests:ResizeLegacySplitScreen`
- *
- * Currently it runs only in 0 degrees because of b/156100803
- */
-@RequiresDevice
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@FlakyTest(bugId = 159096424)
-@Group2
-class ResizeLegacySplitScreen(
- testSpec: FlickerTestParameter
-) : LegacySplitScreenTransition(testSpec) {
- private val testAppTop = SimpleAppHelper(instrumentation)
- private val testAppBottom = ImeAppHelper(instrumentation)
-
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- setup {
- eachRun {
- device.wakeUpAndGoToHomeScreen()
- this.setRotation(testSpec.startRotation)
- this.launcherStrategy.clearRecentAppsFromOverview()
- testAppBottom.launchViaIntent(wmHelper)
- device.pressHome()
- testAppTop.launchViaIntent(wmHelper)
- device.waitForIdle()
- device.launchSplitScreen(wmHelper)
- val snapshot =
- device.findObject(By.res(device.launcherPackageName, "snapshot"))
- snapshot.click()
- testAppBottom.openIME(device)
- device.pressBack()
- device.resizeSplitScreen(startRatio)
- }
- }
- teardown {
- eachRun {
- testAppTop.exit(wmHelper)
- testAppBottom.exit(wmHelper)
- }
- }
- transitions {
- device.resizeSplitScreen(stopRatio)
- }
- }
-
- @Test
- fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible()
-
- @Test
- fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible()
-
- @FlakyTest(bugId = 156223549)
- @Test
- fun topAppWindowIsAlwaysVisible() {
- testSpec.assertWm {
- this.isAppWindowVisible(Components.SimpleActivity.COMPONENT.toFlickerComponent())
- }
- }
-
- @FlakyTest(bugId = 156223549)
- @Test
- fun bottomAppWindowIsAlwaysVisible() {
- testSpec.assertWm {
- this.isAppWindowVisible(Components.ImeActivity.COMPONENT.toFlickerComponent())
- }
- }
-
- @Test
- fun navBarLayerIsVisible() = testSpec.navBarLayerIsVisible()
-
- @Test
- fun statusBarLayerIsVisible() = testSpec.statusBarLayerIsVisible()
-
- @Test
- fun entireScreenCovered() = testSpec.entireScreenCovered()
-
- @Test
- fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales()
-
- @FlakyTest(bugId = 206753786)
- @Test
- fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales()
-
- @Test
- fun topAppLayerIsAlwaysVisible() {
- testSpec.assertLayers {
- this.isVisible(Components.SimpleActivity.COMPONENT.toFlickerComponent())
- }
- }
-
- @Test
- fun bottomAppLayerIsAlwaysVisible() {
- testSpec.assertLayers {
- this.isVisible(Components.ImeActivity.COMPONENT.toFlickerComponent())
- }
- }
-
- @Test
- fun dividerLayerIsAlwaysVisible() {
- testSpec.assertLayers {
- this.isVisible(DOCKED_STACK_DIVIDER_COMPONENT)
- }
- }
-
- @FlakyTest
- @Test
- fun appsStartingBounds() {
- testSpec.assertLayersStart {
- val displayBounds = WindowUtils.displayBounds
- val dividerBounds =
- layer(DOCKED_STACK_DIVIDER_COMPONENT).visibleRegion.region.bounds
-
- val topAppBounds = Region.from(0, 0, dividerBounds.right,
- dividerBounds.top + WindowUtils.dockedStackDividerInset)
- val bottomAppBounds = Region.from(0,
- dividerBounds.bottom - WindowUtils.dockedStackDividerInset,
- displayBounds.right,
- displayBounds.bottom - WindowUtils.navigationBarFrameHeight)
- visibleRegion(Components.SimpleActivity.COMPONENT.toFlickerComponent())
- .coversExactly(topAppBounds)
- visibleRegion(Components.ImeActivity.COMPONENT.toFlickerComponent())
- .coversExactly(bottomAppBounds)
- }
- }
-
- @FlakyTest
- @Test
- fun appsEndingBounds() {
- testSpec.assertLayersStart {
- val displayBounds = WindowUtils.displayBounds
- val dividerBounds =
- layer(DOCKED_STACK_DIVIDER_COMPONENT).visibleRegion.region.bounds
-
- val topAppBounds = Region.from(0, 0, dividerBounds.right,
- dividerBounds.top + WindowUtils.dockedStackDividerInset)
- val bottomAppBounds = Region.from(0,
- dividerBounds.bottom - WindowUtils.dockedStackDividerInset,
- displayBounds.right,
- displayBounds.bottom - WindowUtils.navigationBarFrameHeight)
-
- visibleRegion(Components.SimpleActivity.COMPONENT.toFlickerComponent())
- .coversExactly(topAppBounds)
- visibleRegion(Components.ImeActivity.COMPONENT.toFlickerComponent())
- .coversExactly(bottomAppBounds)
- }
- }
-
- @Test
- fun focusDoesNotChange() {
- testSpec.assertEventLog {
- focusDoesNotChange()
- }
- }
-
- companion object {
- private val startRatio = Rational(1, 3)
- private val stopRatio = Rational(2, 3)
-
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<FlickerTestParameter> {
- return FlickerTestParameterFactory.getInstance()
- .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0))
- .map {
- val description = (startRatio.toString().replace("/", "-") + "_to_" +
- stopRatio.toString().replace("/", "-"))
- val newName = "${FlickerTestParameter.defaultName(it)}_$description"
- FlickerTestParameter(it.config, nameOverride = newName)
- }
- }
- }
-}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppAndEnterSplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppAndEnterSplitScreen.kt
deleted file mode 100644
index d703ea0..0000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppAndEnterSplitScreen.kt
+++ /dev/null
@@ -1,114 +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.wm.shell.flicker.legacysplitscreen
-
-import android.platform.test.annotations.Presubmit
-import android.view.Surface
-import androidx.test.filters.FlakyTest
-import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.annotation.Group2
-import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.launchSplitScreen
-import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.navBarLayerRotatesAndScales
-import com.android.server.wm.flicker.navBarWindowIsVisible
-import com.android.server.wm.flicker.statusBarLayerRotatesScales
-import com.android.server.wm.flicker.statusBarWindowIsVisible
-import com.android.wm.shell.flicker.dockedStackDividerIsVisibleAtEnd
-import com.android.wm.shell.flicker.dockedStackPrimaryBoundsIsVisibleAtEnd
-import com.android.wm.shell.flicker.helpers.SplitScreenHelper
-import org.junit.FixMethodOrder
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/**
- * Test dock activity to primary split screen and rotate
- * To run this test: `atest WMShellFlickerTests:RotateOneLaunchedAppAndEnterSplitScreen`
- */
-@RequiresDevice
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Group2
-class RotateOneLaunchedAppAndEnterSplitScreen(
- testSpec: FlickerTestParameter
-) : LegacySplitScreenRotateTransition(testSpec) {
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- super.transition(this)
- transitions {
- device.launchSplitScreen(wmHelper)
- this.setRotation(testSpec.startRotation)
- }
- }
-
- @Presubmit
- @Test
- fun dockedStackDividerIsVisibleAtEnd() = testSpec.dockedStackDividerIsVisibleAtEnd()
-
- @Presubmit
- @Test
- fun dockedStackPrimaryBoundsIsVisibleAtEnd() =
- testSpec.dockedStackPrimaryBoundsIsVisibleAtEnd(testSpec.startRotation,
- splitScreenApp.component)
-
- @Presubmit
- @Test
- fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales()
-
- @FlakyTest(bugId = 206753786)
- @Test
- fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales()
-
- @Presubmit
- @Test
- fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible()
-
- @Presubmit
- @Test
- fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible()
-
- @FlakyTest
- @Test
- fun appWindowBecomesVisible() {
- testSpec.assertWm {
- this.isAppWindowInvisible(splitScreenApp.component)
- .then()
- .isAppWindowVisible(splitScreenApp.component)
- }
- }
-
- @Presubmit
- @Test
- override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
- super.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
- companion object {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<FlickerTestParameter> {
- return FlickerTestParameterFactory.getInstance()
- .getConfigNonRotationTests(repetitions = SplitScreenHelper.TEST_REPETITIONS,
- supportedRotations = listOf(Surface.ROTATION_0)) // b/178685668
- }
- }
-}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppInSplitScreenMode.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppInSplitScreenMode.kt
deleted file mode 100644
index 6b18839..0000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppInSplitScreenMode.kt
+++ /dev/null
@@ -1,113 +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.wm.shell.flicker.legacysplitscreen
-
-import android.platform.test.annotations.Presubmit
-import android.view.Surface
-import androidx.test.filters.FlakyTest
-import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.annotation.Group2
-import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.launchSplitScreen
-import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.navBarLayerRotatesAndScales
-import com.android.server.wm.flicker.navBarWindowIsVisible
-import com.android.server.wm.flicker.statusBarLayerRotatesScales
-import com.android.server.wm.flicker.statusBarWindowIsVisible
-import com.android.wm.shell.flicker.dockedStackDividerIsVisibleAtEnd
-import com.android.wm.shell.flicker.dockedStackPrimaryBoundsIsVisibleAtEnd
-import com.android.wm.shell.flicker.helpers.SplitScreenHelper
-import org.junit.FixMethodOrder
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/**
- * Rotate
- * To run this test: `atest WMShellFlickerTests:RotateOneLaunchedAppInSplitScreenMode`
- */
-@RequiresDevice
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Group2
-class RotateOneLaunchedAppInSplitScreenMode(
- testSpec: FlickerTestParameter
-) : LegacySplitScreenRotateTransition(testSpec) {
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- super.transition(this)
- transitions {
- this.setRotation(testSpec.startRotation)
- device.launchSplitScreen(wmHelper)
- }
- }
-
- @Presubmit
- @Test
- fun dockedStackDividerIsVisibleAtEnd() = testSpec.dockedStackDividerIsVisibleAtEnd()
-
- @Presubmit
- @Test
- fun dockedStackPrimaryBoundsIsVisibleAtEnd() = testSpec.dockedStackPrimaryBoundsIsVisibleAtEnd(
- testSpec.startRotation, splitScreenApp.component)
-
- @Presubmit
- @Test
- fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales()
-
- @FlakyTest(bugId = 206753786)
- @Test
- fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales()
-
- @Presubmit
- @Test
- fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible()
-
- @Presubmit
- @Test
- fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible()
-
- @FlakyTest
- @Test
- fun appWindowBecomesVisible() {
- testSpec.assertWm {
- this.isAppWindowInvisible(splitScreenApp.component)
- .then()
- .isAppWindowVisible(splitScreenApp.component)
- }
- }
-
- @Presubmit
- @Test
- override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
- super.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
- companion object {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<FlickerTestParameter> {
- return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
- repetitions = SplitScreenHelper.TEST_REPETITIONS,
- supportedRotations = listOf(Surface.ROTATION_0)) // b/178685668
- }
- }
-}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppAndEnterSplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppAndEnterSplitScreen.kt
deleted file mode 100644
index acd658b..0000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppAndEnterSplitScreen.kt
+++ /dev/null
@@ -1,136 +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.wm.shell.flicker.legacysplitscreen
-
-import android.platform.test.annotations.Presubmit
-import android.view.Surface
-import androidx.test.filters.FlakyTest
-import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.annotation.Group2
-import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.launchSplitScreen
-import com.android.server.wm.flicker.helpers.reopenAppFromOverview
-import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.navBarLayerRotatesAndScales
-import com.android.server.wm.flicker.navBarWindowIsVisible
-import com.android.server.wm.flicker.statusBarLayerRotatesScales
-import com.android.server.wm.flicker.statusBarWindowIsVisible
-import com.android.wm.shell.flicker.dockedStackDividerIsVisibleAtEnd
-import com.android.wm.shell.flicker.dockedStackPrimaryBoundsIsVisibleAtEnd
-import com.android.wm.shell.flicker.dockedStackSecondaryBoundsIsVisibleAtEnd
-import com.android.wm.shell.flicker.helpers.SplitScreenHelper
-import org.junit.FixMethodOrder
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/**
- * Test open app to split screen.
- * To run this test: `atest WMShellFlickerTests:RotateTwoLaunchedAppAndEnterSplitScreen`
- */
-@RequiresDevice
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Group2
-class RotateTwoLaunchedAppAndEnterSplitScreen(
- testSpec: FlickerTestParameter
-) : LegacySplitScreenRotateTransition(testSpec) {
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- super.transition(this)
- transitions {
- this.setRotation(testSpec.startRotation)
- device.launchSplitScreen(wmHelper)
- device.reopenAppFromOverview(wmHelper)
- }
- }
-
- @Presubmit
- @Test
- fun dockedStackDividerIsVisibleAtEnd() = testSpec.dockedStackDividerIsVisibleAtEnd()
-
- @Presubmit
- @Test
- fun dockedStackPrimaryBoundsIsVisibleAtEnd() =
- testSpec.dockedStackPrimaryBoundsIsVisibleAtEnd(testSpec.startRotation,
- splitScreenApp.component)
-
- @Presubmit
- @Test
- fun dockedStackSecondaryBoundsIsVisibleAtEnd() =
- testSpec.dockedStackSecondaryBoundsIsVisibleAtEnd(testSpec.startRotation,
- secondaryApp.component)
-
- @Presubmit
- @Test
- fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales()
-
- @FlakyTest(bugId = 206753786)
- @Test
- fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales()
-
- @Presubmit
- @Test
- fun appWindowBecomesVisible() {
- testSpec.assertWm {
- // when the app is launched, first the activity becomes visible, then the
- // SnapshotStartingWindow appears and then the app window becomes visible.
- // Because we log WM once per frame, sometimes the activity and the window
- // become visible in the same entry, sometimes not, thus it is not possible to
- // assert the visibility of the activity here
- this.isAppWindowInvisible(secondaryApp.component)
- .then()
- // during re-parenting, the window may disappear and reappear from the
- // trace, this occurs because we log only 1x per frame
- .notContains(secondaryApp.component, isOptional = true)
- .then()
- // if the window reappears after re-parenting it will most likely not
- // be visible in the first log entry (because we log only 1x per frame)
- .isAppWindowInvisible(secondaryApp.component, isOptional = true)
- .then()
- .isAppWindowVisible(secondaryApp.component)
- }
- }
-
- @Presubmit
- @Test
- fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible()
-
- @Presubmit
- @Test
- fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible()
-
- @Presubmit
- @Test
- override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
- super.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
- companion object {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<FlickerTestParameter> {
- return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
- repetitions = SplitScreenHelper.TEST_REPETITIONS,
- supportedRotations = listOf(Surface.ROTATION_0)) // b/178685668
- }
- }
-}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppInSplitScreenMode.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppInSplitScreenMode.kt
deleted file mode 100644
index b40be8b..0000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppInSplitScreenMode.kt
+++ /dev/null
@@ -1,133 +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.wm.shell.flicker.legacysplitscreen
-
-import android.platform.test.annotations.Presubmit
-import android.view.Surface
-import androidx.test.filters.FlakyTest
-import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.annotation.Group2
-import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.launchSplitScreen
-import com.android.server.wm.flicker.helpers.reopenAppFromOverview
-import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.navBarLayerRotatesAndScales
-import com.android.server.wm.flicker.navBarWindowIsVisible
-import com.android.server.wm.flicker.statusBarLayerRotatesScales
-import com.android.server.wm.flicker.statusBarWindowIsVisible
-import com.android.wm.shell.flicker.dockedStackDividerIsVisibleAtEnd
-import com.android.wm.shell.flicker.dockedStackPrimaryBoundsIsVisibleAtEnd
-import com.android.wm.shell.flicker.dockedStackSecondaryBoundsIsVisibleAtEnd
-import com.android.wm.shell.flicker.helpers.SplitScreenHelper
-import org.junit.FixMethodOrder
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/**
- * Test open app to split screen.
- * To run this test: `atest WMShellFlickerTests:RotateTwoLaunchedAppInSplitScreenMode`
- */
-@RequiresDevice
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Group2
-class RotateTwoLaunchedAppInSplitScreenMode(
- testSpec: FlickerTestParameter
-) : LegacySplitScreenRotateTransition(testSpec) {
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- super.transition(this)
- setup {
- eachRun {
- device.launchSplitScreen(wmHelper)
- device.reopenAppFromOverview(wmHelper)
- this.setRotation(testSpec.startRotation)
- }
- }
- transitions {
- this.setRotation(testSpec.startRotation)
- }
- }
-
- @Presubmit
- @Test
- fun dockedStackDividerIsVisibleAtEnd() = testSpec.dockedStackDividerIsVisibleAtEnd()
-
- @Presubmit
- @Test
- fun dockedStackPrimaryBoundsIsVisibleAtEnd() =
- testSpec.dockedStackPrimaryBoundsIsVisibleAtEnd(testSpec.startRotation,
- splitScreenApp.component)
-
- @Presubmit
- @Test
- fun dockedStackSecondaryBoundsIsVisibleAtEnd() =
- testSpec.dockedStackSecondaryBoundsIsVisibleAtEnd(testSpec.startRotation,
- secondaryApp.component)
-
- @Presubmit
- @Test
- fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales()
-
- @FlakyTest(bugId = 206753786)
- @Test
- fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales()
-
- @FlakyTest
- @Test
- fun appWindowBecomesVisible() {
- testSpec.assertWm {
- this.isAppWindowInvisible(secondaryApp.component)
- .then()
- .isAppWindowVisible(secondaryApp.component)
- }
- }
-
- @Presubmit
- @Test
- fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible()
-
- @Presubmit
- @Test
- fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible()
-
- @Presubmit
- @Test
- override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
- super.visibleLayersShownMoreThanOneConsecutiveEntry()
-
- @Presubmit
- @Test
- override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
- super.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
- companion object {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<FlickerTestParameter> {
- return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
- repetitions = SplitScreenHelper.TEST_REPETITIONS,
- supportedRotations = listOf(Surface.ROTATION_0)) // b/178685668
- }
- }
-}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt
deleted file mode 100644
index 21175a0..0000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt
+++ /dev/null
@@ -1,148 +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.wm.shell.flicker.pip
-
-import android.platform.test.annotations.Presubmit
-import android.view.Surface
-import androidx.test.filters.FlakyTest
-import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.annotation.Group4
-import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.launchSplitScreen
-import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
-import com.android.server.wm.flicker.rules.RemoveAllTasksButHomeRule.Companion.removeAllTasksButHome
-import com.android.wm.shell.flicker.helpers.BaseAppHelper.Companion.isShellTransitionsEnabled
-import com.android.wm.shell.flicker.helpers.FixedAppHelper
-import com.android.wm.shell.flicker.helpers.ImeAppHelper
-import com.android.wm.shell.flicker.helpers.SplitScreenHelper
-import com.android.wm.shell.flicker.testapp.Components.PipActivity.EXTRA_ENTER_PIP
-import org.junit.Assume.assumeFalse
-import org.junit.Assume.assumeTrue
-import org.junit.Before
-import org.junit.FixMethodOrder
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/**
- * Test Pip with split-screen.
- * To run this test: `atest WMShellFlickerTests:PipLegacySplitScreenTest`
- */
-@RequiresDevice
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Group4
-class PipLegacySplitScreenTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
- private val imeApp = ImeAppHelper(instrumentation)
- private val testApp = FixedAppHelper(instrumentation)
-
- @Before
- open fun setup() {
- // Only run legacy split tests when the system is using legacy split screen.
- assumeTrue(SplitScreenHelper.isUsingLegacySplit())
- // Legacy split is having some issue with Shell transition, and will be deprecated soon.
- assumeFalse(isShellTransitionsEnabled())
- }
-
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- setup {
- test {
- removeAllTasksButHome()
- device.wakeUpAndGoToHomeScreen()
- pipApp.launchViaIntent(stringExtras = mapOf(EXTRA_ENTER_PIP to "true"),
- wmHelper = wmHelper)
- }
- }
- transitions {
- testApp.launchViaIntent(wmHelper)
- device.launchSplitScreen(wmHelper)
- imeApp.launchViaIntent(wmHelper)
- }
- teardown {
- eachRun {
- imeApp.exit(wmHelper)
- testApp.exit(wmHelper)
- }
- test {
- removeAllTasksButHome()
- }
- }
- }
-
- /** {@inheritDoc} */
- @FlakyTest(bugId = 206753786)
- @Test
- override fun statusBarLayerRotatesScales() = super.statusBarLayerRotatesScales()
-
- @FlakyTest(bugId = 161435597)
- @Test
- fun pipWindowInsideDisplayBounds() {
- testSpec.assertWmVisibleRegion(pipApp.component) {
- coversAtMost(displayBounds)
- }
- }
-
- @Presubmit
- @Test
- fun bothAppWindowsVisible() {
- testSpec.assertWmEnd {
- isAppWindowVisible(testApp.component)
- isAppWindowVisible(imeApp.component)
- doNotOverlap(testApp.component, imeApp.component)
- }
- }
-
- @FlakyTest(bugId = 161435597)
- @Test
- fun pipLayerInsideDisplayBounds() {
- testSpec.assertLayersVisibleRegion(pipApp.component) {
- coversAtMost(displayBounds)
- }
- }
-
- @Presubmit
- @Test
- fun bothAppLayersVisible() {
- testSpec.assertLayersEnd {
- visibleRegion(testApp.component).coversAtMost(displayBounds)
- visibleRegion(imeApp.component).coversAtMost(displayBounds)
- }
- }
-
- @FlakyTest(bugId = 161435597)
- @Test
- override fun entireScreenCovered() = super.entireScreenCovered()
-
- companion object {
- const val TEST_REPETITIONS = 2
-
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<FlickerTestParameter> {
- return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
- supportedRotations = listOf(Surface.ROTATION_0),
- repetitions = TEST_REPETITIONS
- )
- }
- }
-}
diff --git a/libs/WindowManager/Shell/tests/unittest/Android.bp b/libs/WindowManager/Shell/tests/unittest/Android.bp
index fb53e535..c5ec5bb 100644
--- a/libs/WindowManager/Shell/tests/unittest/Android.bp
+++ b/libs/WindowManager/Shell/tests/unittest/Android.bp
@@ -37,6 +37,7 @@
"androidx.test.ext.junit",
"androidx.dynamicanimation_dynamicanimation",
"dagger2",
+ "frameworks-base-testutils",
"kotlinx-coroutines-android",
"kotlinx-coroutines-core",
"mockito-target-extended-minus-junit4",
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairTests.java
deleted file mode 100644
index e73d9aa..0000000
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairTests.java
+++ /dev/null
@@ -1,123 +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.wm.shell.apppairs;
-
-import static android.view.Display.DEFAULT_DISPLAY;
-
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.app.ActivityManager;
-import android.hardware.display.DisplayManager;
-
-import androidx.test.annotation.UiThreadTest;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import com.android.wm.shell.ShellTaskOrganizer;
-import com.android.wm.shell.ShellTestCase;
-import com.android.wm.shell.TestRunningTaskInfoBuilder;
-import com.android.wm.shell.common.DisplayController;
-import com.android.wm.shell.common.SyncTransactionQueue;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-/**
- * Tests for {@link AppPair}
- * Build/Install/Run:
- * atest WMShellUnitTests:AppPairTests
- */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class AppPairTests extends ShellTestCase {
-
- private AppPairsController mController;
- @Mock private SyncTransactionQueue mSyncQueue;
- @Mock private ShellTaskOrganizer mTaskOrganizer;
- @Mock private DisplayController mDisplayController;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- when(mDisplayController.getDisplayContext(anyInt())).thenReturn(mContext);
- when(mDisplayController.getDisplay(anyInt())).thenReturn(
- mContext.getSystemService(DisplayManager.class).getDisplay(DEFAULT_DISPLAY));
- mController = new TestAppPairsController(
- mTaskOrganizer,
- mSyncQueue,
- mDisplayController);
- spyOn(mController);
- }
-
- @After
- public void tearDown() {}
-
- @Test
- @UiThreadTest
- public void testContains() {
- final ActivityManager.RunningTaskInfo task1 = new TestRunningTaskInfoBuilder().build();
- final ActivityManager.RunningTaskInfo task2 = new TestRunningTaskInfoBuilder().build();
-
- final AppPair pair = mController.pairInner(task1, task2);
- assertThat(pair.contains(task1.taskId)).isTrue();
- assertThat(pair.contains(task2.taskId)).isTrue();
-
- pair.unpair();
- assertThat(pair.contains(task1.taskId)).isFalse();
- assertThat(pair.contains(task2.taskId)).isFalse();
- }
-
- @Test
- @UiThreadTest
- public void testVanishUnpairs() {
- final ActivityManager.RunningTaskInfo task1 = new TestRunningTaskInfoBuilder().build();
- final ActivityManager.RunningTaskInfo task2 = new TestRunningTaskInfoBuilder().build();
-
- final AppPair pair = mController.pairInner(task1, task2);
- assertThat(pair.contains(task1.taskId)).isTrue();
- assertThat(pair.contains(task2.taskId)).isTrue();
-
- pair.onTaskVanished(task1);
- assertThat(pair.contains(task1.taskId)).isFalse();
- assertThat(pair.contains(task2.taskId)).isFalse();
- }
-
- @Test
- @UiThreadTest
- public void testOnTaskInfoChanged_notSupportsMultiWindow() {
- final ActivityManager.RunningTaskInfo task1 = new TestRunningTaskInfoBuilder().build();
- final ActivityManager.RunningTaskInfo task2 = new TestRunningTaskInfoBuilder().build();
-
- final AppPair pair = mController.pairInner(task1, task2);
- assertThat(pair.contains(task1.taskId)).isTrue();
- assertThat(pair.contains(task2.taskId)).isTrue();
-
- task1.supportsMultiWindow = false;
- pair.onTaskInfoChanged(task1);
- verify(mController).unpair(pair.getRootTaskId());
- }
-}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairsControllerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairsControllerTests.java
deleted file mode 100644
index 505c153..0000000
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairsControllerTests.java
+++ /dev/null
@@ -1,104 +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.wm.shell.apppairs;
-
-import static android.view.Display.DEFAULT_DISPLAY;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Mockito.when;
-
-import android.app.ActivityManager;
-import android.hardware.display.DisplayManager;
-
-import androidx.test.annotation.UiThreadTest;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import com.android.wm.shell.ShellTaskOrganizer;
-import com.android.wm.shell.ShellTestCase;
-import com.android.wm.shell.TestRunningTaskInfoBuilder;
-import com.android.wm.shell.common.DisplayController;
-import com.android.wm.shell.common.SyncTransactionQueue;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-/** Tests for {@link AppPairsController} */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class AppPairsControllerTests extends ShellTestCase {
- private TestAppPairsController mController;
- private TestAppPairsPool mPool;
- @Mock private SyncTransactionQueue mSyncQueue;
- @Mock private ShellTaskOrganizer mTaskOrganizer;
- @Mock private DisplayController mDisplayController;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- when(mDisplayController.getDisplayContext(anyInt())).thenReturn(mContext);
- when(mDisplayController.getDisplay(anyInt())).thenReturn(
- mContext.getSystemService(DisplayManager.class).getDisplay(DEFAULT_DISPLAY));
- mController = new TestAppPairsController(
- mTaskOrganizer,
- mSyncQueue,
- mDisplayController);
- mPool = mController.getPool();
- }
-
- @After
- public void tearDown() {}
-
- @Test
- @UiThreadTest
- public void testPairUnpair() {
- final ActivityManager.RunningTaskInfo task1 = new TestRunningTaskInfoBuilder().build();
- final ActivityManager.RunningTaskInfo task2 = new TestRunningTaskInfoBuilder().build();
-
- final AppPair pair = mController.pairInner(task1, task2);
- assertThat(pair.contains(task1.taskId)).isTrue();
- assertThat(pair.contains(task2.taskId)).isTrue();
- assertThat(mPool.poolSize()).isGreaterThan(0);
-
- mController.unpair(task2.taskId);
- assertThat(pair.contains(task1.taskId)).isFalse();
- assertThat(pair.contains(task2.taskId)).isFalse();
- assertThat(mPool.poolSize()).isGreaterThan(1);
- }
-
- @Test
- @UiThreadTest
- public void testUnpair_DontReleaseToPool() {
- final ActivityManager.RunningTaskInfo task1 = new TestRunningTaskInfoBuilder().build();
- final ActivityManager.RunningTaskInfo task2 = new TestRunningTaskInfoBuilder().build();
-
- final AppPair pair = mController.pairInner(task1, task2);
- assertThat(pair.contains(task1.taskId)).isTrue();
- assertThat(pair.contains(task2.taskId)).isTrue();
-
- mController.unpair(task2.taskId, false /* releaseToPool */);
- assertThat(pair.contains(task1.taskId)).isFalse();
- assertThat(pair.contains(task2.taskId)).isFalse();
- assertThat(mPool.poolSize()).isEqualTo(1);
- }
-}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairsPoolTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairsPoolTests.java
deleted file mode 100644
index a3f134e..0000000
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairsPoolTests.java
+++ /dev/null
@@ -1,77 +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.wm.shell.apppairs;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Mockito.when;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import com.android.wm.shell.ShellTaskOrganizer;
-import com.android.wm.shell.ShellTestCase;
-import com.android.wm.shell.common.DisplayController;
-import com.android.wm.shell.common.SyncTransactionQueue;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-/** Tests for {@link AppPairsPool} */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class AppPairsPoolTests extends ShellTestCase {
- private TestAppPairsController mController;
- private TestAppPairsPool mPool;
- @Mock private SyncTransactionQueue mSyncQueue;
- @Mock private ShellTaskOrganizer mTaskOrganizer;
- @Mock private DisplayController mDisplayController;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- when(mDisplayController.getDisplayContext(anyInt())).thenReturn(mContext);
- mController = new TestAppPairsController(
- mTaskOrganizer,
- mSyncQueue,
- mDisplayController);
- mPool = mController.getPool();
- }
-
- @After
- public void tearDown() {}
-
- @Test
- public void testInitialState() {
- // Pool should always start off with at least 1 entry.
- assertThat(mPool.poolSize()).isGreaterThan(0);
- }
-
- @Test
- public void testAcquireRelease() {
- assertThat(mPool.poolSize()).isGreaterThan(0);
- final AppPair appPair = mPool.acquire();
- assertThat(mPool.poolSize()).isGreaterThan(0);
- mPool.release(appPair);
- assertThat(mPool.poolSize()).isGreaterThan(1);
- }
-}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/TestAppPairsController.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/TestAppPairsController.java
deleted file mode 100644
index 294bc12..0000000
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/TestAppPairsController.java
+++ /dev/null
@@ -1,42 +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.wm.shell.apppairs;
-
-import static org.mockito.Mockito.mock;
-
-import com.android.wm.shell.ShellTaskOrganizer;
-import com.android.wm.shell.common.DisplayController;
-import com.android.wm.shell.common.DisplayImeController;
-import com.android.wm.shell.common.DisplayInsetsController;
-import com.android.wm.shell.common.ShellExecutor;
-import com.android.wm.shell.common.SyncTransactionQueue;
-
-public class TestAppPairsController extends AppPairsController {
- private TestAppPairsPool mPool;
-
- public TestAppPairsController(ShellTaskOrganizer organizer, SyncTransactionQueue syncQueue,
- DisplayController displayController) {
- super(organizer, syncQueue, displayController, mock(ShellExecutor.class),
- mock(DisplayImeController.class), mock(DisplayInsetsController.class));
- mPool = new TestAppPairsPool(this);
- setPairsPool(mPool);
- }
-
- TestAppPairsPool getPool() {
- return mPool;
- }
-}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/TestAppPairsPool.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/TestAppPairsPool.java
deleted file mode 100644
index 1ee7fff..0000000
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/TestAppPairsPool.java
+++ /dev/null
@@ -1,36 +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.wm.shell.apppairs;
-
-import android.app.ActivityManager;
-
-import com.android.wm.shell.TestRunningTaskInfoBuilder;
-
-public class TestAppPairsPool extends AppPairsPool{
- TestAppPairsPool(AppPairsController controller) {
- super(controller);
- }
-
- @Override
- void incrementPool() {
- final AppPair entry = new AppPair(mController);
- final ActivityManager.RunningTaskInfo info =
- new TestRunningTaskInfoBuilder().build();
- entry.onTaskAppeared(info, null /* leash */);
- release(entry);
- }
-}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
index 1ce2444..5d94ca5 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
@@ -26,7 +26,9 @@
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
import android.app.IActivityTaskManager;
import android.app.WindowConfiguration;
@@ -47,7 +49,6 @@
import androidx.test.filters.SmallTest;
import com.android.wm.shell.TestShellExecutor;
-import com.android.wm.shell.common.ShellExecutor;
import org.junit.Before;
import org.junit.Ignore;
@@ -64,7 +65,7 @@
@RunWith(AndroidTestingRunner.class)
public class BackAnimationControllerTest {
- private final ShellExecutor mShellExecutor = new TestShellExecutor();
+ private final TestShellExecutor mShellExecutor = new TestShellExecutor();
@Mock
private Context mContext;
@@ -221,4 +222,60 @@
BackEvent.EDGE_LEFT);
verify(mIOnBackInvokedCallback).onBackInvoked();
}
+
+ @Test
+ public void ignoresGesture_transitionInProgress() throws RemoteException {
+ mController.setBackToLauncherCallback(mIOnBackInvokedCallback);
+ RemoteAnimationTarget animationTarget = createAnimationTarget();
+ createNavigationInfo(animationTarget, null, null,
+ BackNavigationInfo.TYPE_RETURN_TO_HOME);
+
+ triggerBackGesture();
+ // Check that back invocation is dispatched.
+ verify(mIOnBackInvokedCallback).onBackInvoked();
+
+ reset(mIOnBackInvokedCallback);
+ // Verify that we prevent animation from restarting if another gestures happens before
+ // the previous transition is finished.
+ mController.onMotionEvent(
+ MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0),
+ MotionEvent.ACTION_DOWN,
+ BackEvent.EDGE_LEFT);
+ verifyNoMoreInteractions(mIOnBackInvokedCallback);
+
+ // Verify that we start accepting gestures again once transition finishes.
+ mController.onBackToLauncherAnimationFinished();
+ mController.onMotionEvent(
+ MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0),
+ MotionEvent.ACTION_DOWN,
+ BackEvent.EDGE_LEFT);
+ mController.onMotionEvent(
+ MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 100, 100, 0),
+ MotionEvent.ACTION_MOVE,
+ BackEvent.EDGE_LEFT);
+ verify(mIOnBackInvokedCallback).onBackStarted();
+ }
+
+ @Test
+ public void acceptsGesture_transitionTimeout() throws RemoteException {
+ mController.setBackToLauncherCallback(mIOnBackInvokedCallback);
+ RemoteAnimationTarget animationTarget = createAnimationTarget();
+ createNavigationInfo(animationTarget, null, null,
+ BackNavigationInfo.TYPE_RETURN_TO_HOME);
+
+ triggerBackGesture();
+ reset(mIOnBackInvokedCallback);
+
+ // Simulate transition timeout.
+ mShellExecutor.flushAll();
+ mController.onMotionEvent(
+ MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0),
+ MotionEvent.ACTION_DOWN,
+ BackEvent.EDGE_LEFT);
+ mController.onMotionEvent(
+ MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 100, 100, 0),
+ MotionEvent.ACTION_MOVE,
+ BackEvent.EDGE_LEFT);
+ verify(mIOnBackInvokedCallback).onBackStarted();
+ }
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java
index bde94d9..e6711ac 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java
@@ -129,8 +129,8 @@
mEntryA3 = createBubbleEntry(1, "a3", "package.a", null);
mEntryB1 = createBubbleEntry(1, "b1", "package.b", null);
mEntryB2 = createBubbleEntry(1, "b2", "package.b", null);
- mEntryB3 = createBubbleEntry(1, "b3", "package.b", null);
- mEntryC1 = createBubbleEntry(1, "c1", "package.c", null);
+ mEntryB3 = createBubbleEntry(11, "b3", "package.b", null);
+ mEntryC1 = createBubbleEntry(11, "c1", "package.c", null);
NotificationListenerService.Ranking ranking =
mock(NotificationListenerService.Ranking.class);
@@ -1058,6 +1058,37 @@
assertBubbleListContains(mBubbleA2, mBubbleA1, mBubbleLocusId);
}
+ @Test
+ public void test_removeBubblesForUser() {
+ // A is user 1
+ sendUpdatedEntryAtTime(mEntryA1, 2000);
+ sendUpdatedEntryAtTime(mEntryA2, 3000);
+ // B & C belong to user 11
+ sendUpdatedEntryAtTime(mEntryB3, 4000);
+ sendUpdatedEntryAtTime(mEntryC1, 5000);
+ mBubbleData.setListener(mListener);
+
+ mBubbleData.dismissBubbleWithKey(mEntryA1.getKey(), Bubbles.DISMISS_USER_GESTURE);
+ verifyUpdateReceived();
+ assertOverflowChangedTo(ImmutableList.of(mBubbleA1));
+ assertBubbleListContains(mBubbleC1, mBubbleB3, mBubbleA2);
+
+ // Remove all the A bubbles
+ mBubbleData.removeBubblesForUser(1);
+ verifyUpdateReceived();
+
+ // Verify the update has the removals.
+ BubbleData.Update update = mUpdateCaptor.getValue();
+ assertThat(update.removedBubbles.get(0)).isEqualTo(
+ Pair.create(mBubbleA2, Bubbles.DISMISS_USER_REMOVED));
+ assertThat(update.removedBubbles.get(1)).isEqualTo(
+ Pair.create(mBubbleA1, Bubbles.DISMISS_USER_REMOVED));
+
+ // Verify no A bubbles in active or overflow.
+ assertBubbleListContains(mBubbleC1, mBubbleB3);
+ assertOverflowChangedTo(ImmutableList.of());
+ }
+
private void verifyUpdateReceived() {
verify(mListener).applyUpdate(mUpdateCaptor.capture());
reset(mListener);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubblesNavBarMotionEventHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubblesNavBarMotionEventHandlerTest.java
new file mode 100644
index 0000000..44ff354
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubblesNavBarMotionEventHandlerTest.java
@@ -0,0 +1,142 @@
+/*
+ * 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.bubbles;
+
+import static android.view.MotionEvent.ACTION_CANCEL;
+import static android.view.MotionEvent.ACTION_DOWN;
+import static android.view.MotionEvent.ACTION_MOVE;
+import static android.view.MotionEvent.ACTION_UP;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.floatThat;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.verifyZeroInteractions;
+
+import android.os.SystemClock;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.view.MotionEvent;
+import android.view.WindowManager;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.wm.shell.ShellTestCase;
+import com.android.wm.shell.bubbles.BubblesNavBarMotionEventHandler.MotionEventListener;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Test {@link MotionEvent} handling in {@link BubblesNavBarMotionEventHandler}.
+ * Verifies that swipe events
+ */
+@SmallTest
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+@RunWith(AndroidTestingRunner.class)
+public class BubblesNavBarMotionEventHandlerTest extends ShellTestCase {
+
+ private BubblesNavBarMotionEventHandler mMotionEventHandler;
+ @Mock
+ private WindowManager mWindowManager;
+ @Mock
+ private Runnable mInterceptTouchRunnable;
+ @Mock
+ private MotionEventListener mMotionEventListener;
+ private long mMotionEventTime;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ TestableBubblePositioner positioner = new TestableBubblePositioner(getContext(),
+ mWindowManager);
+ mMotionEventHandler = new BubblesNavBarMotionEventHandler(getContext(), positioner,
+ mInterceptTouchRunnable, mMotionEventListener);
+ mMotionEventTime = SystemClock.uptimeMillis();
+ }
+
+ @Test
+ public void testMotionEvent_swipeUpInGestureZone_handled() {
+ mMotionEventHandler.onMotionEvent(newEvent(ACTION_DOWN, 0, 990));
+ mMotionEventHandler.onMotionEvent(newEvent(ACTION_MOVE, 0, 690));
+ mMotionEventHandler.onMotionEvent(newEvent(ACTION_MOVE, 0, 490));
+ mMotionEventHandler.onMotionEvent(newEvent(ACTION_MOVE, 0, 390));
+ mMotionEventHandler.onMotionEvent(newEvent(ACTION_UP, 0, 390));
+
+ verify(mMotionEventListener).onDown(0, 990);
+ verify(mMotionEventListener).onMove(0, -300);
+ verify(mMotionEventListener).onMove(0, -500);
+ verify(mMotionEventListener).onMove(0, -600);
+ // Check that velocity up is about 5000
+ verify(mMotionEventListener).onUp(eq(0f), floatThat(f -> Math.round(f) == -5000));
+ verifyZeroInteractions(mMotionEventListener);
+ verify(mInterceptTouchRunnable).run();
+ }
+
+ @Test
+ public void testMotionEvent_swipeUpOutsideGestureZone_ignored() {
+ mMotionEventHandler.onMotionEvent(newEvent(ACTION_DOWN, 0, 500));
+ mMotionEventHandler.onMotionEvent(newEvent(ACTION_MOVE, 0, 100));
+ mMotionEventHandler.onMotionEvent(newEvent(ACTION_UP, 0, 100));
+
+ verifyZeroInteractions(mMotionEventListener);
+ verifyZeroInteractions(mInterceptTouchRunnable);
+ }
+
+ @Test
+ public void testMotionEvent_horizontalMoveMoreThanTouchSlop_handled() {
+ mMotionEventHandler.onMotionEvent(newEvent(ACTION_DOWN, 0, 990));
+ mMotionEventHandler.onMotionEvent(newEvent(ACTION_MOVE, 100, 990));
+ mMotionEventHandler.onMotionEvent(newEvent(ACTION_UP, 100, 990));
+
+ verify(mMotionEventListener).onDown(0, 990);
+ verify(mMotionEventListener).onMove(100, 0);
+ verify(mMotionEventListener).onUp(0, 0);
+ verifyZeroInteractions(mMotionEventListener);
+ verify(mInterceptTouchRunnable).run();
+ }
+
+ @Test
+ public void testMotionEvent_moveLessThanTouchSlop_ignored() {
+ mMotionEventHandler.onMotionEvent(newEvent(ACTION_DOWN, 0, 990));
+ mMotionEventHandler.onMotionEvent(newEvent(ACTION_MOVE, 0, 989));
+ mMotionEventHandler.onMotionEvent(newEvent(ACTION_UP, 0, 989));
+
+ verify(mMotionEventListener).onDown(0, 990);
+ verifyNoMoreInteractions(mMotionEventListener);
+ verifyZeroInteractions(mInterceptTouchRunnable);
+ }
+
+ @Test
+ public void testMotionEvent_actionCancel_listenerNotified() {
+ mMotionEventHandler.onMotionEvent(newEvent(ACTION_DOWN, 0, 990));
+ mMotionEventHandler.onMotionEvent(newEvent(ACTION_CANCEL, 0, 990));
+ verify(mMotionEventListener).onDown(0, 990);
+ verify(mMotionEventListener).onCancel();
+ verifyNoMoreInteractions(mMotionEventListener);
+ verifyZeroInteractions(mInterceptTouchRunnable);
+ }
+
+ private MotionEvent newEvent(int actionDown, float x, float y) {
+ MotionEvent event = MotionEvent.obtain(0L, mMotionEventTime, actionDown, x, y, 0);
+ mMotionEventTime += 10;
+ return event;
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/ExpandedViewAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/ExpandedViewAnimationControllerTest.java
new file mode 100644
index 0000000..21887c0
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/ExpandedViewAnimationControllerTest.java
@@ -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.wm.shell.bubbles.animation;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assume.assumeTrue;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.view.ViewConfiguration;
+import android.view.WindowManager;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.wm.shell.ShellTestCase;
+import com.android.wm.shell.bubbles.BubbleExpandedView;
+import com.android.wm.shell.bubbles.TestableBubblePositioner;
+
+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)
+public class ExpandedViewAnimationControllerTest extends ShellTestCase {
+
+ private ExpandedViewAnimationController mController;
+
+ @Mock
+ private WindowManager mWindowManager;
+
+ @Mock
+ private BubbleExpandedView mMockExpandedView;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ TestableBubblePositioner positioner = new TestableBubblePositioner(getContext(),
+ mWindowManager);
+ mController = new ExpandedViewAnimationControllerImpl(getContext(), positioner);
+
+ mController.setExpandedView(mMockExpandedView);
+ when(mMockExpandedView.getContentHeight()).thenReturn(1000);
+ }
+
+ @Test
+ public void testUpdateDrag_expandedViewMovesUpAndClipped() {
+ // Drag by 50 pixels which corresponds to 10 pixels with overscroll
+ int dragDistance = 50;
+ int dampenedDistance = 10;
+
+ mController.updateDrag(dragDistance);
+
+ verify(mMockExpandedView).setTopClip(dampenedDistance);
+ verify(mMockExpandedView).setContentTranslationY(-dampenedDistance);
+ verify(mMockExpandedView).setManageButtonTranslationY(-dampenedDistance);
+ }
+
+ @Test
+ public void testUpdateDrag_zOrderUpdates() {
+ mController.updateDrag(10);
+ mController.updateDrag(20);
+
+ verify(mMockExpandedView, times(1)).setSurfaceZOrderedOnTop(true);
+ verify(mMockExpandedView, times(1)).setAnimating(true);
+ }
+
+ @Test
+ public void testUpdateDrag_moveBackToZero_zOrderRestored() {
+ mController.updateDrag(50);
+ reset(mMockExpandedView);
+ mController.updateDrag(0);
+ mController.updateDrag(0);
+
+ verify(mMockExpandedView, times(1)).setSurfaceZOrderedOnTop(false);
+ verify(mMockExpandedView, times(1)).setAnimating(false);
+ }
+
+ @Test
+ public void testUpdateDrag_hapticFeedbackOnlyOnce() {
+ // Drag by 10 which is below the collapse threshold - no feedback
+ mController.updateDrag(10);
+ verify(mMockExpandedView, times(0)).performHapticFeedback(anyInt());
+ // 150 takes it over the threshold - perform feedback
+ mController.updateDrag(150);
+ verify(mMockExpandedView, times(1)).performHapticFeedback(anyInt());
+ // Continue dragging, no more feedback
+ mController.updateDrag(200);
+ verify(mMockExpandedView, times(1)).performHapticFeedback(anyInt());
+ // Drag below threshold and over again - no more feedback
+ mController.updateDrag(10);
+ mController.updateDrag(150);
+ verify(mMockExpandedView, times(1)).performHapticFeedback(anyInt());
+ }
+
+ @Test
+ public void testShouldCollapse_doNotCollapseIfNotDragged() {
+ assertThat(mController.shouldCollapse()).isFalse();
+ }
+
+ @Test
+ public void testShouldCollapse_doNotCollapseIfVelocityDown() {
+ assumeTrue("Min fling velocity should be > 1 for this test", getMinFlingVelocity() > 1);
+ mController.setSwipeVelocity(getVelocityAboveMinFling());
+ assertThat(mController.shouldCollapse()).isFalse();
+ }
+
+ @Test
+ public void tesShouldCollapse_doNotCollapseIfVelocityUpIsSmall() {
+ assumeTrue("Min fling velocity should be > 1 for this test", getMinFlingVelocity() > 1);
+ mController.setSwipeVelocity(-getVelocityBelowMinFling());
+ assertThat(mController.shouldCollapse()).isFalse();
+ }
+
+ @Test
+ public void testShouldCollapse_collapseIfVelocityUpIsLarge() {
+ assumeTrue("Min fling velocity should be > 1 for this test", getMinFlingVelocity() > 1);
+ mController.setSwipeVelocity(-getVelocityAboveMinFling());
+ assertThat(mController.shouldCollapse()).isTrue();
+ }
+
+ @Test
+ public void testShouldCollapse_collapseIfPastThreshold() {
+ mController.updateDrag(500);
+ assertThat(mController.shouldCollapse()).isTrue();
+ }
+
+ @Test
+ public void testReset() {
+ mController.updateDrag(100);
+ reset(mMockExpandedView);
+ mController.reset();
+ verify(mMockExpandedView, atLeastOnce()).setAnimating(false);
+ verify(mMockExpandedView).setContentAlpha(1);
+ verify(mMockExpandedView).setAlpha(1);
+ verify(mMockExpandedView).setManageButtonAlpha(1);
+ verify(mMockExpandedView).setManageButtonAlpha(1);
+ verify(mMockExpandedView).setTopClip(0);
+ verify(mMockExpandedView).setContentTranslationY(-0f);
+ verify(mMockExpandedView).setManageButtonTranslationY(-0f);
+ verify(mMockExpandedView).setBottomClip(0);
+ verify(mMockExpandedView).movePointerBy(0, 0);
+ assertThat(mController.shouldCollapse()).isFalse();
+ }
+
+ private int getVelocityBelowMinFling() {
+ return getMinFlingVelocity() - 1;
+ }
+
+ private int getVelocityAboveMinFling() {
+ return getMinFlingVelocity() + 1;
+ }
+
+ private int getMinFlingVelocity() {
+ return ViewConfiguration.get(getContext()).getScaledMinimumFlingVelocity();
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubbleVolatileRepositoryTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubbleVolatileRepositoryTest.kt
index bfdf520..77c7055 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubbleVolatileRepositoryTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubbleVolatileRepositoryTest.kt
@@ -23,14 +23,19 @@
import androidx.test.filters.SmallTest
import org.junit.Test
import com.android.wm.shell.ShellTestCase
+import com.google.common.truth.Truth.assertThat
import junit.framework.Assert.assertEquals
import org.junit.Before
import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.any
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.ArgumentMatchers.anyString
import org.mockito.ArgumentMatchers.eq
import org.mockito.Mockito
import org.mockito.Mockito.mock
-import org.mockito.Mockito.verify
+import org.mockito.Mockito.never
import org.mockito.Mockito.reset
+import org.mockito.Mockito.verify
@SmallTest
@RunWith(AndroidTestingRunner::class)
@@ -41,17 +46,17 @@
private val user11 = UserHandle.of(11)
// user, package, shortcut, notification key, height, res-height, title, taskId, locusId
- private val bubble1 = BubbleEntity(0, "com.example.messenger", "shortcut-1",
- "0key-1", 120, 0, null, 1, null)
- private val bubble2 = BubbleEntity(10, "com.example.chat", "alice and bob",
- "10key-2", 0, 16537428, "title", 2, null)
- private val bubble3 = BubbleEntity(0, "com.example.messenger", "shortcut-2",
- "0key-3", 120, 0, null, INVALID_TASK_ID, null)
+ private val bubble1 = BubbleEntity(user0.identifier,
+ "com.example.messenger", "shortcut-1", "0key-1", 120, 0, null, 1, null)
+ private val bubble2 = BubbleEntity(user10_managed.identifier,
+ "com.example.chat", "alice and bob", "10key-2", 0, 16537428, "title", 2, null)
+ private val bubble3 = BubbleEntity(user0.identifier,
+ "com.example.messenger", "shortcut-2", "0key-3", 120, 0, null, INVALID_TASK_ID, null)
- private val bubble11 = BubbleEntity(11, "com.example.messenger",
- "shortcut-1", "01key-1", 120, 0, null, 3)
- private val bubble12 = BubbleEntity(11, "com.example.chat", "alice and bob",
- "11key-2", 0, 16537428, "title", INVALID_TASK_ID)
+ private val bubble11 = BubbleEntity(user11.identifier,
+ "com.example.messenger", "shortcut-1", "01key-1", 120, 0, null, 3)
+ private val bubble12 = BubbleEntity(user11.identifier,
+ "com.example.chat", "alice and bob", "11key-2", 0, 16537428, "title", INVALID_TASK_ID)
private val user0bubbles = listOf(bubble1, bubble2, bubble3)
private val user11bubbles = listOf(bubble11, bubble12)
@@ -151,6 +156,119 @@
repository.addBubbles(user0.identifier, listOf(bubbleModified))
assertEquals(bubbleModified, repository.getEntities(user0.identifier).get(0))
}
+
+ @Test
+ fun testRemoveBubblesForUser() {
+ repository.addBubbles(user0.identifier, user0bubbles)
+ assertThat(repository.getEntities(user0.identifier).toList())
+ .isEqualTo(listOf(bubble1, bubble2, bubble3))
+
+ val ret = repository.removeBubblesForUser(user0.identifier, -1)
+ assertThat(ret).isTrue() // bubbles were removed
+
+ assertThat(repository.getEntities(user0.identifier).toList()).isEmpty()
+ verify(launcherApps, never()).uncacheShortcuts(anyString(),
+ any(),
+ any(UserHandle::class.java), anyInt())
+ }
+
+ @Test
+ fun testRemoveBubblesForUser_parentUserRemoved() {
+ repository.addBubbles(user0.identifier, user0bubbles)
+ // bubble2 is the work profile bubble
+ assertThat(repository.getEntities(user0.identifier).toList())
+ .isEqualTo(listOf(bubble1, bubble2, bubble3))
+
+ val ret = repository.removeBubblesForUser(user10_managed.identifier, user0.identifier)
+ assertThat(ret).isTrue() // bubbles were removed
+
+ assertThat(repository.getEntities(user0.identifier).toList())
+ .isEqualTo(listOf(bubble1, bubble3))
+ verify(launcherApps, never()).uncacheShortcuts(anyString(),
+ any(),
+ any(UserHandle::class.java), anyInt())
+ }
+
+ @Test
+ fun testRemoveBubblesForUser_withoutBubbles() {
+ repository.addBubbles(user0.identifier, user0bubbles)
+ assertThat(repository.getEntities(user0.identifier).toList())
+ .isEqualTo(listOf(bubble1, bubble2, bubble3))
+
+ val ret = repository.removeBubblesForUser(user11.identifier, -1)
+ assertThat(ret).isFalse() // bubbles were NOT removed
+
+ assertThat(repository.getEntities(user0.identifier).toList())
+ .isEqualTo(listOf(bubble1, bubble2, bubble3))
+ verify(launcherApps, never()).uncacheShortcuts(anyString(),
+ any(),
+ any(UserHandle::class.java), anyInt())
+ }
+
+ @Test
+ fun testSanitizeBubbles_noChanges() {
+ repository.addBubbles(user0.identifier, user0bubbles)
+ assertThat(repository.getEntities(user0.identifier).toList())
+ .isEqualTo(listOf(bubble1, bubble2, bubble3))
+ repository.addBubbles(user11.identifier, user11bubbles)
+ assertThat(repository.getEntities(user11.identifier).toList())
+ .isEqualTo(listOf(bubble11, bubble12))
+
+ val ret = repository.sanitizeBubbles(listOf(user0.identifier,
+ user10_managed.identifier,
+ user11.identifier))
+ assertThat(ret).isFalse() // bubbles were NOT removed
+
+ verify(launcherApps, never()).uncacheShortcuts(anyString(),
+ any(),
+ any(UserHandle::class.java), anyInt())
+ }
+
+ @Test
+ fun testSanitizeBubbles_userRemoved() {
+ repository.addBubbles(user0.identifier, user0bubbles)
+ assertThat(repository.getEntities(user0.identifier).toList())
+ .isEqualTo(listOf(bubble1, bubble2, bubble3))
+ repository.addBubbles(user11.identifier, user11bubbles)
+ assertThat(repository.getEntities(user11.identifier).toList())
+ .isEqualTo(listOf(bubble11, bubble12))
+
+ val ret = repository.sanitizeBubbles(listOf(user11.identifier))
+ assertThat(ret).isTrue() // bubbles were removed
+
+ assertThat(repository.getEntities(user0.identifier).toList()).isEmpty()
+ verify(launcherApps, never()).uncacheShortcuts(anyString(),
+ any(),
+ any(UserHandle::class.java), anyInt())
+
+ // User 11 bubbles should still be here
+ assertThat(repository.getEntities(user11.identifier).toList())
+ .isEqualTo(listOf(bubble11, bubble12))
+ }
+
+ @Test
+ fun testSanitizeBubbles_userParentRemoved() {
+ repository.addBubbles(user0.identifier, user0bubbles)
+ assertThat(repository.getEntities(user0.identifier).toList())
+ .isEqualTo(listOf(bubble1, bubble2, bubble3))
+
+ repository.addBubbles(user11.identifier, user11bubbles)
+ assertThat(repository.getEntities(user11.identifier).toList())
+ .isEqualTo(listOf(bubble11, bubble12))
+
+ val ret = repository.sanitizeBubbles(listOf(user0.identifier, user11.identifier))
+ assertThat(ret).isTrue() // bubbles were removed
+ // bubble2 is the work profile bubble and should be removed
+ assertThat(repository.getEntities(user0.identifier).toList())
+ .isEqualTo(listOf(bubble1, bubble3))
+ verify(launcherApps, never()).uncacheShortcuts(anyString(),
+ any(),
+ any(UserHandle::class.java), anyInt())
+
+ // User 11 bubbles should still be here
+ assertThat(repository.getEntities(user11.identifier).toList())
+ .isEqualTo(listOf(bubble11, bubble12))
+ }
}
private const val PKG_MESSENGER = "com.example.messenger"
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/TaskStackListenerImplTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/TaskStackListenerImplTest.java
index d8aebc2..96938eb 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/TaskStackListenerImplTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/TaskStackListenerImplTest.java
@@ -109,9 +109,10 @@
@Test
public void testOnTaskProfileLocked() {
- mImpl.onTaskProfileLocked(1, 2);
- verify(mCallback).onTaskProfileLocked(eq(1), eq(2));
- verify(mOtherCallback).onTaskProfileLocked(eq(1), eq(2));
+ ActivityManager.RunningTaskInfo info = mock(ActivityManager.RunningTaskInfo.class);
+ mImpl.onTaskProfileLocked(info);
+ verify(mCallback).onTaskProfileLocked(eq(info));
+ verify(mOtherCallback).onTaskProfileLocked(eq(info));
}
@Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java
index ecf1c5d..6a6db8a 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java
@@ -345,8 +345,8 @@
when(mMockSettingsUitl.getSettingsSwipeToNotificationEnabled(any(), anyInt())).thenReturn(
false);
final WindowContainerTransaction handlerWCT = new WindowContainerTransaction();
- mSpiedOneHandedController.onRotateDisplay(mDisplay.getDisplayId(), Surface.ROTATION_0,
- Surface.ROTATION_90, handlerWCT);
+ mSpiedOneHandedController.onDisplayChange(mDisplay.getDisplayId(), Surface.ROTATION_0,
+ Surface.ROTATION_90, null /* newDisplayAreaInfo */, handlerWCT);
verify(mMockDisplayAreaOrganizer, atLeastOnce()).onRotateDisplay(eq(mContext),
eq(Surface.ROTATION_90), any(WindowContainerTransaction.class));
@@ -358,8 +358,8 @@
when(mMockSettingsUitl.getSettingsSwipeToNotificationEnabled(any(), anyInt())).thenReturn(
false);
final WindowContainerTransaction handlerWCT = new WindowContainerTransaction();
- mSpiedOneHandedController.onRotateDisplay(mDisplay.getDisplayId(), Surface.ROTATION_0,
- Surface.ROTATION_90, handlerWCT);
+ mSpiedOneHandedController.onDisplayChange(mDisplay.getDisplayId(), Surface.ROTATION_0,
+ Surface.ROTATION_90, null /* newDisplayAreaInfo */, handlerWCT);
verify(mMockDisplayAreaOrganizer, never()).onRotateDisplay(eq(mContext),
eq(Surface.ROTATION_90), any(WindowContainerTransaction.class));
@@ -371,8 +371,8 @@
when(mMockSettingsUitl.getSettingsSwipeToNotificationEnabled(any(), anyInt())).thenReturn(
true);
final WindowContainerTransaction handlerWCT = new WindowContainerTransaction();
- mSpiedOneHandedController.onRotateDisplay(mDisplay.getDisplayId(), Surface.ROTATION_0,
- Surface.ROTATION_90, handlerWCT);
+ mSpiedOneHandedController.onDisplayChange(mDisplay.getDisplayId(), Surface.ROTATION_0,
+ Surface.ROTATION_90, null /* newDisplayAreaInfo */, handlerWCT);
verify(mMockDisplayAreaOrganizer, never()).onRotateDisplay(eq(mContext),
eq(Surface.ROTATION_90), any(WindowContainerTransaction.class));
@@ -384,8 +384,8 @@
when(mMockSettingsUitl.getSettingsSwipeToNotificationEnabled(any(), anyInt())).thenReturn(
false);
final WindowContainerTransaction handlerWCT = new WindowContainerTransaction();
- mSpiedOneHandedController.onRotateDisplay(mDisplay.getDisplayId(), Surface.ROTATION_0,
- Surface.ROTATION_90, handlerWCT);
+ mSpiedOneHandedController.onDisplayChange(mDisplay.getDisplayId(), Surface.ROTATION_0,
+ Surface.ROTATION_90, null /* newDisplayAreaInfo */, handlerWCT);
verify(mMockDisplayAreaOrganizer, atLeastOnce()).onRotateDisplay(eq(mContext),
eq(Surface.ROTATION_90), any(WindowContainerTransaction.class));
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/tv/TvPipBoundsControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/tv/TvPipBoundsControllerTest.kt
new file mode 100644
index 0000000..05e4722
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/tv/TvPipBoundsControllerTest.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.wm.shell.pip.tv
+
+import android.content.Context
+import android.content.res.Resources
+import android.graphics.Rect
+import android.os.Handler
+import android.os.test.TestLooper
+import android.testing.AndroidTestingRunner
+
+import com.android.wm.shell.R
+import com.android.wm.shell.pip.PipBoundsState.STASH_TYPE_RIGHT
+import com.android.wm.shell.pip.tv.TvPipBoundsController.POSITION_DEBOUNCE_TIMEOUT_MILLIS
+import com.android.wm.shell.pip.tv.TvPipKeepClearAlgorithm.Placement
+
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.AdditionalAnswers.returnsFirstArg
+import org.mockito.Mock
+import org.mockito.Mockito.`when` as whenever
+import org.mockito.Mockito.any
+import org.mockito.Mockito.anyInt
+import org.mockito.Mockito.eq
+import org.mockito.Mockito.never
+import org.mockito.Mockito.reset
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@RunWith(AndroidTestingRunner::class)
+class TvPipBoundsControllerTest {
+ val ANIMATION_DURATION = 100
+ val STASH_DURATION = 5000
+ val FAR_FUTURE = 60 * 60000L
+ val ANCHOR_BOUNDS = Rect(90, 90, 100, 100)
+ val STASHED_BOUNDS = Rect(99, 90, 109, 100)
+ val MOVED_BOUNDS = Rect(90, 80, 100, 90)
+ val STASHED_MOVED_BOUNDS = Rect(99, 80, 109, 90)
+ val ANCHOR_PLACEMENT = Placement(ANCHOR_BOUNDS, ANCHOR_BOUNDS)
+ val STASHED_PLACEMENT = Placement(STASHED_BOUNDS, ANCHOR_BOUNDS,
+ STASH_TYPE_RIGHT, ANCHOR_BOUNDS, false)
+ val STASHED_PLACEMENT_RESTASH = Placement(STASHED_BOUNDS, ANCHOR_BOUNDS,
+ STASH_TYPE_RIGHT, ANCHOR_BOUNDS, true)
+ val MOVED_PLACEMENT = Placement(MOVED_BOUNDS, ANCHOR_BOUNDS)
+ val STASHED_MOVED_PLACEMENT = Placement(STASHED_MOVED_BOUNDS, ANCHOR_BOUNDS,
+ STASH_TYPE_RIGHT, MOVED_BOUNDS, false)
+ val STASHED_MOVED_PLACEMENT_RESTASH = Placement(STASHED_MOVED_BOUNDS, ANCHOR_BOUNDS,
+ STASH_TYPE_RIGHT, MOVED_BOUNDS, true)
+
+ lateinit var boundsController: TvPipBoundsController
+ var time = 0L
+ lateinit var testLooper: TestLooper
+ lateinit var mainHandler: Handler
+
+ var inMenu = false
+ var inMoveMode = false
+
+ @Mock
+ lateinit var context: Context
+ @Mock
+ lateinit var resources: Resources
+ @Mock
+ lateinit var tvPipBoundsState: TvPipBoundsState
+ @Mock
+ lateinit var tvPipBoundsAlgorithm: TvPipBoundsAlgorithm
+ @Mock
+ lateinit var listener: TvPipBoundsController.PipBoundsListener
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ time = 0L
+ inMenu = false
+ inMoveMode = false
+
+ testLooper = TestLooper { time }
+ mainHandler = Handler(testLooper.getLooper())
+
+ whenever(context.resources).thenReturn(resources)
+ whenever(resources.getInteger(R.integer.config_pipStashDuration)).thenReturn(STASH_DURATION)
+ whenever(tvPipBoundsAlgorithm.adjustBoundsForTemporaryDecor(any()))
+ .then(returnsFirstArg<Rect>())
+
+ boundsController = TvPipBoundsController(
+ context,
+ { time },
+ mainHandler,
+ tvPipBoundsState,
+ tvPipBoundsAlgorithm)
+ boundsController.setListener(listener)
+ }
+
+ @Test
+ fun testPlacement_MovedAfterDebounceTimeout() {
+ triggerPlacement(MOVED_PLACEMENT)
+ assertMovementAt(POSITION_DEBOUNCE_TIMEOUT_MILLIS, MOVED_BOUNDS)
+ assertNoMovementUpTo(time + FAR_FUTURE)
+ }
+
+ @Test
+ fun testStashedPlacement_MovedAfterDebounceTimeout_Unstashes() {
+ triggerPlacement(STASHED_PLACEMENT_RESTASH)
+ assertMovementAt(POSITION_DEBOUNCE_TIMEOUT_MILLIS, STASHED_BOUNDS)
+ assertMovementAt(POSITION_DEBOUNCE_TIMEOUT_MILLIS + STASH_DURATION, ANCHOR_BOUNDS)
+ }
+
+ @Test
+ fun testDebounceSamePlacement_MovesDebounceTimeoutAfterFirstPlacement() {
+ triggerPlacement(MOVED_PLACEMENT)
+ advanceTimeTo(POSITION_DEBOUNCE_TIMEOUT_MILLIS / 2)
+ triggerPlacement(MOVED_PLACEMENT)
+
+ assertMovementAt(POSITION_DEBOUNCE_TIMEOUT_MILLIS, MOVED_BOUNDS)
+ }
+
+ @Test
+ fun testNoMovementUntilPlacementStabilizes() {
+ triggerPlacement(ANCHOR_PLACEMENT)
+ advanceTimeTo(time + POSITION_DEBOUNCE_TIMEOUT_MILLIS / 10)
+ triggerPlacement(MOVED_PLACEMENT)
+ advanceTimeTo(time + POSITION_DEBOUNCE_TIMEOUT_MILLIS / 10)
+ triggerPlacement(ANCHOR_PLACEMENT)
+ advanceTimeTo(time + POSITION_DEBOUNCE_TIMEOUT_MILLIS / 10)
+ triggerPlacement(MOVED_PLACEMENT)
+
+ assertMovementAt(time + POSITION_DEBOUNCE_TIMEOUT_MILLIS, MOVED_BOUNDS)
+ }
+
+ @Test
+ fun testUnstashIfStashNoLongerNecessary() {
+ triggerPlacement(STASHED_PLACEMENT_RESTASH)
+ assertMovementAt(POSITION_DEBOUNCE_TIMEOUT_MILLIS, STASHED_BOUNDS)
+
+ triggerPlacement(ANCHOR_PLACEMENT)
+ assertMovementAt(time + POSITION_DEBOUNCE_TIMEOUT_MILLIS, ANCHOR_BOUNDS)
+ }
+
+ @Test
+ fun testRestashingPlacementDelaysUnstash() {
+ triggerPlacement(STASHED_PLACEMENT_RESTASH)
+ assertMovementAt(POSITION_DEBOUNCE_TIMEOUT_MILLIS, STASHED_BOUNDS)
+
+ assertNoMovementUpTo(time + STASH_DURATION / 2)
+ triggerPlacement(STASHED_PLACEMENT_RESTASH)
+ assertNoMovementUpTo(time + POSITION_DEBOUNCE_TIMEOUT_MILLIS)
+ assertMovementAt(time + STASH_DURATION, ANCHOR_BOUNDS)
+ }
+
+ @Test
+ fun testNonRestashingPlacementDoesNotDelayUnstash() {
+ triggerPlacement(STASHED_PLACEMENT_RESTASH)
+ assertMovementAt(POSITION_DEBOUNCE_TIMEOUT_MILLIS, STASHED_BOUNDS)
+
+ assertNoMovementUpTo(time + STASH_DURATION / 2)
+ triggerPlacement(STASHED_PLACEMENT)
+ assertMovementAt(POSITION_DEBOUNCE_TIMEOUT_MILLIS + STASH_DURATION, ANCHOR_BOUNDS)
+ }
+
+ @Test
+ fun testImmediatePlacement() {
+ triggerImmediatePlacement(STASHED_PLACEMENT_RESTASH)
+ assertMovement(STASHED_BOUNDS)
+ assertMovementAt(time + STASH_DURATION, ANCHOR_BOUNDS)
+ }
+
+ @Test
+ fun testInMoveMode_KeepAtAnchor() {
+ startMoveMode()
+ triggerImmediatePlacement(STASHED_MOVED_PLACEMENT_RESTASH)
+ assertMovement(ANCHOR_BOUNDS)
+ assertNoMovementUpTo(time + FAR_FUTURE)
+ }
+
+ @Test
+ fun testInMenu_Unstashed() {
+ openPipMenu()
+ triggerImmediatePlacement(STASHED_MOVED_PLACEMENT_RESTASH)
+ assertMovement(MOVED_BOUNDS)
+ assertNoMovementUpTo(time + FAR_FUTURE)
+ }
+
+ @Test
+ fun testCloseMenu_DoNotRestash() {
+ openPipMenu()
+ triggerImmediatePlacement(STASHED_MOVED_PLACEMENT_RESTASH)
+ assertMovement(MOVED_BOUNDS)
+
+ closePipMenu()
+ triggerPlacement(STASHED_MOVED_PLACEMENT)
+ assertNoMovementUpTo(time + FAR_FUTURE)
+ }
+
+ fun assertMovement(bounds: Rect) {
+ verify(listener).onPipTargetBoundsChange(eq(bounds), anyInt())
+ reset(listener)
+ }
+
+ fun assertMovementAt(timeMs: Long, bounds: Rect) {
+ assertNoMovementUpTo(timeMs - 1)
+ advanceTimeTo(timeMs)
+ assertMovement(bounds)
+ }
+
+ fun assertNoMovementUpTo(timeMs: Long) {
+ advanceTimeTo(timeMs)
+ verify(listener, never()).onPipTargetBoundsChange(any(), anyInt())
+ }
+
+ fun triggerPlacement(placement: Placement, immediate: Boolean = false) {
+ whenever(tvPipBoundsAlgorithm.getTvPipPlacement()).thenReturn(placement)
+ val stayAtAnchorPosition = inMoveMode
+ val disallowStashing = inMenu || stayAtAnchorPosition
+ boundsController.recalculatePipBounds(stayAtAnchorPosition, disallowStashing,
+ ANIMATION_DURATION, immediate)
+ }
+
+ fun triggerImmediatePlacement(placement: Placement) {
+ triggerPlacement(placement, true)
+ }
+
+ fun openPipMenu() {
+ inMenu = true
+ inMoveMode = false
+ }
+
+ fun closePipMenu() {
+ inMenu = false
+ inMoveMode = false
+ }
+
+ fun startMoveMode() {
+ inMenu = true
+ inMoveMode = true
+ }
+
+ fun advanceTimeTo(ms: Long) {
+ time = ms
+ testLooper.dispatchAll()
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/tv/TvPipKeepClearAlgorithmTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/tv/TvPipKeepClearAlgorithmTest.kt
index 46f388d..0fcc5cf 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/tv/TvPipKeepClearAlgorithmTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/tv/TvPipKeepClearAlgorithmTest.kt
@@ -30,7 +30,9 @@
import org.junit.Before
import org.junit.Test
import junit.framework.Assert.assertEquals
+import junit.framework.Assert.assertFalse
import junit.framework.Assert.assertNull
+import junit.framework.Assert.assertTrue
@RunWith(AndroidTestingRunner::class)
class TvPipKeepClearAlgorithmTest {
@@ -46,7 +48,6 @@
private lateinit var pipSize: Size
private lateinit var movementBounds: Rect
private lateinit var algorithm: TvPipKeepClearAlgorithm
- private var currentTime = 0L
private var restrictedAreas = mutableSetOf<Rect>()
private var unrestrictedAreas = mutableSetOf<Rect>()
private var gravity: Int = 0
@@ -58,16 +59,14 @@
restrictedAreas.clear()
unrestrictedAreas.clear()
- currentTime = 0L
pipSize = DEFAULT_PIP_SIZE
gravity = Gravity.BOTTOM or Gravity.RIGHT
- algorithm = TvPipKeepClearAlgorithm({ currentTime })
+ algorithm = TvPipKeepClearAlgorithm()
algorithm.setScreenSize(SCREEN_SIZE)
algorithm.setMovementBounds(movementBounds)
algorithm.pipAreaPadding = PADDING
algorithm.stashOffset = STASH_OFFSET
- algorithm.stashDuration = 5000L
algorithm.setGravity(gravity)
algorithm.maxRestrictedDistanceFraction = 0.3
}
@@ -265,7 +264,7 @@
assertEquals(expectedBounds, placement.bounds)
assertEquals(STASH_TYPE_BOTTOM, placement.stashType)
assertEquals(getExpectedAnchorBounds(), placement.unstashDestinationBounds)
- assertEquals(algorithm.stashDuration, placement.unstashTime)
+ assertTrue(placement.triggerStash)
}
@Test
@@ -305,7 +304,7 @@
assertEquals(expectedBounds, placement.bounds)
assertEquals(STASH_TYPE_RIGHT, placement.stashType)
assertEquals(expectedUnstashBounds, placement.unstashDestinationBounds)
- assertEquals(algorithm.stashDuration, placement.unstashTime)
+ assertTrue(placement.triggerStash)
}
@Test
@@ -352,9 +351,7 @@
assertEquals(expectedBounds, placement.bounds)
assertEquals(STASH_TYPE_RIGHT, placement.stashType)
assertEquals(expectedUnstashBounds, placement.unstashDestinationBounds)
- assertEquals(algorithm.stashDuration, placement.unstashTime)
-
- currentTime += 1000
+ assertTrue(placement.triggerStash)
restrictedAreas.remove(sideBar)
placement = getActualPlacement()
@@ -363,7 +360,7 @@
}
@Test
- fun test_Stashed_UnstashBoundsStaysObstructed_UnstashesAfterTimeout() {
+ fun test_Stashed_UnstashBoundsStaysObstructed_DoesNotTriggerStash() {
gravity = Gravity.BOTTOM or Gravity.RIGHT
val bottomBar = makeBottomBar(BOTTOM_SHEET_HEIGHT)
@@ -384,13 +381,13 @@
assertEquals(expectedBounds, placement.bounds)
assertEquals(STASH_TYPE_RIGHT, placement.stashType)
assertEquals(expectedUnstashBounds, placement.unstashDestinationBounds)
- assertEquals(algorithm.stashDuration, placement.unstashTime)
-
- currentTime += algorithm.stashDuration
+ assertTrue(placement.triggerStash)
placement = getActualPlacement()
- assertEquals(expectedUnstashBounds, placement.bounds)
- assertNotStashed(placement)
+ assertEquals(expectedBounds, placement.bounds)
+ assertEquals(STASH_TYPE_RIGHT, placement.stashType)
+ assertEquals(expectedUnstashBounds, placement.unstashDestinationBounds)
+ assertFalse(placement.triggerStash)
}
@Test
@@ -415,9 +412,7 @@
assertEquals(expectedBounds, placement.bounds)
assertEquals(STASH_TYPE_RIGHT, placement.stashType)
assertEquals(expectedUnstashBounds, placement.unstashDestinationBounds)
- assertEquals(algorithm.stashDuration, placement.unstashTime)
-
- currentTime += 1000
+ assertTrue(placement.triggerStash)
val newObstruction = Rect(
0,
@@ -431,7 +426,7 @@
assertEquals(expectedBounds, placement.bounds)
assertEquals(STASH_TYPE_RIGHT, placement.stashType)
assertEquals(expectedUnstashBounds, placement.unstashDestinationBounds)
- assertEquals(currentTime + algorithm.stashDuration, placement.unstashTime)
+ assertTrue(placement.triggerStash)
}
@Test
@@ -458,21 +453,9 @@
@Test
fun test_PipInsets() {
- val permInsets = Insets.of(-1, -2, -3, -4)
- algorithm.setPipPermanentDecorInsets(permInsets)
- testInsetsForAllPositions(permInsets)
+ val insets = Insets.of(-1, -2, -3, -4)
+ algorithm.setPipPermanentDecorInsets(insets)
- val tempInsets = Insets.of(-4, -3, -2, -1)
- algorithm.setPipPermanentDecorInsets(Insets.NONE)
- algorithm.setPipTemporaryDecorInsets(tempInsets)
- testInsetsForAllPositions(tempInsets)
-
- algorithm.setPipPermanentDecorInsets(permInsets)
- algorithm.setPipTemporaryDecorInsets(tempInsets)
- testInsetsForAllPositions(Insets.add(permInsets, tempInsets))
- }
-
- private fun testInsetsForAllPositions(insets: Insets) {
gravity = Gravity.BOTTOM or Gravity.RIGHT
testAnchorPositionWithInsets(insets)
@@ -546,6 +529,6 @@
private fun assertNotStashed(actual: Placement) {
assertEquals(STASH_TYPE_NONE, actual.stashType)
assertNull(actual.unstashDestinationBounds)
- assertEquals(0L, actual.unstashTime)
+ assertFalse(actual.triggerStash)
}
}
diff --git a/libs/hwui/AnimatorManager.cpp b/libs/hwui/AnimatorManager.cpp
index 4826d5a..0780414 100644
--- a/libs/hwui/AnimatorManager.cpp
+++ b/libs/hwui/AnimatorManager.cpp
@@ -31,7 +31,8 @@
animator->detach();
}
-AnimatorManager::AnimatorManager(RenderNode& parent) : mParent(parent), mAnimationHandle(nullptr) {}
+AnimatorManager::AnimatorManager(RenderNode& parent)
+ : mParent(parent), mAnimationHandle(nullptr), mCancelAllAnimators(false) {}
AnimatorManager::~AnimatorManager() {
for_each(mNewAnimators.begin(), mNewAnimators.end(), detach);
@@ -82,8 +83,16 @@
}
mNewAnimators.clear();
}
- for (auto& animator : mAnimators) {
- animator->pushStaging(mAnimationHandle->context());
+
+ if (mCancelAllAnimators) {
+ for (auto& animator : mAnimators) {
+ animator->forceEndNow(mAnimationHandle->context());
+ }
+ mCancelAllAnimators = false;
+ } else {
+ for (auto& animator : mAnimators) {
+ animator->pushStaging(mAnimationHandle->context());
+ }
}
}
@@ -184,5 +193,9 @@
mAnimationHandle->release();
}
+void AnimatorManager::forceEndAnimators() {
+ mCancelAllAnimators = true;
+}
+
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/AnimatorManager.h b/libs/hwui/AnimatorManager.h
index a0df01d..6002661d 100644
--- a/libs/hwui/AnimatorManager.h
+++ b/libs/hwui/AnimatorManager.h
@@ -16,11 +16,11 @@
#ifndef ANIMATORMANAGER_H
#define ANIMATORMANAGER_H
-#include <vector>
-
#include <cutils/compiler.h>
#include <utils/StrongPointer.h>
+#include <vector>
+
#include "utils/Macros.h"
namespace android {
@@ -56,6 +56,8 @@
// Hard-ends all animators. May only be called on the UI thread.
void endAllStagingAnimators();
+ void forceEndAnimators();
+
// Hard-ends all animators that have been pushed. Used for cleanup if
// the ActivityContext is being destroyed
void endAllActiveAnimators();
@@ -71,6 +73,8 @@
// To improve the efficiency of resizing & removing from the vector
std::vector<sp<BaseRenderNodeAnimator> > mNewAnimators;
std::vector<sp<BaseRenderNodeAnimator> > mAnimators;
+
+ bool mCancelAllAnimators;
};
} /* namespace uirenderer */
diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp
index 86ae399..5a67eb9 100644
--- a/libs/hwui/Properties.cpp
+++ b/libs/hwui/Properties.cpp
@@ -134,7 +134,7 @@
skpCaptureEnabled = debuggingEnabled && base::GetBoolProperty(PROPERTY_CAPTURE_SKP_ENABLED, false);
SkAndroidFrameworkTraceUtil::setEnableTracing(
- base::GetBoolProperty(PROPERTY_SKIA_ATRACE_ENABLED, true));
+ base::GetBoolProperty(PROPERTY_SKIA_ATRACE_ENABLED, false));
runningInEmulator = base::GetBoolProperty(PROPERTY_IS_EMULATOR, false);
diff --git a/libs/hwui/jni/android_graphics_RenderNode.cpp b/libs/hwui/jni/android_graphics_RenderNode.cpp
index 944393c..db76390 100644
--- a/libs/hwui/jni/android_graphics_RenderNode.cpp
+++ b/libs/hwui/jni/android_graphics_RenderNode.cpp
@@ -543,6 +543,12 @@
renderNode->animators().endAllStagingAnimators();
}
+static void android_view_RenderNode_forceEndAnimators(JNIEnv* env, jobject clazz,
+ jlong renderNodePtr) {
+ RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+ renderNode->animators().forceEndAnimators();
+}
+
// ----------------------------------------------------------------------------
// SurfaceView position callback
// ----------------------------------------------------------------------------
@@ -745,6 +751,7 @@
{"nGetAllocatedSize", "(J)I", (void*)android_view_RenderNode_getAllocatedSize},
{"nAddAnimator", "(JJ)V", (void*)android_view_RenderNode_addAnimator},
{"nEndAllAnimators", "(J)V", (void*)android_view_RenderNode_endAllAnimators},
+ {"nForceEndAnimators", "(J)V", (void*)android_view_RenderNode_forceEndAnimators},
{"nRequestPositionUpdates", "(JLjava/lang/ref/WeakReference;)V",
(void*)android_view_RenderNode_requestPositionUpdates},
diff --git a/libs/input/TEST_MAPPING b/libs/input/TEST_MAPPING
index fe74c62..9626d8d 100644
--- a/libs/input/TEST_MAPPING
+++ b/libs/input/TEST_MAPPING
@@ -1,7 +1,7 @@
{
- "presubmit": [
- {
- "name": "libinputservice_test"
- }
- ]
+ "imports": [
+ {
+ "path": "frameworks/native/services/inputflinger"
+ }
+ ]
}
diff --git a/location/java/android/location/Location.java b/location/java/android/location/Location.java
index 033056c..55ee3aa 100644
--- a/location/java/android/location/Location.java
+++ b/location/java/android/location/Location.java
@@ -95,6 +95,8 @@
private static final int HAS_SPEED_ACCURACY_MASK = 1 << 6;
private static final int HAS_BEARING_ACCURACY_MASK = 1 << 7;
private static final int HAS_ELAPSED_REALTIME_UNCERTAINTY_MASK = 1 << 8;
+ private static final int HAS_MSL_ALTITUDE_MASK = 1 << 9;
+ private static final int HAS_MSL_ALTITUDE_ACCURACY_MASK = 1 << 10;
// Cached data to make bearing/distance computations more efficient for the case
// where distanceTo and bearingTo are called in sequence. Assume this typically happens
@@ -118,6 +120,8 @@
private float mSpeedAccuracyMetersPerSecond;
private float mBearingDegrees;
private float mBearingAccuracyDegrees;
+ private double mMslAltitudeMeters;
+ private float mMslAltitudeAccuracyMeters;
private Bundle mExtras = null;
@@ -156,6 +160,8 @@
mSpeedAccuracyMetersPerSecond = location.mSpeedAccuracyMetersPerSecond;
mBearingDegrees = location.mBearingDegrees;
mBearingAccuracyDegrees = location.mBearingAccuracyDegrees;
+ mMslAltitudeMeters = location.mMslAltitudeMeters;
+ mMslAltitudeAccuracyMeters = location.mMslAltitudeAccuracyMeters;
mExtras = (location.mExtras == null) ? null : new Bundle(location.mExtras);
}
@@ -178,6 +184,8 @@
mAltitudeAccuracyMeters = 0;
mSpeedAccuracyMetersPerSecond = 0;
mBearingAccuracyDegrees = 0;
+ mMslAltitudeMeters = 0;
+ mMslAltitudeAccuracyMeters = 0;
mExtras = null;
}
@@ -690,6 +698,75 @@
}
/**
+ * Returns the Mean Sea Level altitude of this location in meters.
+ *
+ * <p>This is only valid if {@link #hasMslAltitude()} is true.
+ */
+ public @FloatRange double getMslAltitudeMeters() {
+ Preconditions.checkState(hasMslAltitude(),
+ "The Mean Sea Level altitude of this location is not set.");
+ return mMslAltitudeMeters;
+ }
+
+ /**
+ * Sets the Mean Sea Level altitude of this location in meters.
+ */
+ public void setMslAltitudeMeters(@FloatRange double mslAltitudeMeters) {
+ mMslAltitudeMeters = mslAltitudeMeters;
+ mFieldsMask |= HAS_MSL_ALTITUDE_MASK;
+ }
+
+ /**
+ * Returns true if this location has a Mean Sea Level altitude, false otherwise.
+ */
+ public boolean hasMslAltitude() {
+ return (mFieldsMask & HAS_MSL_ALTITUDE_MASK) != 0;
+ }
+
+ /**
+ * Removes the Mean Sea Level altitude from this location.
+ */
+ public void removeMslAltitude() {
+ mFieldsMask &= ~HAS_MSL_ALTITUDE_MASK;
+ }
+
+ /**
+ * Returns the estimated Mean Sea Level altitude accuracy in meters of this location at the 68th
+ * percentile confidence level. This means that there is 68% chance that the true Mean Sea Level
+ * altitude of this location falls within {@link #getMslAltitudeMeters()} +/- this uncertainty.
+ *
+ * <p>This is only valid if {@link #hasMslAltitudeAccuracy()} is true.
+ */
+ public @FloatRange(from = 0.0) float getMslAltitudeAccuracyMeters() {
+ Preconditions.checkState(hasMslAltitudeAccuracy(),
+ "The Mean Sea Level altitude accuracy of this location is not set.");
+ return mMslAltitudeAccuracyMeters;
+ }
+
+ /**
+ * Sets the Mean Sea Level altitude accuracy of this location in meters.
+ */
+ public void setMslAltitudeAccuracyMeters(
+ @FloatRange(from = 0.0) float mslAltitudeAccuracyMeters) {
+ mMslAltitudeAccuracyMeters = mslAltitudeAccuracyMeters;
+ mFieldsMask |= HAS_MSL_ALTITUDE_ACCURACY_MASK;
+ }
+
+ /**
+ * Returns true if this location has a Mean Sea Level altitude accuracy, false otherwise.
+ */
+ public boolean hasMslAltitudeAccuracy() {
+ return (mFieldsMask & HAS_MSL_ALTITUDE_ACCURACY_MASK) != 0;
+ }
+
+ /**
+ * Removes the Mean Sea Level altitude accuracy from this location.
+ */
+ public void removeMslAltitudeAccuracy() {
+ mFieldsMask &= ~HAS_MSL_ALTITUDE_ACCURACY_MASK;
+ }
+
+ /**
* Returns true if this is a mock location. If this location comes from the Android framework,
* this indicates that the location was provided by a test location provider, and thus may not
* be related to the actual location of the device.
@@ -839,6 +916,14 @@
&& hasBearingAccuracy() == location.hasBearingAccuracy()
&& (!hasBearingAccuracy() || Float.compare(location.mBearingAccuracyDegrees,
mBearingAccuracyDegrees) == 0)
+ && hasMslAltitude() == location.hasMslAltitude()
+ && (!hasMslAltitude() || Double.compare(location.mMslAltitudeMeters,
+ mMslAltitudeMeters)
+ == 0)
+ && hasMslAltitudeAccuracy() == location.hasMslAltitudeAccuracy()
+ && (!hasMslAltitudeAccuracy() || Float.compare(
+ location.mMslAltitudeAccuracyMeters,
+ mMslAltitudeAccuracyMeters) == 0)
&& Objects.equals(mProvider, location.mProvider)
&& areExtrasEqual(mExtras, location.mExtras);
}
@@ -876,6 +961,12 @@
s.append(" vAcc=").append(mAltitudeAccuracyMeters);
}
}
+ if (hasMslAltitude()) {
+ s.append(" mslAlt=").append(mMslAltitudeMeters);
+ if (hasMslAltitudeAccuracy()) {
+ s.append(" mslAltAcc=").append(mMslAltitudeAccuracyMeters);
+ }
+ }
if (hasSpeed()) {
s.append(" vel=").append(mSpeedMetersPerSecond);
if (hasSpeedAccuracy()) {
@@ -944,6 +1035,12 @@
if (l.hasBearingAccuracy()) {
l.mBearingAccuracyDegrees = in.readFloat();
}
+ if (l.hasMslAltitude()) {
+ l.mMslAltitudeMeters = in.readDouble();
+ }
+ if (l.hasMslAltitudeAccuracy()) {
+ l.mMslAltitudeAccuracyMeters = in.readFloat();
+ }
l.mExtras = Bundle.setDefusable(in.readBundle(), true);
return l;
}
@@ -991,6 +1088,12 @@
if (hasBearingAccuracy()) {
parcel.writeFloat(mBearingAccuracyDegrees);
}
+ if (hasMslAltitude()) {
+ parcel.writeDouble(mMslAltitudeMeters);
+ }
+ if (hasMslAltitudeAccuracy()) {
+ parcel.writeFloat(mMslAltitudeAccuracyMeters);
+ }
parcel.writeBundle(mExtras);
}
diff --git a/media/TEST_MAPPING b/media/TEST_MAPPING
index 4385a80..803c33c 100644
--- a/media/TEST_MAPPING
+++ b/media/TEST_MAPPING
@@ -1,6 +1,9 @@
{
"presubmit": [
{
+ "name": "CtsMediaBetterTogetherTestCases"
+ },
+ {
"name": "CtsCameraTestCases",
"options" : [
{
diff --git a/media/java/android/media/AudioDeviceVolumeManager.java b/media/java/android/media/AudioDeviceVolumeManager.java
index 11cacd0..fe58cca 100644
--- a/media/java/android/media/AudioDeviceVolumeManager.java
+++ b/media/java/android/media/AudioDeviceVolumeManager.java
@@ -235,13 +235,7 @@
mDeviceVolumeDispatcherStub = new DeviceVolumeDispatcherStub();
}
} else {
- for (ListenerInfo info : mDeviceVolumeListeners) {
- if (info.mListener == vclistener) {
- throw new IllegalArgumentException(
- "attempt to call setDeviceAbsoluteMultiVolumeBehavior() "
- + "on a previously registered listener");
- }
- }
+ mDeviceVolumeListeners.removeIf(info -> info.mDevice.equalTypeAddress(device));
}
mDeviceVolumeListeners.add(listenerInfo);
mDeviceVolumeDispatcherStub.register(true, device, volumes, handlesVolumeAdjustment);
@@ -304,6 +298,28 @@
"removeOnDeviceVolumeBehaviorChangedListener");
}
+ /**
+ * Return human-readable name for volume behavior
+ * @param behavior one of the volume behaviors defined in AudioManager
+ * @return a string for the given behavior
+ */
+ public static String volumeBehaviorName(@AudioManager.DeviceVolumeBehavior int behavior) {
+ switch (behavior) {
+ case AudioManager.DEVICE_VOLUME_BEHAVIOR_VARIABLE:
+ return "DEVICE_VOLUME_BEHAVIOR_VARIABLE";
+ case AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL:
+ return "DEVICE_VOLUME_BEHAVIOR_FULL";
+ case AudioManager.DEVICE_VOLUME_BEHAVIOR_FIXED:
+ return "DEVICE_VOLUME_BEHAVIOR_FIXED";
+ case AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE:
+ return "DEVICE_VOLUME_BEHAVIOR_ABSOLUTE";
+ case AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE:
+ return "DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE";
+ default:
+ return "invalid volume behavior " + behavior;
+ }
+ }
+
private final class DeviceVolumeBehaviorDispatcherStub
extends IDeviceVolumeBehaviorDispatcher.Stub implements CallbackUtil.DispatcherStub {
public void register(boolean register) {
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 2c68273..13933bb 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -6628,7 +6628,7 @@
/**
* The message sent to apps when the contents of the device list changes if they provide
- * a {@link Handler} object to addOnAudioDeviceConnectionListener().
+ * a {@link Handler} object to {@link registerAudioDeviceCallback}.
*/
private final static int MSG_DEVICES_CALLBACK_REGISTERED = 0;
private final static int MSG_DEVICES_DEVICES_ADDED = 1;
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 55c558f..85cd342 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -2910,6 +2910,10 @@
* For portability, an application should prime the data path to the maximum allowed
* by writing data until the write() method returns a short transfer count.
* This allows play() to start immediately, and reduces the chance of underrun.
+ *<p>
+ * As of {@link android.os.Build.VERSION_CODES#S} the minimum level to start playing
+ * can be obtained using {@link #getStartThresholdInFrames()} and set with
+ * {@link #setStartThresholdInFrames(int)}.
*
* @throws IllegalStateException if the track isn't properly initialized
*/
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index e39914d..e3d9ab1 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -755,7 +755,7 @@
<h4 id=KeyFrames><a name="KeyFrames"></a>Stream Boundary and Key Frames</h4>
<p>
It is important that the input data after {@link #start} or {@link #flush} starts at a suitable
- stream boundary: the first frame must a key frame. A <em>key frame</em> can be decoded
+ stream boundary: the first frame must be a key frame. A <em>key frame</em> can be decoded
completely on its own (for most codecs this means an I-frame), and no frames that are to be
displayed after a key frame refer to frames before the key frame.
<p>
@@ -2317,10 +2317,6 @@
*/
public final void start() {
native_start();
- synchronized(mBufferLock) {
- cacheBuffers(true /* input */);
- cacheBuffers(false /* input */);
- }
}
private native final void native_start();
@@ -3952,6 +3948,9 @@
+ "objects and attach to QueueRequest objects.");
}
if (mCachedInputBuffers == null) {
+ cacheBuffers(true /* input */);
+ }
+ if (mCachedInputBuffers == null) {
throw new IllegalStateException();
}
// FIXME: check codec status
@@ -3990,6 +3989,9 @@
+ "Please use getOutputFrame to get output frames.");
}
if (mCachedOutputBuffers == null) {
+ cacheBuffers(false /* input */);
+ }
+ if (mCachedOutputBuffers == null) {
throw new IllegalStateException();
}
// FIXME: check codec status
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index 32fff1e..15dfc96 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -291,9 +291,10 @@
/**
* A key describing the log session ID for MediaCodec. The log session ID is a random 32-byte
* hexadecimal string that is used to associate metrics from multiple media codec instances
- * to the same playback or recording session.
+ * to the same playback or recording session. The value is created as
+ * {@link android.media.metrics.LogSessionId LogSessionId}. Sessions are created in
+ * {@link android.media.metrics.MediaMetricsManager MediaMetricsManager}.
* The associated value is a string.
- * @hide
*/
public static final String LOG_SESSION_ID = "log-session-id";
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppManagerCallback.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppManagerCallback.aidl
index fed86dc..2e792b3 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppManagerCallback.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppManagerCallback.aidl
@@ -22,10 +22,10 @@
* Interface to receive callbacks from ITvInteractiveAppManager regardless of sessions.
* @hide
*/
-interface ITvInteractiveAppManagerCallback {
+oneway interface ITvInteractiveAppManagerCallback {
void onInteractiveAppServiceAdded(in String iAppServiceId);
void onInteractiveAppServiceRemoved(in String iAppServiceId);
void onInteractiveAppServiceUpdated(in String iAppServiceId);
void onTvInteractiveAppServiceInfoUpdated(in TvInteractiveAppServiceInfo tvIAppInfo);
void onStateChanged(in String iAppServiceId, int type, int state, int err);
-}
\ No newline at end of file
+}
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index c8d2d1e..5850a81 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -1294,45 +1294,46 @@
std::string defaultMsg = "Unknown Error";
/* translate OS errors to Java API CryptoException errorCodes (which are positive) */
+ jint jerr = 0;
switch (err) {
case ERROR_DRM_NO_LICENSE:
- err = gCryptoErrorCodes.cryptoErrorNoKey;
+ jerr = gCryptoErrorCodes.cryptoErrorNoKey;
defaultMsg = "Crypto key not available";
break;
case ERROR_DRM_LICENSE_EXPIRED:
- err = gCryptoErrorCodes.cryptoErrorKeyExpired;
+ jerr = gCryptoErrorCodes.cryptoErrorKeyExpired;
defaultMsg = "License expired";
break;
case ERROR_DRM_RESOURCE_BUSY:
- err = gCryptoErrorCodes.cryptoErrorResourceBusy;
+ jerr = gCryptoErrorCodes.cryptoErrorResourceBusy;
defaultMsg = "Resource busy or unavailable";
break;
case ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION:
- err = gCryptoErrorCodes.cryptoErrorInsufficientOutputProtection;
+ jerr = gCryptoErrorCodes.cryptoErrorInsufficientOutputProtection;
defaultMsg = "Required output protections are not active";
break;
case ERROR_DRM_SESSION_NOT_OPENED:
- err = gCryptoErrorCodes.cryptoErrorSessionNotOpened;
+ jerr = gCryptoErrorCodes.cryptoErrorSessionNotOpened;
defaultMsg = "Attempted to use a closed session";
break;
case ERROR_DRM_INSUFFICIENT_SECURITY:
- err = gCryptoErrorCodes.cryptoErrorInsufficientSecurity;
+ jerr = gCryptoErrorCodes.cryptoErrorInsufficientSecurity;
defaultMsg = "Required security level is not met";
break;
case ERROR_DRM_CANNOT_HANDLE:
- err = gCryptoErrorCodes.cryptoErrorUnsupportedOperation;
+ jerr = gCryptoErrorCodes.cryptoErrorUnsupportedOperation;
defaultMsg = "Operation not supported in this configuration";
break;
case ERROR_DRM_FRAME_TOO_LARGE:
- err = gCryptoErrorCodes.cryptoErrorFrameTooLarge;
+ jerr = gCryptoErrorCodes.cryptoErrorFrameTooLarge;
defaultMsg = "Decrytped frame exceeds size of output buffer";
break;
case ERROR_DRM_SESSION_LOST_STATE:
- err = gCryptoErrorCodes.cryptoErrorLostState;
+ jerr = gCryptoErrorCodes.cryptoErrorLostState;
defaultMsg = "Session state was lost, open a new session and retry";
break;
default: /* Other negative DRM error codes go out best-effort. */
- err = MediaErrorToJavaError(err);
+ jerr = MediaErrorToJavaError(err);
defaultMsg = StrCryptoError(err);
break;
}
@@ -1344,7 +1345,7 @@
jstring msgObj = env->NewStringUTF(msgStr.c_str());
jthrowable exception =
- (jthrowable)env->NewObject(clazz.get(), constructID, err, msgObj);
+ (jthrowable)env->NewObject(clazz.get(), constructID, jerr, msgObj);
env->Throw(exception);
}
diff --git a/media/jni/android_media_Utils.cpp b/media/jni/android_media_Utils.cpp
index f4a39b3..b7ad6dc 100644
--- a/media/jni/android_media_Utils.cpp
+++ b/media/jni/android_media_Utils.cpp
@@ -18,10 +18,10 @@
#define LOG_TAG "AndroidMediaUtils"
#include <aidl/android/hardware/graphics/common/PlaneLayoutComponentType.h>
-#include <hardware/camera3.h>
#include <ui/GraphicBufferMapper.h>
#include <ui/GraphicTypes.h>
#include <utils/Log.h>
+
#include "android_media_Utils.h"
#define ALIGN(x, mask) ( ((x) + (mask) - 1) & ~((mask) - 1) )
@@ -122,8 +122,8 @@
}
// First check for BLOB transport header at the end of the buffer
- uint8_t* header = blobBuffer + (width - sizeof(struct camera3_jpeg_blob));
- struct camera3_jpeg_blob *blob = (struct camera3_jpeg_blob*)(header);
+ uint8_t* header = blobBuffer + (width - sizeof(struct camera3_jpeg_blob_v2));
+ struct camera3_jpeg_blob_v2 *blob = (struct camera3_jpeg_blob_v2*)(header);
if (blob->jpeg_blob_id == CAMERA3_JPEG_BLOB_ID ||
blob->jpeg_blob_id == CAMERA3_HEIC_BLOB_ID) {
size = blob->jpeg_size;
diff --git a/media/jni/android_media_Utils.h b/media/jni/android_media_Utils.h
index 4feb4f51..c12cec1 100644
--- a/media/jni/android_media_Utils.h
+++ b/media/jni/android_media_Utils.h
@@ -50,6 +50,20 @@
int getBufferHeight(BufferItem *buffer);
+// Must be in sync with AIDL CameraBlob : android.hardware.camera.device.CameraBlob
+// HALs must NOT copy this definition.
+// for details: http://b/229688810
+typedef struct camera3_jpeg_blob_v2 {
+ uint32_t jpeg_blob_id;
+ uint32_t jpeg_size;
+} camera3_jpeg_blobv2_t;
+
+// Must be in sync with AIDL CameraBlob : android.hardware.camera.device.CameraBlobId
+enum {
+ CAMERA3_JPEG_BLOB_ID = 0x00FF,
+ CAMERA3_JPEG_APP_SEGMENTS_BLOB_ID = 0x0100,
+};
+
}; // namespace android
#endif // _ANDROID_MEDIA_UTILS_H_
diff --git a/packages/BackupRestoreConfirmation/res/values-eu/strings.xml b/packages/BackupRestoreConfirmation/res/values-eu/strings.xml
index 5b52278..6f734a3 100644
--- a/packages/BackupRestoreConfirmation/res/values-eu/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-eu/strings.xml
@@ -18,10 +18,10 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="backup_confirm_title" msgid="827563724209303345">"Babeskopia osoa"</string>
<string name="restore_confirm_title" msgid="5469365809567486602">"Leheneratze osoa"</string>
- <string name="backup_confirm_text" msgid="1878021282758896593">"Datu guztien babeskopia egitea eta konektatutako ordenagailu batean gordetzea eskatu da. Horretarako baimena eman nahi duzu?\n\nEz baduzu babeskopia egitea zuk eskatu, ez eman eragiketarekin jarraitzeko baimena."</string>
+ <string name="backup_confirm_text" msgid="1878021282758896593">"Datu guztien babeskopia egitea eta konektatutako ordenagailu batean gordetzea eskatu da. Horretarako baimena eman nahi duzu?\n\nBabeskopia egitea zeuk eskatu ez baduzu, ez eman eragiketarekin jarraitzeko baimena."</string>
<string name="allow_backup_button_label" msgid="4217228747769644068">"Egin datuen babeskopia"</string>
<string name="deny_backup_button_label" msgid="6009119115581097708">"Ez egin babeskopia"</string>
- <string name="restore_confirm_text" msgid="7499866728030461776">"Konektatutako ordenagailu bateko datu guztiak leheneratzeko eskatu da. Horretarako baimena eman nahi duzu?\n\nEz baduzu leheneratzea zuk eskatu, ez eman eragiketarekin jarraitzeko baimena. Eragiketa gauzatzen bada, gailuan dituzun datu guztiak ordeztuko dira!"</string>
+ <string name="restore_confirm_text" msgid="7499866728030461776">"Konektatutako ordenagailu bateko datu guztiak leheneratzeko eskatu da. Horretarako baimena eman nahi duzu?\n\nLeheneratzea zeuk eskatu ez baduzu, ez eman eragiketarekin jarraitzeko baimena. Eragiketa gauzatzen bada, gailuan dituzun datu guztiak ordeztuko dira!"</string>
<string name="allow_restore_button_label" msgid="3081286752277127827">"Leheneratu datuak"</string>
<string name="deny_restore_button_label" msgid="1724367334453104378">"Ez leheneratu"</string>
<string name="current_password_text" msgid="8268189555578298067">"Idatzi babeskopien oraingo pasahitza behean:"</string>
diff --git a/packages/CompanionDeviceManager/res/values-af/strings.xml b/packages/CompanionDeviceManager/res/values-af/strings.xml
index bb3f987..e35b4b6 100644
--- a/packages/CompanionDeviceManager/res/values-af/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-af/strings.xml
@@ -17,11 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Metgeseltoestel-bestuurder"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Laat <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> toe om jou <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> te bestuur"</string>
+ <!-- no translation found for confirmation_title (3785000297483688997) -->
+ <skip />
<string name="profile_name_watch" msgid="576290739483672360">"horlosie"</string>
<string name="chooser_title" msgid="2262294130493605839">"Kies \'n <xliff:g id="PROFILE_NAME">%1$s</xliff:g> om deur <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> bestuur te word"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> sal interaksie met jou kennisgewings mag hê en toegang kry tot jou Foon-, SMS-, Kontakte- en Kalender-toestemmings."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> sal interaksie met jou kennisgewings mag hê en toegang kry tot jou Foon-, SMS-, Kontakte- en Kalender-toestemmings."</string>
+ <!-- no translation found for summary_watch (3002344206574997652) -->
+ <skip />
<string name="permission_apps" msgid="6142133265286656158">"Programme"</string>
<string name="permission_apps_summary" msgid="798718816711515431">"Stroom jou foon se programme"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Gee <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> toegang tot hierdie inligting op jou foon"</string>
@@ -44,4 +45,8 @@
<string name="consent_back" msgid="2560683030046918882">"Terug"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Gee programme op <strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> dieselfde toestemmings as op <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>Dit kan mikrofoon-, kamera- en liggingtoegang insluit, asook ander sensitiewe toestemmings op <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong>.</p> <p>Jy kan hierdie toestemmings enige tyd verander in jou Instellings op <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong>.</p>"</string>
+ <!-- no translation found for vendor_icon_description (4445875290032225965) -->
+ <skip />
+ <!-- no translation found for vendor_header_button_description (6566660389500630608) -->
+ <skip />
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-am/strings.xml b/packages/CompanionDeviceManager/res/values-am/strings.xml
index 5c72a16..a61cc3c 100644
--- a/packages/CompanionDeviceManager/res/values-am/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-am/strings.xml
@@ -17,11 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"አጃቢ የመሣሪያ አስተዳዳሪ"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> የእርስዎን <xliff:g id="DEVICE_NAME">%2$s</xliff:g> - <strong></strong> እንዲያስተዳደር ይፍቀዱ"</string>
+ <!-- no translation found for confirmation_title (3785000297483688997) -->
+ <skip />
<string name="profile_name_watch" msgid="576290739483672360">"ሰዓት"</string>
<string name="chooser_title" msgid="2262294130493605839">"በ<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> የሚተዳደር <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ይምረጡ"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ከማሳወቂያዎችዎ ጋር መስተጋብር እንዲፈጥር እና የእርስዎን ስልክ፣ ኤስኤምኤስ፣ እውቂያዎች እና የቀን መቁጠሪያ ፈቃዶች እንዲደርስ ይፈቀድለታል።"</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ከማሳወቂያዎችዎ ጋር መስተጋብር እንዲፈጥር እና የእርስዎን ስልክ፣ ኤስኤምኤስ፣ እውቂያዎች እና የቀን መቁጠሪያ ፈቃዶች እንዲደርስ ይፈቀድለታል።"</string>
+ <!-- no translation found for summary_watch (3002344206574997652) -->
+ <skip />
<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>
@@ -44,4 +45,6 @@
<string name="consent_back" msgid="2560683030046918882">"ተመለስ"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"በ<strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> ላይ ላሉ መተግበሪያዎች በ<strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong> ላይ ካሉት ጋር ተመሳሳይ ፈቃዶች ይሰጣቸው?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>ይህ የማይክሮፎን፣ የካሜራ እና የአካባቢ መዳረሻ እና ሌሎች በ<strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong>.</p> <p> ላይ ያሉ አደገኛ ፈቃዶችን ሊያካትት ይችላል።እነዚህን ፈቃዶች በማንኛውም ጊዜ በ<strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong>.</p>ላይ ቅንብሮችዎ ውስጥ መቀየር ይችላሉ።"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"የመተግበሪያ አዶ"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"የተጨማሪ መረጃ አዝራር"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-ar/strings.xml b/packages/CompanionDeviceManager/res/values-ar/strings.xml
index f3313c9..1407a2a 100644
--- a/packages/CompanionDeviceManager/res/values-ar/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ar/strings.xml
@@ -17,11 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"تطبيق \"مدير الجهاز المصاحب\""</string>
- <string name="confirmation_title" msgid="8455544820286920304">"السماح للتطبيق <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> بإدارة <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
+ <!-- no translation found for confirmation_title (3785000297483688997) -->
+ <skip />
<string name="profile_name_watch" msgid="576290739483672360">"ساعة"</string>
<string name="chooser_title" msgid="2262294130493605839">"اختَر <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ليديره تطبيق <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"سيتم السماح لتطبيق <xliff:g id="APP_NAME">%1$s</xliff:g> بالتفاعل مع الإشعارات والوصول إلى أذونات الهاتف والرسائل القصيرة وجهات الاتصال والتقويم."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"سيتم السماح لتطبيق <xliff:g id="APP_NAME">%1$s</xliff:g> بالتفاعل مع الإشعارات والوصول إلى أذونات الهاتف والرسائل القصيرة وجهات الاتصال والتقويم."</string>
+ <!-- no translation found for summary_watch (3002344206574997652) -->
+ <skip />
<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>
@@ -44,4 +45,8 @@
<string name="consent_back" msgid="2560683030046918882">"رجوع"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"هل تريد منح التطبيقات على <strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> نفس الأذونات على <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong>؟"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>قد تتضمَّن هذه الأذونات الوصول إلى الميكروفون والكاميرا والموقع الجغرافي وغيرها من أذونات الوصول إلى المعلومات الحسّاسة على <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong>.</p> <p>يمكنك تغيير هذه الأذونات في أي وقت في إعداداتك على <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong>.</p>"</string>
+ <!-- no translation found for vendor_icon_description (4445875290032225965) -->
+ <skip />
+ <!-- no translation found for vendor_header_button_description (6566660389500630608) -->
+ <skip />
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-as/strings.xml b/packages/CompanionDeviceManager/res/values-as/strings.xml
index 614260b..fc7545b 100644
--- a/packages/CompanionDeviceManager/res/values-as/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-as/strings.xml
@@ -17,11 +17,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"কম্পেনিয়ন ডিভাইচ মেনেজাৰ"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>ক আপোনাৰ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> পৰিচালনা কৰিবলৈ দিয়ক"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>ক আপোনাৰ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> এক্সেছ কৰিবলৈ দিয়ক"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ঘড়ী"</string>
<string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>এ পৰিচালনা কৰিব লগা এটা <xliff:g id="PROFILE_NAME">%1$s</xliff:g> বাছনি কৰক"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g>ক আপোনাৰ জাননী ব্যৱহাৰ কৰিবলৈ আৰু আপোনাৰ ফ’ন, এছএমএছ, সম্পৰ্ক আৰু কেলেণ্ডাৰৰ অনুমতি এক্সেছ কৰিবলৈ দিয়া হ’ব।"</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g>ক আপোনাৰ জাননী ব্যৱহাৰ কৰিবলৈ আৰু আপোনাৰ ফ’ন, এছএমএছ, সম্পৰ্ক আৰু কেলেণ্ডাৰৰ অনুমতি এক্সেছ কৰিবলৈ দিয়া হ’ব।"</string>
+ <string name="summary_watch" msgid="3002344206574997652">"আপোনাৰ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> পৰিচালনা কৰিবলৈ এই এপ্টোৰ আৱশ্যক। <xliff:g id="APP_NAME">%2$s</xliff:g>ক আপোনাৰ জাননী ব্যৱহাৰ কৰিবলৈ আৰু আপোনাৰ ফ’ন, এছএমএছ, সম্পৰ্ক ,কেলেণ্ডাৰ, কল লগ আৰু নিকটৱৰ্তী ডিভাইচৰ অনুমতি এক্সেছ কৰিবলৈ দিয়া হ’ব।"</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>
@@ -44,4 +43,6 @@
<string name="consent_back" msgid="2560683030046918882">"উভতি যাওক"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"এপ্সমূহক <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong>ত দিয়াৰ দৰে <strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong>তো একে অনুমতি প্ৰদান কৰিবনে?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>ইয়াত <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong>ত মাইক্ৰ’ফ’ন, কেমেৰা আৰু অৱস্থানৰ এক্সেছ আৰু অন্য সংবেদশীল অনুমতিসমূহ প্ৰদান কৰাটো অন্তৰ্ভুক্ত হ’ব পাৰে।</p> <p>আপুনি যিকোনো সময়তে <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong>ত থকা আপোনাৰ ছেটিঙত এই অনুমতিসমূহ সলনি কৰিব পাৰে।</p>"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"এপৰ চিহ্ন"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"অধিক তথ্যৰ বুটাম"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-az/strings.xml b/packages/CompanionDeviceManager/res/values-az/strings.xml
index 692b3a7..e8c11e8 100644
--- a/packages/CompanionDeviceManager/res/values-az/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-az/strings.xml
@@ -17,11 +17,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Kompanyon Cihaz Meneceri"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> tətbiqinə <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> cihazınızı idarə etməsinə icazə verin"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> tətbiqinin <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> cihazınıza girişinə icazə verin"</string>
<string name="profile_name_watch" msgid="576290739483672360">"izləyin"</string>
<string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> tərəfindən idarə ediləcək <xliff:g id="PROFILE_NAME">%1$s</xliff:g> seçin"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> bildirişlərinizə, Telefon, SMS, Kontaktlar və Təqvimə giriş əldə edəcək."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> bildirişlərinizə, Telefon, SMS, Kontaktlar və Təqvimə giriş əldə edəcək."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"Bu tətbiq <xliff:g id="DEVICE_NAME">%1$s</xliff:g> cihazınızı idarə etmək üçün lazımdır. <xliff:g id="APP_NAME">%2$s</xliff:g> bildirişlərinizə, Telefon, SMS, Kontaktlar, Təqvim, Zəng qeydləri və Yaxınlıqdakı cihaz icazələrinə giriş əldə edəcək."</string>
<string name="permission_apps" msgid="6142133265286656158">"Tətbiqlər"</string>
<string name="permission_apps_summary" msgid="798718816711515431">"Telefonunuzun tətbiqlərini yayımlayın"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> tətbiqinə telefonunuzdan bu məlumata giriş icazəsi verin"</string>
@@ -44,4 +43,6 @@
<string name="consent_back" msgid="2560683030046918882">"Geriyə"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"<strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> cihazındakı tətbiqlərə <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong> cihazındakılarla eyni icazələr verilsin?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>Buraya <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong> cihazındakı Mikrofon, Kamera və Məkana girişi və digər həssas icazələr daxil ola bilər.</p> <p>Bu icazələri istənilən vaxt <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong> cihazında ayarlarınızda dəyişə bilərsiniz.</p>"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Tətbiq İkonası"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Ətraflı Məlumat Düyməsi"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml b/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml
index 09fa465..71c0a41 100644
--- a/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml
@@ -17,16 +17,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Menadžer pridruženog uređaja"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Dozvolite aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> da upravlja uređajem <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
+ <!-- no translation found for confirmation_title (3785000297483688997) -->
+ <skip />
<string name="profile_name_watch" msgid="576290739483672360">"sat"</string>
<string name="chooser_title" msgid="2262294130493605839">"Odaberite profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g> kojim će upravljati aplikacija <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> će dobiti dozvolu za interakciju sa obaveštenjima i pristup dozvolama za telefon, SMS poruke, kontakte i kalendar."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> će dobiti dozvolu za interakciju sa obaveštenjima i pristup dozvolama za telefon, SMS poruke, kontakte i kalendar."</string>
+ <!-- no translation found for summary_watch (3002344206574997652) -->
+ <skip />
<string name="permission_apps" msgid="6142133265286656158">"Aplikacije"</string>
<string name="permission_apps_summary" msgid="798718816711515431">"Strimujte aplikacije na telefonu"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Dozvolite da <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> pristupa ovim informacijama sa telefona"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Usluge na više uređaja"</string>
- <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> zahteva dozvolu u ime uređaja <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> za pristup slikama, medijskom sadržaju i obaveštenjima sa telefona"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> zahteva dozvolu u ime uređaja <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> za pristup slikama, medijskom sadržaju i obaveštenjima sa telefona"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Dozvolite da <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> pristupa ovim informacijama sa telefona"</string>
@@ -44,4 +45,6 @@
<string name="consent_back" msgid="2560683030046918882">"Nazad"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Aplikcijama na uređaju <strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> dajte sve dozvole kao na uređaju <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>To može da obuhvata pristup mikrofonu, kameri i lokaciji, kao i drugim osetljivim dozvolama na uređaju <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong>.</p> <p>U svakom trenutku možete da promenite te dozvole u Podešavanjima na uređaju <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong>.</p>"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Ikona aplikacije"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Dugme za više informacija"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-be/strings.xml b/packages/CompanionDeviceManager/res/values-be/strings.xml
index 882699e..1d5ded2 100644
--- a/packages/CompanionDeviceManager/res/values-be/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-be/strings.xml
@@ -17,16 +17,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Менеджар спадарожнай прылады"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Дазвольце праграме <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> кіраваць прыладай <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
+ <!-- no translation found for confirmation_title (3785000297483688997) -->
+ <skip />
<string name="profile_name_watch" msgid="576290739483672360">"гадзіннік"</string>
<string name="chooser_title" msgid="2262294130493605839">"Выберыце прыладу (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>), якой будзе кіраваць праграма <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> атрымае доступ да вашых апавяшчэнняў, тэлефона, SMS, кантактаў і календара."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> атрымае доступ да вашых апавяшчэнняў, тэлефона, SMS, кантактаў і календара."</string>
+ <!-- no translation found for summary_watch (3002344206574997652) -->
+ <skip />
<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="helper_title_app_streaming" msgid="4151687003439969765">"Сэрвісы для некалькіх прылад"</string>
- <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> запытвае дазвол ад імя вашай прылады \"<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>\" на доступ да фота, медыяфайлаў і апавяшчэнняў вашага тэлефона"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"Праграма \"<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>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Дазвольце праграме <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> мець доступ да гэтай інфармацыі з вашага тэлефона"</string>
@@ -36,7 +37,7 @@
<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_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g> запытвае дазвол ад імя вашай прылады \"<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>\" на перадачу праграм плынню паміж вашымі прыладамі"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"Праграма \"<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>
<string name="consent_yes" msgid="8344487259618762872">"Дазволіць"</string>
@@ -44,4 +45,8 @@
<string name="consent_back" msgid="2560683030046918882">"Назад"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Даць праграмам на прыладзе <strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> такія самыя дазволы, што і на прыладзе <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>Дазволы могуць уключаць доступ да мікрафона, камеры і даных пра месцазнаходжанне, а таксама да іншай канфідэнцыяльнай інфармацыі на прыладзе <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong>.</p> <p>Вы можаце ў любы час змяніць гэтыя дазволы ў Наладах на прыладзе <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong>.</p>"</string>
+ <!-- no translation found for vendor_icon_description (4445875290032225965) -->
+ <skip />
+ <!-- no translation found for vendor_header_button_description (6566660389500630608) -->
+ <skip />
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-bg/strings.xml b/packages/CompanionDeviceManager/res/values-bg/strings.xml
index f55b950..f93f9fa 100644
--- a/packages/CompanionDeviceManager/res/values-bg/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-bg/strings.xml
@@ -17,16 +17,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Разрешаване на <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> да управлява устройството ви <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
+ <!-- no translation found for confirmation_title (3785000297483688997) -->
+ <skip />
<string name="profile_name_watch" msgid="576290739483672360">"часовник"</string>
<string name="chooser_title" msgid="2262294130493605839">"Изберете устройство (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>), което да се управлява от <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ще получи разрешение да взаимодейства с известията ви и да осъществява достъп до разрешенията за телефона, SMS съобщенията, контактите и календара."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ще получи разрешение да взаимодейства с известията ви и да осъществява достъп до разрешенията за телефона, SMS съобщенията, контактите и календара."</string>
+ <!-- no translation found for summary_watch (3002344206574997652) -->
+ <skip />
<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="helper_title_app_streaming" msgid="4151687003439969765">"Услуги за различни устройства"</string>
- <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> иска разрешение от името на <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> за достъп до снимките, мултимедията и известията на телефона ви"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"„<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>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Разрешете на <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> да осъществява достъп до тази информация от телефона ви"</string>
@@ -44,4 +45,6 @@
<string name="consent_back" msgid="2560683030046918882">"Назад"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Искате ли да дадете на приложенията на <strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> същите разрешения както на <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>Това може да включва достъп до микрофона, камерата и местоположението, както и други разрешения за достъп до поверителна информация на <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong>.</p> <p>Можете да промените тези разрешения по всяко време от настройките на <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong>.</p>"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Икона на приложението"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Бутон за още информация"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-bn/strings.xml b/packages/CompanionDeviceManager/res/values-bn/strings.xml
index c38c17f..0fa52d9 100644
--- a/packages/CompanionDeviceManager/res/values-bn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-bn/strings.xml
@@ -17,11 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"আপনার <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ম্যানেজ করার জন্য <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> -কে অনুমতি দিন"</string>
+ <!-- no translation found for confirmation_title (3785000297483688997) -->
+ <skip />
<string name="profile_name_watch" msgid="576290739483672360">"ঘড়ি"</string>
<string name="chooser_title" msgid="2262294130493605839">"<xliff:g id="PROFILE_NAME">%1$s</xliff:g> বেছে নিন যেটি <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> ম্যানেজ করবে"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> আপনার বিজ্ঞপ্তির সাথে ইন্টার্যাক্ট করতে পারবে, তার সাথে আপনার ফোন, এমএসএস, পরিচিতি এবং ক্যালেন্ডারের অনুমতিও অ্যাক্সেস করতে পারবে।"</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> আপনার বিজ্ঞপ্তির সাথে ইন্টার্যাক্ট করতে পারবে, তার সাথে আপনার ফোন, এমএসএস, পরিচিতি এবং ক্যালেন্ডারের অনুমতিও অ্যাক্সেস করতে পারবে।"</string>
+ <!-- no translation found for summary_watch (3002344206574997652) -->
+ <skip />
<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>
@@ -44,4 +45,8 @@
<string name="consent_back" msgid="2560683030046918882">"ফিরুন"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"<strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong>-এ যে অনুমতি দেওয়া আছে <strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong>-এও সেই একই অনুমতি দিতে চান?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>এটি <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong>.</p> <p&gt-এ হয়ত মাইক্রোফোন, ক্যামেরা এবং লোকেশনের অ্যাক্সেস ও অন্যান্য সংবেদনশীল অনুমতি অন্তর্ভুক্ত করতে পারে;আপনি যেকোনও সময় <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong>.</p>-এর \'সেটিংস\'-এ গিয়ে এইসব অনুমতি পরিবর্তন করতে পারবেন"</string>
+ <!-- no translation found for vendor_icon_description (4445875290032225965) -->
+ <skip />
+ <!-- no translation found for vendor_header_button_description (6566660389500630608) -->
+ <skip />
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-bs/strings.xml b/packages/CompanionDeviceManager/res/values-bs/strings.xml
index 4957f92..dd437c1 100644
--- a/packages/CompanionDeviceManager/res/values-bs/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-bs/strings.xml
@@ -17,16 +17,15 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Prateći upravitelj uređaja"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Dozvolite aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> da upravlja uređajem <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"Dopustite aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> da pristupa vašem uređaju <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
<string name="profile_name_watch" msgid="576290739483672360">"sat"</string>
<string name="chooser_title" msgid="2262294130493605839">"Odaberite uređaj <xliff:g id="PROFILE_NAME">%1$s</xliff:g> kojim će upravljati aplikacija <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"Aplikaciji <xliff:g id="APP_NAME">%1$s</xliff:g> će se dozvoliti da ostvari interakciju s vašim obavještenjima i da pristupi odobrenjima za Telefon, SMS, Kontakte i Kalendar."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"Aplikaciji <xliff:g id="APP_NAME">%1$s</xliff:g> će se dozvoliti da ostvari interakciju s vašim obavještenjima i da pristupi odobrenjima za Telefon, SMS, Kontakte i Kalendar."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"Ta je aplikacija potrebna za upravljanje vašim uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. Aplikacija <xliff:g id="APP_NAME">%2$s</xliff:g> moći će stupati u interakciju s vašim obavijestima i pristupati dopuštenjima za telefon, SMS-ove, kontakte, kalendar, zapisnike poziva i uređaje u blizini."</string>
<string name="permission_apps" msgid="6142133265286656158">"Aplikacije"</string>
<string name="permission_apps_summary" msgid="798718816711515431">"Prenosite aplikacije s telefona"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Dozvolite da aplikacija <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> pristupa ovim informacijama s telefona"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Usluga na više uređaja"</string>
- <string name="helper_summary_app_streaming" msgid="7380294597268573523">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> u ime uređaja <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> zahtijeva odobrenje da pristupi fotografijama, medijima i odobrenjima vašeg telefona"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> u ime uređaja <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> zahtijeva odobrenje da pristupi fotografijama, medijima i odobrenjima na vašem telefonu"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Dozvolite aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> da pristupa ovim informacijama s vašeg telefona"</string>
@@ -44,4 +43,6 @@
<string name="consent_back" msgid="2560683030046918882">"Nazad"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Dati aplikacijama na uređaju <strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> ista odobrenja kao na uređaju <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>Ovo može uključivati pristup mikrofonu, kameri i lokaciji i druga osjetljiva odobrenja na uređaju <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong>.</p> <p>Uvijek možete promijeniti ova odobrenja u Postavkama na uređaju <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong>.</p>"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Ikona aplikacije"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Gumb Više informacija"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-ca/strings.xml b/packages/CompanionDeviceManager/res/values-ca/strings.xml
index 74b42e7..4107445 100644
--- a/packages/CompanionDeviceManager/res/values-ca/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ca/strings.xml
@@ -17,11 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Gestor de dispositius complementaris"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Permet que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> gestioni el teu <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
+ <!-- no translation found for confirmation_title (3785000297483688997) -->
+ <skip />
<string name="profile_name_watch" msgid="576290739483672360">"rellotge"</string>
<string name="chooser_title" msgid="2262294130493605839">"Tria un <xliff:g id="PROFILE_NAME">%1$s</xliff:g> perquè el gestioni <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> tindrà permís per interaccionar amb les teves notificacions i accedir al telèfon, als SMS, als contactes i al calendari."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> tindrà permís per interaccionar amb les teves notificacions i accedir al telèfon, als SMS, als contactes i al calendari."</string>
+ <!-- no translation found for summary_watch (3002344206574997652) -->
+ <skip />
<string name="permission_apps" msgid="6142133265286656158">"Aplicacions"</string>
<string name="permission_apps_summary" msgid="798718816711515431">"Reprodueix en continu aplicacions del telèfon"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Permet que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> accedeixi a aquesta informació del telèfon"</string>
@@ -44,4 +45,8 @@
<string name="consent_back" msgid="2560683030046918882">"Enrere"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Vols concedir a les aplicacions del dispositiu <strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> els mateixos permisos que tenen a <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>Això pot incloure accés al micròfon, a la càmera i a la ubicació, i altres permisos sensibles a <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong>.</p> <p>Pots canviar aquests permisos en qualsevol moment a <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong>, a Configuració.</p>"</string>
+ <!-- no translation found for vendor_icon_description (4445875290032225965) -->
+ <skip />
+ <!-- no translation found for vendor_header_button_description (6566660389500630608) -->
+ <skip />
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-cs/strings.xml b/packages/CompanionDeviceManager/res/values-cs/strings.xml
index 35414f0..5e541ac 100644
--- a/packages/CompanionDeviceManager/res/values-cs/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-cs/strings.xml
@@ -17,11 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Správce doprovodných zařízení"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Povolit aplikaci <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> spravovat <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
+ <!-- no translation found for confirmation_title (3785000297483688997) -->
+ <skip />
<string name="profile_name_watch" msgid="576290739483672360">"hodinky"</string>
<string name="chooser_title" msgid="2262294130493605839">"Vyberte zařízení <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, které chcete spravovat pomocí aplikace <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> bude moci interagovat s vašimi oznámeními a získá přístup k telefonu, SMS, kontaktům a kalendáři."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> bude moci interagovat s vašimi oznámeními a získá přístup k telefonu, SMS, kontaktům a kalendáři."</string>
+ <!-- no translation found for summary_watch (3002344206574997652) -->
+ <skip />
<string name="permission_apps" msgid="6142133265286656158">"Aplikace"</string>
<string name="permission_apps_summary" msgid="798718816711515431">"Streamujte aplikace v telefonu"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Povolte aplikaci <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> přístup k těmto informacím z vašeho telefonu"</string>
@@ -44,4 +45,8 @@
<string name="consent_back" msgid="2560683030046918882">"Zpět"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Udělit aplikacím v zařízení <strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> stejné oprávnění jako v zařízení <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>Může být zahrnut přístup k mikrofonu, fotoaparátu a poloze a další citlivá oprávnění na zařízení <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong>.</p> <p>Tato oprávnění můžete v Nastavení na zařízení <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong> kdykoliv změnit.</p>"</string>
+ <!-- no translation found for vendor_icon_description (4445875290032225965) -->
+ <skip />
+ <!-- no translation found for vendor_header_button_description (6566660389500630608) -->
+ <skip />
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-da/strings.xml b/packages/CompanionDeviceManager/res/values-da/strings.xml
index d9f0162..e4ea709 100644
--- a/packages/CompanionDeviceManager/res/values-da/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-da/strings.xml
@@ -17,11 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Medfølgende enhedsadministrator"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Tillad at <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> kan administrere: <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
+ <!-- no translation found for confirmation_title (3785000297483688997) -->
+ <skip />
<string name="profile_name_watch" msgid="576290739483672360">"ur"</string>
<string name="chooser_title" msgid="2262294130493605839">"Vælg den enhed (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>), som skal administreres af <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> får tilladelse til at interagere med dine notifikationer og adgang til dine tilladelser for Opkald, Sms, Kontakter og Kalender."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> får tilladelse til at interagere med dine notifikationer og adgang til dine tilladelser for Opkald, Sms, Kontakter og Kalender."</string>
+ <!-- no translation found for summary_watch (3002344206574997652) -->
+ <skip />
<string name="permission_apps" msgid="6142133265286656158">"Apps"</string>
<string name="permission_apps_summary" msgid="798718816711515431">"Stream din telefons apps"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Giv <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> adgang til disse oplysninger fra din telefon"</string>
@@ -44,4 +45,6 @@
<string name="consent_back" msgid="2560683030046918882">"Tilbage"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Vil du give apps på <strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> de samme tilladelser som på <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>Dette kan omfatte mikrofon-, kamera- og lokationsadgang samt andre tilladelser til at tilgå følsomme oplysninger på <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong>.</p> <p>Du kan til enhver tid ændre disse tilladelser under Indstillinger på <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong>.</p>"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Appikon"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Knappen Flere oplysninger"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-de/strings.xml b/packages/CompanionDeviceManager/res/values-de/strings.xml
index 9fed647..0809575 100644
--- a/packages/CompanionDeviceManager/res/values-de/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-de/strings.xml
@@ -17,11 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Begleitgerät-Manager"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> erlauben, dein Gerät <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> zu verwalten"</string>
+ <!-- no translation found for confirmation_title (3785000297483688997) -->
+ <skip />
<string name="profile_name_watch" msgid="576290739483672360">"Smartwatch"</string>
<string name="chooser_title" msgid="2262294130493605839">"Gerät (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>) auswählen, das von <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> verwaltet werden soll"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> darf mit deinen Benachrichtigungen interagieren und auf die Berechtigungen „Telefon“, „SMS“, „Kontakte“ und „Kalender“ zugreifen."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> darf mit deinen Benachrichtigungen interagieren und auf die Berechtigungen „Telefon“, „SMS“, „Kontakte“ und „Kalender“ zugreifen."</string>
+ <!-- no translation found for summary_watch (3002344206574997652) -->
+ <skip />
<string name="permission_apps" msgid="6142133265286656158">"Apps"</string>
<string name="permission_apps_summary" msgid="798718816711515431">"Smartphone-Apps streamen"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> Zugriff auf diese Informationen von deinem Smartphone gewähren"</string>
@@ -44,4 +45,6 @@
<string name="consent_back" msgid="2560683030046918882">"Zurück"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Apps auf <strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> die gleichen Berechtigungen geben wie auf <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>Dazu können Berechtigungen für Mikrofon, Kamera und Standortzugriff sowie andere vertrauliche Berechtigungen auf <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong> gehören.</p><p>Sie lassen sich jederzeit in den Einstellungen auf <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong> ändern.</p>"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"App-Symbol"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Weitere-Infos-Schaltfläche"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-el/strings.xml b/packages/CompanionDeviceManager/res/values-el/strings.xml
index 4b419a5..bfad521 100644
--- a/packages/CompanionDeviceManager/res/values-el/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-el/strings.xml
@@ -17,11 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Διαχείριση συνοδευτικής εφαρμογής"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Επιτρέψτε στην εφαρμογή <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> να διαχειρίζεται τη συσκευή <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
+ <!-- no translation found for confirmation_title (3785000297483688997) -->
+ <skip />
<string name="profile_name_watch" msgid="576290739483672360">"ρολόι"</string>
<string name="chooser_title" msgid="2262294130493605839">"Επιλέξτε ένα προφίλ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> για διαχείριση από την εφαρμογή <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> θα επιτρέπεται να αλληλεπιδρά με τις ειδοποιήσεις σας και να έχει πρόσβαση στις άδειες Τηλεφώνου, SMS, Επαφών και Ημερολογίου."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> θα επιτρέπεται να αλληλεπιδρά με τις ειδοποιήσεις σας και να έχει πρόσβαση στις άδειες Τηλεφώνου, SMS, Επαφών και Ημερολογίου."</string>
+ <!-- no translation found for summary_watch (3002344206574997652) -->
+ <skip />
<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>
@@ -44,4 +45,8 @@
<string name="consent_back" msgid="2560683030046918882">"Πίσω"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Παραχώρηση στις εφαρμογές στη συσκευή <strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> των ίδιων αδειών όπως στη συσκευή <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong>;"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>Αυτές μπορεί να περιλαμβάνουν πρόσβαση σε μικρόφωνο, κάμερα και τοποθεσία και άλλες άδειες πρόσβασης σε ευαίσθητες πληροφορίες στη συσκευή <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong>.</p> <p>Μπορείτε να αλλάξετε αυτές τις άδειες ανά πάσα στιγμή στις Ρυθμίσεις σας στη συσκευή <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong>.</p>"</string>
+ <!-- no translation found for vendor_icon_description (4445875290032225965) -->
+ <skip />
+ <!-- no translation found for vendor_header_button_description (6566660389500630608) -->
+ <skip />
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml b/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml
index c4138ef..85a3275 100644
--- a/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml
@@ -17,11 +17,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to manage your <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to access your <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
<string name="profile_name_watch" msgid="576290739483672360">"watch"</string>
<string name="chooser_title" msgid="2262294130493605839">"Choose a <xliff:g id="PROFILE_NAME">%1$s</xliff:g> to be managed by <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> will be allowed to interact with your notifications and access your Phone, SMS, Contacts and Calendar permissions."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> will be allowed to interact with your notifications and access your Phone, SMS, Contacts and Calendar permissions."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"This app is needed to manage your <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> will be allowed to interact with your notifications and access your phone, SMS, contacts, calendar, call logs and Nearby devices permissions."</string>
<string name="permission_apps" msgid="6142133265286656158">"Apps"</string>
<string name="permission_apps_summary" msgid="798718816711515431">"Stream your phone’s apps"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to access this information from your phone"</string>
@@ -44,4 +43,6 @@
<string name="consent_back" msgid="2560683030046918882">"Back"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Give apps on <strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> the same permissions as on <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>This may include microphone, camera and location access, and other sensitive permissions on <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong>.</p> <p>You can change these permissions at any time in your settings on <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong>.</p>"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"App icon"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"More information button"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml b/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml
index c4138ef..85a3275 100644
--- a/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml
@@ -17,11 +17,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to manage your <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to access your <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
<string name="profile_name_watch" msgid="576290739483672360">"watch"</string>
<string name="chooser_title" msgid="2262294130493605839">"Choose a <xliff:g id="PROFILE_NAME">%1$s</xliff:g> to be managed by <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> will be allowed to interact with your notifications and access your Phone, SMS, Contacts and Calendar permissions."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> will be allowed to interact with your notifications and access your Phone, SMS, Contacts and Calendar permissions."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"This app is needed to manage your <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> will be allowed to interact with your notifications and access your phone, SMS, contacts, calendar, call logs and Nearby devices permissions."</string>
<string name="permission_apps" msgid="6142133265286656158">"Apps"</string>
<string name="permission_apps_summary" msgid="798718816711515431">"Stream your phone’s apps"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to access this information from your phone"</string>
@@ -44,4 +43,6 @@
<string name="consent_back" msgid="2560683030046918882">"Back"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Give apps on <strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> the same permissions as on <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>This may include microphone, camera and location access, and other sensitive permissions on <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong>.</p> <p>You can change these permissions at any time in your settings on <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong>.</p>"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"App icon"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"More information button"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml b/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml
index c4138ef..85a3275 100644
--- a/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml
@@ -17,11 +17,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to manage your <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to access your <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
<string name="profile_name_watch" msgid="576290739483672360">"watch"</string>
<string name="chooser_title" msgid="2262294130493605839">"Choose a <xliff:g id="PROFILE_NAME">%1$s</xliff:g> to be managed by <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> will be allowed to interact with your notifications and access your Phone, SMS, Contacts and Calendar permissions."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> will be allowed to interact with your notifications and access your Phone, SMS, Contacts and Calendar permissions."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"This app is needed to manage your <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> will be allowed to interact with your notifications and access your phone, SMS, contacts, calendar, call logs and Nearby devices permissions."</string>
<string name="permission_apps" msgid="6142133265286656158">"Apps"</string>
<string name="permission_apps_summary" msgid="798718816711515431">"Stream your phone’s apps"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to access this information from your phone"</string>
@@ -44,4 +43,6 @@
<string name="consent_back" msgid="2560683030046918882">"Back"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Give apps on <strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> the same permissions as on <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>This may include microphone, camera and location access, and other sensitive permissions on <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong>.</p> <p>You can change these permissions at any time in your settings on <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong>.</p>"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"App icon"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"More information button"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml b/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml
index c4138ef..85a3275 100644
--- a/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml
@@ -17,11 +17,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to manage your <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to access your <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
<string name="profile_name_watch" msgid="576290739483672360">"watch"</string>
<string name="chooser_title" msgid="2262294130493605839">"Choose a <xliff:g id="PROFILE_NAME">%1$s</xliff:g> to be managed by <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> will be allowed to interact with your notifications and access your Phone, SMS, Contacts and Calendar permissions."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> will be allowed to interact with your notifications and access your Phone, SMS, Contacts and Calendar permissions."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"This app is needed to manage your <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> will be allowed to interact with your notifications and access your phone, SMS, contacts, calendar, call logs and Nearby devices permissions."</string>
<string name="permission_apps" msgid="6142133265286656158">"Apps"</string>
<string name="permission_apps_summary" msgid="798718816711515431">"Stream your phone’s apps"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to access this information from your phone"</string>
@@ -44,4 +43,6 @@
<string name="consent_back" msgid="2560683030046918882">"Back"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Give apps on <strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> the same permissions as on <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>This may include microphone, camera and location access, and other sensitive permissions on <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong>.</p> <p>You can change these permissions at any time in your settings on <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong>.</p>"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"App icon"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"More information button"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-en-rXC/strings.xml b/packages/CompanionDeviceManager/res/values-en-rXC/strings.xml
index 69a212a..e95cc0d 100644
--- a/packages/CompanionDeviceManager/res/values-en-rXC/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rXC/strings.xml
@@ -17,11 +17,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to manage your <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to access your <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
<string name="profile_name_watch" msgid="576290739483672360">"watch"</string>
<string name="chooser_title" msgid="2262294130493605839">"Choose a <xliff:g id="PROFILE_NAME">%1$s</xliff:g> to be managed by <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> will be allowed to interact with your notifications and access your Phone, SMS, Contacts and Calendar permissions."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> will be allowed to interact with your notifications and access your Phone, SMS, Contacts and Calendar permissions."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"This app is needed to manage your <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> will be allowed to interact with your notifications and access your Phone, SMS, Contacts, Calendar, Call logs and Nearby devices permissions."</string>
<string name="permission_apps" msgid="6142133265286656158">"Apps"</string>
<string name="permission_apps_summary" msgid="798718816711515431">"Stream your phone’s apps"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to access this information from your phone"</string>
@@ -44,4 +43,6 @@
<string name="consent_back" msgid="2560683030046918882">"Back"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Give apps on <strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> the same permissions as on <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>This may include Microphone, Camera, and Location access, and other sensitive permissions on <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong>.</p> <p>You can change these permissions any time in your Settings on <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong>.</p>"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"App Icon"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"More Information Button"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml b/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml
index d5c0c06..e0a5b4c 100644
--- a/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml
@@ -17,11 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Administrador de dispositivo complementario"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Permite que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> administre tu <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
+ <!-- no translation found for confirmation_title (3785000297483688997) -->
+ <skip />
<string name="profile_name_watch" msgid="576290739483672360">"reloj"</string>
<string name="chooser_title" msgid="2262294130493605839">"Elige un <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para que <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> lo administre"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> podrá interactuar con tus notificaciones y acceder a los permisos de Teléfono, SMS, Contactos y Calendario."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> podrá interactuar con tus notificaciones y acceder a los permisos de Teléfono, SMS, Contactos y Calendario."</string>
+ <!-- no translation found for summary_watch (3002344206574997652) -->
+ <skip />
<string name="permission_apps" msgid="6142133265286656158">"Apps"</string>
<string name="permission_apps_summary" msgid="798718816711515431">"Transmitir las apps de tu teléfono"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Permite que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acceda a esta información de tu teléfono"</string>
@@ -44,4 +45,8 @@
<string name="consent_back" msgid="2560683030046918882">"Atrás"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"¿Quieres otorgar a las apps de <strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> los mismos permisos que tienen en <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>Esto puede incluir el acceso al micrófono, la cámara y la ubicación, así como otros permisos sensibles del dispositivo <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong>.</p> <p>Puedes cambiar estos permisos en cualquier momento en la Configuración del dispositivo <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong>.</p>"</string>
+ <!-- no translation found for vendor_icon_description (4445875290032225965) -->
+ <skip />
+ <!-- no translation found for vendor_header_button_description (6566660389500630608) -->
+ <skip />
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-es/strings.xml b/packages/CompanionDeviceManager/res/values-es/strings.xml
index aabf7f6..0b1db6c 100644
--- a/packages/CompanionDeviceManager/res/values-es/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-es/strings.xml
@@ -17,11 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Gestor de dispositivos complementario"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Permitir que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> gestione tu <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
+ <!-- no translation found for confirmation_title (3785000297483688997) -->
+ <skip />
<string name="profile_name_watch" msgid="576290739483672360">"reloj"</string>
<string name="chooser_title" msgid="2262294130493605839">"Elige un <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para gestionarlo con <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> podrá interactuar con tus notificaciones y acceder a tus permisos de teléfono, SMS, contactos y calendario."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> podrá interactuar con tus notificaciones y acceder a tus permisos de teléfono, SMS, contactos y calendario."</string>
+ <!-- no translation found for summary_watch (3002344206574997652) -->
+ <skip />
<string name="permission_apps" msgid="6142133265286656158">"Aplicaciones"</string>
<string name="permission_apps_summary" msgid="798718816711515431">"Emite las aplicaciones de tu teléfono"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Permitir que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acceda a esta información desde tu teléfono"</string>
@@ -44,4 +45,8 @@
<string name="consent_back" msgid="2560683030046918882">"Atrás"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"¿Dar a las aplicaciones de <strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> los mismos permisos que tienen en <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>Esto puede incluir acceso al micrófono, la cámara y la ubicación, así como otros permisos sensibles de <p><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong>.</p> <p>Puedes cambiar estos permisos cuando quieras en los ajustes de <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong>.</p>."</string>
+ <!-- no translation found for vendor_icon_description (4445875290032225965) -->
+ <skip />
+ <!-- no translation found for vendor_header_button_description (6566660389500630608) -->
+ <skip />
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-et/strings.xml b/packages/CompanionDeviceManager/res/values-et/strings.xml
index 57f1b1f..7a379b7 100644
--- a/packages/CompanionDeviceManager/res/values-et/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-et/strings.xml
@@ -17,16 +17,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Kaasseadme haldur"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Lubage rakendusel <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> hallata teie seadet <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
+ <!-- no translation found for confirmation_title (3785000297483688997) -->
+ <skip />
<string name="profile_name_watch" msgid="576290739483672360">"käekell"</string>
<string name="chooser_title" msgid="2262294130493605839">"Valige seade <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, mida haldab rakendus <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> saab kasutada teie märguandeid ning pääseda juurde teie telefoni, SMS-ide, kontaktide ja kalendri lubadele."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> saab kasutada teie märguandeid ning pääseda juurde teie telefoni, SMS-ide, kontaktide ja kalendri lubadele."</string>
+ <!-- no translation found for summary_watch (3002344206574997652) -->
+ <skip />
<string name="permission_apps" msgid="6142133265286656158">"Rakendused"</string>
<string name="permission_apps_summary" msgid="798718816711515431">"Telefoni rakenduste voogesitamine"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Lubage rakendusel <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> pääseda teie telefonis juurde sellele teabele"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Seadmeülesed teenused"</string>
- <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> taotleb teie seadme <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> nimel luba pääseda juurde telefoni fotodele, meediale ja märguannetele"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> taotlevad teie seadme <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> nimel luba pääseda juurde telefoni fotodele, meediale ja märguannetele"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Lubage rakendusel <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> pääseda teie telefonis juurde sellele teabele"</string>
@@ -44,4 +45,8 @@
<string name="consent_back" msgid="2560683030046918882">"Tagasi"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Kas anda rakendustele seadmes <strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> samad load, mis seadmes <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>See võib hõlmata mikrofoni, kaamerat ja juurdepääsu asukohale ning muid tundlikke lube seadmes <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong>.</p> <p>Võite neid lube seadme <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong> seadetes igal ajal muuta.</p>"</string>
+ <!-- no translation found for vendor_icon_description (4445875290032225965) -->
+ <skip />
+ <!-- no translation found for vendor_header_button_description (6566660389500630608) -->
+ <skip />
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-eu/strings.xml b/packages/CompanionDeviceManager/res/values-eu/strings.xml
index 24b8954..51982d7 100644
--- a/packages/CompanionDeviceManager/res/values-eu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-eu/strings.xml
@@ -17,15 +17,16 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Gailu osagarriaren kudeatzailea"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Eman <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> kudeatzeko baimena <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> aplikazioari"</string>
+ <!-- no translation found for confirmation_title (3785000297483688997) -->
+ <skip />
<string name="profile_name_watch" msgid="576290739483672360">"erlojua"</string>
<string name="chooser_title" msgid="2262294130493605839">"Aukeratu <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> aplikazioak kudeatu beharreko <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"Jakinarazpenekin interakzioan aritzeko eta telefonoa, SMSak, kontaktuak eta egutegia erabiltzeko baimenak izango ditu <xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"Jakinarazpenekin interakzioan aritzeko eta telefonoa, SMSak, kontaktuak eta egutegia erabiltzeko baimenak izango ditu <xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak."</string>
+ <!-- no translation found for summary_watch (3002344206574997652) -->
+ <skip />
<string name="permission_apps" msgid="6142133265286656158">"Aplikazioak"</string>
<string name="permission_apps_summary" msgid="798718816711515431">"Igorri zuzenean telefonoko aplikazioak"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Eman informazioa telefonotik hartzeko baimena <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> aplikazioari"</string>
- <string name="helper_title_app_streaming" msgid="4151687003439969765">"Gailu bat baino gehiagotarako zerbitzuak"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Gailu baterako baino gehiagotarako zerbitzuak"</string>
<string name="helper_summary_app_streaming" msgid="7380294597268573523">"Telefonoko argazkiak, multimedia-edukia eta jakinarazpenak atzitzeko baimena eskatzen ari da <xliff:g id="APP_NAME">%1$s</xliff:g>, <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> gailuaren izenean"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
@@ -44,4 +45,6 @@
<string name="consent_back" msgid="2560683030046918882">"Atzera"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"<strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong> gailuan dituzten baimen berberak eman nahi dizkiezu <strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> gailuko aplikazioei?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>Haien artean, baliteke <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong> gailuaren mikrofonoa, kamera, kokapenerako sarbidea eta beste kontuzko baimen batzuk egotea.</p> <p>Baimen horiek edonoiz alda ditzakezu <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong> gailuaren ezarpenetan.</p>"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Aplikazioaren ikonoa"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Informazio gehiagorako botoia"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-fa/strings.xml b/packages/CompanionDeviceManager/res/values-fa/strings.xml
index ba96c2ce..d9d64af 100644
--- a/packages/CompanionDeviceManager/res/values-fa/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fa/strings.xml
@@ -17,11 +17,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"مدیر دستگاه مرتبط"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"مجاز کردن <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> برای مدیریت کردن <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"به <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> اجازه دهید به <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> دسترسی داشته باشد"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ساعت"</string>
<string name="chooser_title" msgid="2262294130493605839">"انتخاب <xliff:g id="PROFILE_NAME">%1$s</xliff:g> برای مدیریت کردن با <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> میتواند با اعلانهای شما تعامل داشته باشد و به اجازههای «تلفن»، «پیامک»، «مخاطبین»، و «تقویم» دسترسی پیدا کند."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> میتواند با اعلانهای شما تعامل داشته باشد و به اجازههای «تلفن»، «پیامک»، «مخاطبین»، و «تقویم» دسترسی پیدا کند."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"این برنامه برای مدیریت <xliff:g id="DEVICE_NAME">%1$s</xliff:g> شما لازم است. <xliff:g id="APP_NAME">%2$s</xliff:g> میتواند با اعلانهای شما تعامل داشته باشد و به اجازههای «تلفن»، «پیامک»، «مخاطبین»، «تقویم»، «گزارشهای تماس» و «دستگاههای اطراف» دسترسی خواهد داشت."</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>
@@ -39,9 +38,11 @@
<string name="helper_summary_computer" msgid="1676407599909474428">"<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>
- <string name="consent_yes" msgid="8344487259618762872">"مجاز است"</string>
+ <string name="consent_yes" msgid="8344487259618762872">"اجازه دادن"</string>
<string name="consent_no" msgid="2640796915611404382">"مجاز نبودن"</string>
<string name="consent_back" msgid="2560683030046918882">"برگشت"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"به برنامههای موجود در <strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> همان اجازههای <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong> داده شود؟"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>این اجازهها میتواند شامل دسترسی به «میکروفون»، «دوربین»، و «مکان»، و دیگر اجازههای حساس در <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong> شود.</p> <p>هروقت بخواهید میتوانید این اجازهها را در «تنظیمات» در <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong> تغییر دهید.</p>"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"نماد برنامه"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"دکمه اطلاعات بیشتر"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-fi/strings.xml b/packages/CompanionDeviceManager/res/values-fi/strings.xml
index 50962f5..c0533c9 100644
--- a/packages/CompanionDeviceManager/res/values-fi/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fi/strings.xml
@@ -17,11 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Salli, että <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> voi hallinnoida tätä laitettasi: <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
+ <!-- no translation found for confirmation_title (3785000297483688997) -->
+ <skip />
<string name="profile_name_watch" msgid="576290739483672360">"kello"</string>
<string name="chooser_title" msgid="2262294130493605839">"Valitse <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, jota <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> hallinnoi"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> saa luvan hallinnoida ilmoituksiasi sekä pääsyn puhelimeesi, tekstiviesteihisi, kontakteihisi ja kalenteriisi."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> saa luvan hallinnoida ilmoituksiasi sekä pääsyn puhelimeesi, tekstiviesteihisi, kontakteihisi ja kalenteriisi."</string>
+ <!-- no translation found for summary_watch (3002344206574997652) -->
+ <skip />
<string name="permission_apps" msgid="6142133265286656158">"Sovellukset"</string>
<string name="permission_apps_summary" msgid="798718816711515431">"Striimaa puhelimen sovelluksia"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Salli, että <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> saa pääsyn näihin puhelimesi tietoihin"</string>
@@ -44,4 +45,8 @@
<string name="consent_back" msgid="2560683030046918882">"Takaisin"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Anna laitteen <strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> sovelluksille samat luvat kuin laitteella <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>Tähän voi kuulua pääsy mikrofoniin, kameraan ja sijaintiin sekä muita arkaluontoisia lupia laitteella <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong>.</p> <p>Voit muuttaa lupia asetuksista milloin tahansa laitteella <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong>.</p>"</string>
+ <!-- no translation found for vendor_icon_description (4445875290032225965) -->
+ <skip />
+ <!-- no translation found for vendor_header_button_description (6566660389500630608) -->
+ <skip />
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml b/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml
index 4d78453..49907a8 100644
--- a/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml
@@ -17,11 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Gestionnaire d\'appareil compagnon"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Autoriser <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à gérer votre <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
+ <!-- no translation found for confirmation_title (3785000297483688997) -->
+ <skip />
<string name="profile_name_watch" msgid="576290739483672360">"montre"</string>
<string name="chooser_title" msgid="2262294130493605839">"Choisissez un <xliff:g id="PROFILE_NAME">%1$s</xliff:g> qui sera géré par <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> aura l\'autorisation d\'interagir avec vos notifications et d\'accéder aux autorisations pour votre téléphone, vos messages texte, vos contacts et votre agenda."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> aura l\'autorisation d\'interagir avec vos notifications et d\'accéder aux autorisations pour votre téléphone, vos messages texte, vos contacts et votre agenda."</string>
+ <!-- no translation found for summary_watch (3002344206574997652) -->
+ <skip />
<string name="permission_apps" msgid="6142133265286656158">"Applications"</string>
<string name="permission_apps_summary" msgid="798718816711515431">"Diffusez les applications de votre téléphone"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Autorisez <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à accéder à ces informations à partir de votre téléphone"</string>
@@ -44,4 +45,6 @@
<string name="consent_back" msgid="2560683030046918882">"Retour"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Accorder aux applications sur <strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> les autorisations déjà accordées sur <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>Cela peut comprendre l\'accès au microphone, à l\'appareil photo et à la position, ainsi que d\'autres autorisations sensibles sur <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong>.</p> <p>Vous pouvez modifier ces autorisations en tout temps dans vos paramètres sur <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong>.</p>"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Icône de l\'application"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Bouton En savoir plus"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-fr/strings.xml b/packages/CompanionDeviceManager/res/values-fr/strings.xml
index b3fd930..e4dfea8 100644
--- a/packages/CompanionDeviceManager/res/values-fr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fr/strings.xml
@@ -17,13 +17,14 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Gestionnaire d\'appareils associés"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Autoriser <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à gérer votre <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
+ <!-- no translation found for confirmation_title (3785000297483688997) -->
+ <skip />
<string name="profile_name_watch" msgid="576290739483672360">"montre"</string>
<string name="chooser_title" msgid="2262294130493605839">"Sélectionner le/la <xliff:g id="PROFILE_NAME">%1$s</xliff:g> qui sera géré(e) par <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> aura l\'autorisation d\'interagir avec vos notifications et d\'accéder au téléphone, aux SMS, aux contacts et à l\'agenda."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> aura l\'autorisation d\'interagir avec vos notifications et d\'accéder au téléphone, aux SMS, aux contacts et à l\'agenda."</string>
+ <!-- no translation found for summary_watch (3002344206574997652) -->
+ <skip />
<string name="permission_apps" msgid="6142133265286656158">"Applis"</string>
- <string name="permission_apps_summary" msgid="798718816711515431">"Caster les applis de votre téléphone"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Diffuser en streaming les applis de votre téléphone"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Autoriser <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à accéder à ces informations depuis votre téléphone"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Services inter-appareils"</string>
<string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> demande l\'autorisation au nom de votre <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> pour accéder aux photos, contenus multimédias et notifications de votre téléphone"</string>
@@ -44,4 +45,8 @@
<string name="consent_back" msgid="2560683030046918882">"Retour"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Accorder les mêmes autorisations aux applis sur <strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> que sur <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong> ?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>Il peut s\'agir de l\'accès au micro, à l\'appareil photo et à la position, et d\'autres autorisations sensibles sur l\'appareil <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong>.</p> <p>Vous pouvez modifier ces autorisations à tout moment dans les paramètres de l\'appareil <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong>.</p>"</string>
+ <!-- no translation found for vendor_icon_description (4445875290032225965) -->
+ <skip />
+ <!-- no translation found for vendor_header_button_description (6566660389500630608) -->
+ <skip />
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-gl/strings.xml b/packages/CompanionDeviceManager/res/values-gl/strings.xml
index abfec86..6f054f7 100644
--- a/packages/CompanionDeviceManager/res/values-gl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-gl/strings.xml
@@ -17,11 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Xestor de dispositivos complementarios"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Permitir que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> xestione o teu dispositivo (<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>)"</string>
+ <!-- no translation found for confirmation_title (3785000297483688997) -->
+ <skip />
<string name="profile_name_watch" msgid="576290739483672360">"reloxo"</string>
<string name="chooser_title" msgid="2262294130493605839">"Escolle un perfil (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>) para que o xestione a aplicación <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> poderá interactuar coas túas notificacións e acceder aos permisos do teu teléfono, das mensaxes, dos contactos e do calendario."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> poderá interactuar coas túas notificacións e acceder aos permisos do teu teléfono, das mensaxes, dos contactos e do calendario."</string>
+ <!-- no translation found for summary_watch (3002344206574997652) -->
+ <skip />
<string name="permission_apps" msgid="6142133265286656158">"Aplicacións"</string>
<string name="permission_apps_summary" msgid="798718816711515431">"Emite as aplicacións do teu teléfono"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Permitir que a aplicación <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acceda a esta información desde o teu teléfono"</string>
@@ -44,4 +45,6 @@
<string name="consent_back" msgid="2560683030046918882">"Atrás"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Queres darlles ás aplicacións de <strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> os mesmos permisos que teñen as de <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>Con esta acción podes conceder acceso ao micrófono, á cámara e á localización, así como outros permisos de acceso á información confidencial de <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong>.</p> <p>Podes cambiar estes permisos en calquera momento na configuración de <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong>.</p>"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Icona de aplicación"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Botón de máis información"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-gu/strings.xml b/packages/CompanionDeviceManager/res/values-gu/strings.xml
index 881415e..84ead761 100644
--- a/packages/CompanionDeviceManager/res/values-gu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-gu/strings.xml
@@ -17,11 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"કમ્પેનિયન ડિવાઇસ મેનેજર"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"તમારા <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>ને મેનેજ કરવા માટે <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>ને મંજૂર કરો"</string>
+ <!-- no translation found for confirmation_title (3785000297483688997) -->
+ <skip />
<string name="profile_name_watch" msgid="576290739483672360">"સ્માર્ટવૉચ"</string>
<string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> દ્વારા મેનેજ કરવા માટે કોઈ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> પસંદ કરો"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g>ને તમારા નોટિફિકેશન સાથે ક્રિયાપ્રતિક્રિયા કરવાની તેમજ તમારો ફોન, SMS, સંપર્કો તેમજ કૅલેન્ડરની પરવાનગીઓ ઍક્સેસ કરવાની મંજૂરી આપવામાં આવશે."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g>ને તમારા નોટિફિકેશન સાથે ક્રિયાપ્રતિક્રિયા કરવાની તેમજ તમારો ફોન, SMS, સંપર્કો તેમજ કૅલેન્ડરની પરવાનગીઓ ઍક્સેસ કરવાની મંજૂરી આપવામાં આવશે."</string>
+ <!-- no translation found for summary_watch (3002344206574997652) -->
+ <skip />
<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>
@@ -44,4 +45,8 @@
<string name="consent_back" msgid="2560683030046918882">"પાછળ"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"<strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> પરની ઍપને <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong> પર છે તે જ પરવાનગીઓ આપીએ?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>આમાં <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong> પરના માઇક્રોફોન, કૅમેરા અને સ્થાનના ઍક્સેસ તથા અન્ય સંવેદનશીલ માહિતીની પરવાનગીઓ શામેલ હોઈ શકે છે.</p> <p>તમે <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong> પર તમારા સેટિંગમાં તમે કોઈપણ સમયે આ પરવાનગીઓને બદલી શકો છો.</p>"</string>
+ <!-- no translation found for vendor_icon_description (4445875290032225965) -->
+ <skip />
+ <!-- no translation found for vendor_header_button_description (6566660389500630608) -->
+ <skip />
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-hi/strings.xml b/packages/CompanionDeviceManager/res/values-hi/strings.xml
index 84c8a8e..c800e9a 100644
--- a/packages/CompanionDeviceManager/res/values-hi/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hi/strings.xml
@@ -17,16 +17,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"सहयोगी डिवाइस मैनेजर"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> को, अपनी <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> मैनेज करने की अनुमति दें"</string>
+ <!-- no translation found for confirmation_title (3785000297483688997) -->
+ <skip />
<string name="profile_name_watch" msgid="576290739483672360">"स्मार्टवॉच"</string>
<string name="chooser_title" msgid="2262294130493605839">"कोई <xliff:g id="PROFILE_NAME">%1$s</xliff:g> चुनें, ताकि उसे <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> की मदद से प्रबंधित किया जा सके"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> आपकी सूचनाओं पर कार्रवाई कर पाएगा. साथ ही, यह आपके फ़ोन, एसएमएस, संपर्कों, और कैलेंडर की अनुमतियों को भी ऐक्सेस कर पाएगा."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> आपकी सूचनाओं पर कार्रवाई कर पाएगा. साथ ही, यह आपके फ़ोन, एसएमएस, संपर्कों, और कैलेंडर की अनुमतियों को भी ऐक्सेस कर पाएगा."</string>
+ <!-- no translation found for summary_watch (3002344206574997652) -->
+ <skip />
<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="helper_title_app_streaming" msgid="4151687003439969765">"क्रॉस-डिवाइस से जुड़ी सेवाएं"</string>
- <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> आपके <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> की ओर से, फ़ोन में मौजूद फ़ोटो, मीडिया, और सूचनाओं को ऐक्सेस करने की अनुमति मांग रहा है"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<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>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> को अपने फ़ोन से यह जानकारी ऐक्सेस करने की अनुमति दें"</string>
@@ -44,4 +45,6 @@
<string name="consent_back" msgid="2560683030046918882">"वापस जाएं"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"क्या <strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> पर ऐप्लिकेशन को वही अनुमतियां देनी हैं जो <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong> पर दी हैं?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>इसमें <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong> पर मौजूद माइक्रोफ़ोन, कैमरा, जगह की जानकारी को ऐक्सेस करने, और अन्य संवेदनशील जानकारी ऐक्सेस करने की अनुमतियां शामिल हो सकती हैं.</p> <p>किसी भी समय <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong> की सेटिंग में जाकर, इन अनुमतियों में बदलाव किए जा सकते हैं.</p>"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"ऐप्लिकेशन आइकॉन"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"ज़्यादा जानकारी वाला बटन"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-hr/strings.xml b/packages/CompanionDeviceManager/res/values-hr/strings.xml
index fda9cfa..224bf69 100644
--- a/packages/CompanionDeviceManager/res/values-hr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hr/strings.xml
@@ -17,11 +17,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Dopustite aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> da upravlja vašim <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"Dopustite aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> da pristupa vašem uređaju <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
<string name="profile_name_watch" msgid="576290739483672360">"satom"</string>
<string name="chooser_title" msgid="2262294130493605839">"Odaberite profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g> kojim će upravljati aplikacija <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> moći će stupati u interakciju s vašim obavijestima i pristupati dopuštenjima za telefon, SMS-ove, kontakte i kalendar."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> moći će stupati u interakciju s vašim obavijestima i pristupati dopuštenjima za telefon, SMS-ove, kontakte i kalendar."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"Ta je aplikacija potrebna za upravljanje vašim uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. Aplikacija <xliff:g id="APP_NAME">%2$s</xliff:g> moći će stupati u interakciju s vašim obavijestima i pristupati dopuštenjima za telefon, SMS-ove, kontakte, kalendar, zapisnike poziva i uređaje u blizini."</string>
<string name="permission_apps" msgid="6142133265286656158">"Aplikacije"</string>
<string name="permission_apps_summary" msgid="798718816711515431">"Streaming aplikacija vašeg telefona"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Omogućite aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> da pristupa informacijama s vašeg telefona"</string>
@@ -44,4 +43,6 @@
<string name="consent_back" msgid="2560683030046918882">"Natrag"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Davanje jednakih dopuštenja aplikacijama na uređaju <strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> kao i na uređaju <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>To može uključivati pristup mikrofonu, kameri i lokaciji i druga dopuštenja za osjetljive podatke na uređaju <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong>.</p> <p>Ta dopuštenja uvijek možete promijeniti u postavkama na uređaju <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong>.</p>"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Ikona aplikacije"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Gumb Više informacija"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-hu/strings.xml b/packages/CompanionDeviceManager/res/values-hu/strings.xml
index a65b312..b336e51 100644
--- a/packages/CompanionDeviceManager/res/values-hu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hu/strings.xml
@@ -17,11 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Társeszközök kezelője"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"A(z) <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> engedélyezése a(z) <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> kezelésére"</string>
+ <!-- no translation found for confirmation_title (3785000297483688997) -->
+ <skip />
<string name="profile_name_watch" msgid="576290739483672360">"óra"</string>
<string name="chooser_title" msgid="2262294130493605839">"A(z) <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> alkalmazással kezelni kívánt <xliff:g id="PROFILE_NAME">%1$s</xliff:g> kiválasztása"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> műveleteket végezhet majd az értesítésekkel, és hozzáférhet a telefonra, az SMS-ekre, a névjegyekre és a naptárra vonatkozó engedélyekhez."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> műveleteket végezhet majd az értesítésekkel, és hozzáférhet a telefonra, az SMS-ekre, a névjegyekre és a naptárra vonatkozó engedélyekhez."</string>
+ <!-- no translation found for summary_watch (3002344206574997652) -->
+ <skip />
<string name="permission_apps" msgid="6142133265286656158">"Alkalmazások"</string>
<string name="permission_apps_summary" msgid="798718816711515431">"A telefon alkalmazásainak streamelése"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Engedélyezi a(z) „<xliff:g id="APP_NAME">%1$s</xliff:g>” alkalmazás számára az információhoz való hozzáférést a telefonról"</string>
@@ -44,4 +45,6 @@
<string name="consent_back" msgid="2560683030046918882">"Vissza"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Ugyanolyan engedélyeket ad a(z) <strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> eszközön található alkalmazásoknak, mint a(z) <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong> eszköz esetén?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>Ide tartozhatnak a mikrofonhoz, a kamerához és a helyhez való hozzáférések, valamint a(z) <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong> eszközön érvényes egyéb, bizalmas adatokra vonatkozó hozzáférési engedélyek is.</p> <p>Ezeket az engedélyeket bármikor módosíthatja a(z) <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong> eszköz beállításai között.</p>"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Alkalmazás ikonja"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"További információ gomb"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-hy/strings.xml b/packages/CompanionDeviceManager/res/values-hy/strings.xml
index f07a785..94f020c 100644
--- a/packages/CompanionDeviceManager/res/values-hy/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hy/strings.xml
@@ -17,11 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Թույլատրեք <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> հավելվածին կառավարել ձեր <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> սարքը"</string>
+ <!-- no translation found for confirmation_title (3785000297483688997) -->
+ <skip />
<string name="profile_name_watch" msgid="576290739483672360">"ժամացույց"</string>
<string name="chooser_title" msgid="2262294130493605839">"Ընտրեք <xliff:g id="PROFILE_NAME">%1$s</xliff:g>ը, որը պետք է կառավարվի <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> հավելվածի կողմից"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածը կկարողանա փոխազդել ձեր ծանուցումների հետ և կստանա «Հեռախոս», «SMS», «Կոնտակտներ» և «Օրացույց» ծառայությունների թույլտվությունները։"</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածը կկարողանա փոխազդել ձեր ծանուցումների հետ և կստանա «Հեռախոս», «SMS», «Կոնտակտներ» և «Օրացույց» ծառայությունների թույլտվությունները։"</string>
+ <!-- no translation found for summary_watch (3002344206574997652) -->
+ <skip />
<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>
@@ -44,4 +45,8 @@
<string name="consent_back" msgid="2560683030046918882">"Հետ"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"<strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> սարքում տա՞լ հավելվածներին նույն թույլտվությունները, ինչ <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong> սարքում"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>Դրանք կարող են ներառել խոսափողի, տեսախցիկի և տեղադրության տվյալների օգտագործման թույլտվությունները, ինչպես նաև կոնֆիդենցիալ տեղեկությունների օգտագործման այլ թույլտվություններ <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong> սարքում։</p> <p>Այդ թույլտվությունները ցանկացած ժամանակ կարելի է փոխել <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong> սարքի ձեր կարգավորումներում։</p>"</string>
+ <!-- no translation found for vendor_icon_description (4445875290032225965) -->
+ <skip />
+ <!-- no translation found for vendor_header_button_description (6566660389500630608) -->
+ <skip />
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-in/strings.xml b/packages/CompanionDeviceManager/res/values-in/strings.xml
index 6fbdcbe..7fefba1 100644
--- a/packages/CompanionDeviceManager/res/values-in/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-in/strings.xml
@@ -17,13 +17,14 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Pengelola Perangkat Pendamping"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Izinkan <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> untuk mengelola <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
+ <!-- no translation found for confirmation_title (3785000297483688997) -->
+ <skip />
<string name="profile_name_watch" msgid="576290739483672360">"smartwatch"</string>
<string name="chooser_title" msgid="2262294130493605839">"Pilih <xliff:g id="PROFILE_NAME">%1$s</xliff:g> untuk dikelola oleh <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> akan diizinkan berinteraksi dengan notifikasi dan mengakses izin Telepon, SMS, Kontak, dan Kalender."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> akan diizinkan berinteraksi dengan notifikasi dan mengakses izin Telepon, SMS, Kontak, dan Kalender."</string>
+ <!-- no translation found for summary_watch (3002344206574997652) -->
+ <skip />
<string name="permission_apps" msgid="6142133265286656158">"Aplikasi"</string>
- <string name="permission_apps_summary" msgid="798718816711515431">"Melakukan streaming aplikasi ponsel Anda"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Streaming aplikasi ponsel"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Izinkan <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> untuk mengakses informasi ini dari ponsel Anda"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Layanan lintas perangkat"</string>
<string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> meminta izin atas nama <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> untuk mengakses foto, media, dan notifikasi ponsel Anda"</string>
@@ -44,4 +45,8 @@
<string name="consent_back" msgid="2560683030046918882">"Kembali"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Berikan aplikasi di <strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> izin yang sama seperti di <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>Ini termasuk akses Mikrofon, Kamera, dan Lokasi, serta izin sensitif lainnya di <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong>.</p> <p>Anda dapat mengubah izin ini kapan saja di Setelan pada <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong>.</p>"</string>
+ <!-- no translation found for vendor_icon_description (4445875290032225965) -->
+ <skip />
+ <!-- no translation found for vendor_header_button_description (6566660389500630608) -->
+ <skip />
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-is/strings.xml b/packages/CompanionDeviceManager/res/values-is/strings.xml
index 035a5a2..e4a5361 100644
--- a/packages/CompanionDeviceManager/res/values-is/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-is/strings.xml
@@ -17,11 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Stjórnun fylgdartækja"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Veita <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> stjórn á: <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
+ <!-- no translation found for confirmation_title (3785000297483688997) -->
+ <skip />
<string name="profile_name_watch" msgid="576290739483672360">"úr"</string>
<string name="chooser_title" msgid="2262294130493605839">"Velja <xliff:g id="PROFILE_NAME">%1$s</xliff:g> sem <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> á að stjórna"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> fær aðgang að tilkynningum og heimildum síma, SMS, tengiliða og dagatals."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> fær aðgang að tilkynningum og heimildum síma, SMS, tengiliða og dagatals."</string>
+ <!-- no translation found for summary_watch (3002344206574997652) -->
+ <skip />
<string name="permission_apps" msgid="6142133265286656158">"Forrit"</string>
<string name="permission_apps_summary" msgid="798718816711515431">"Streymdu forritum símans"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Veita <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> aðgang að þessum upplýsingum úr símanum þínum"</string>
@@ -44,4 +45,8 @@
<string name="consent_back" msgid="2560683030046918882">"Til baka"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Veita forritum í <strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> sömu heimildir og í <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>Þetta kann að fela í sér aðgang að hljóðnema, myndavél og staðsetningu og aðrar heimildir fyrir viðkvæmu efni í <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong>.</p> <p>Hægt er að breyta þessum heimildum hvenær sem er í stillingunum í <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong>.</p>"</string>
+ <!-- no translation found for vendor_icon_description (4445875290032225965) -->
+ <skip />
+ <!-- no translation found for vendor_header_button_description (6566660389500630608) -->
+ <skip />
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-it/strings.xml b/packages/CompanionDeviceManager/res/values-it/strings.xml
index 3bf2bcd..71df4ef 100644
--- a/packages/CompanionDeviceManager/res/values-it/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-it/strings.xml
@@ -17,14 +17,15 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Gestione dispositivi companion"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Consenti all\'app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> di gestire <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
+ <!-- no translation found for confirmation_title (3785000297483688997) -->
+ <skip />
<string name="profile_name_watch" msgid="576290739483672360">"orologio"</string>
<string name="chooser_title" msgid="2262294130493605839">"Scegli un <xliff:g id="PROFILE_NAME">%1$s</xliff:g> che sia gestito da <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"L\'app <xliff:g id="APP_NAME">%1$s</xliff:g> potrà interagire con le tue notifiche e accedere alle autorizzazioni Telefono, SMS, Contatti e Calendario."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"L\'app <xliff:g id="APP_NAME">%1$s</xliff:g> potrà interagire con le tue notifiche e accedere alle autorizzazioni Telefono, SMS, Contatti e Calendario."</string>
+ <!-- no translation found for summary_watch (3002344206574997652) -->
+ <skip />
<string name="permission_apps" msgid="6142133265286656158">"App"</string>
<string name="permission_apps_summary" msgid="798718816711515431">"Trasmetti in streaming le app del tuo telefono"</string>
- <string name="title_app_streaming" msgid="2270331024626446950">"Consenti all\'app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> di accedere a queste informazioni dal tuo telefono"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Consenti a <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> di accedere a queste informazioni dal tuo telefono"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Servizi cross-device"</string>
<string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> richiede per conto del tuo <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> l\'autorizzazione ad accedere a foto, contenuti multimediali e notifiche del telefono"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
@@ -44,4 +45,6 @@
<string name="consent_back" msgid="2560683030046918882">"Indietro"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Vuoi dare alle app su <strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> le stesse autorizzazioni che hai dato su <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>Potrebbero essere incluse le autorizzazioni di accesso al microfono, alla fotocamera e alla posizione, nonché altre autorizzazioni sensibili su <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong>.</p> <p>Puoi cambiare queste autorizzazioni in qualsiasi momento nelle Impostazioni su <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong>.</p>"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Icona dell\'app"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Pulsante Altre informazioni"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-iw/strings.xml b/packages/CompanionDeviceManager/res/values-iw/strings.xml
index b8794fe..fe815f5 100644
--- a/packages/CompanionDeviceManager/res/values-iw/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-iw/strings.xml
@@ -17,11 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"ניהול מכשיר מותאם"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"אישור לאפליקציה <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> לנהל את <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
+ <!-- no translation found for confirmation_title (3785000297483688997) -->
+ <skip />
<string name="profile_name_watch" msgid="576290739483672360">"שעון"</string>
<string name="chooser_title" msgid="2262294130493605839">"בחירת <xliff:g id="PROFILE_NAME">%1$s</xliff:g> לניהול באמצעות <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"האפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> תוכל לבצע פעולות בהתראות ותקבל הרשאות גישה לטלפון, ל-SMS לאנשי הקשר וליומן."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"האפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> תוכל לבצע פעולות בהתראות ותקבל הרשאות גישה לטלפון, ל-SMS לאנשי הקשר וליומן."</string>
+ <!-- no translation found for summary_watch (3002344206574997652) -->
+ <skip />
<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>
@@ -44,4 +45,6 @@
<string name="consent_back" msgid="2560683030046918882">"חזרה"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"האם לתת לאפליקציות ב-<strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong>את אותן הרשאות כמו ב-<strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>ההרשאות עשויות לכלול גישה למיקרופון, למצלמה ולמיקום, וכן גישה למידע רגיש אחר ב-</strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong>.</p&gt; <p>אפשר לשנות את ההרשאות האלה בכל שלב בהגדרות של <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong>.</p>"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"סמל האפליקציה"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"לחצן מידע נוסף"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-ja/strings.xml b/packages/CompanionDeviceManager/res/values-ja/strings.xml
index 579907f..a8f9877 100644
--- a/packages/CompanionDeviceManager/res/values-ja/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ja/strings.xml
@@ -17,11 +17,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"コンパニオン デバイス マネージャ"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> に <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> の管理を許可する"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> に <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> へのアクセスを許可"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ウォッチ"</string>
<string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> の管理対象となる<xliff:g id="PROFILE_NAME">%1$s</xliff:g>の選択"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> は通知を使用でき、電話、SMS、連絡先、カレンダーの権限にもアクセスできるようになります。"</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> は通知を使用でき、電話、SMS、連絡先、カレンダーの権限にもアクセスできるようになります。"</string>
+ <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、連絡先、カレンダー、通話履歴、付近のデバイスの権限へのアクセスが可能となります。"</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>
@@ -44,4 +43,8 @@
<string name="consent_back" msgid="2560683030046918882">"戻る"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"<strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> のアプリに <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong> の場合と同じ権限を付与しますか?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>これには、<strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong> のマイク、カメラ、位置情報へのアクセスや、その他の機密情報に関わる権限が含まれる可能性があります。</p> <p>これらの権限は <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong> の [設定] でいつでも変更できます。</p>"</string>
+ <!-- no translation found for vendor_icon_description (4445875290032225965) -->
+ <skip />
+ <!-- no translation found for vendor_header_button_description (6566660389500630608) -->
+ <skip />
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-ka/strings.xml b/packages/CompanionDeviceManager/res/values-ka/strings.xml
index 7b15ad1..7db3d0c 100644
--- a/packages/CompanionDeviceManager/res/values-ka/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ka/strings.xml
@@ -17,11 +17,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"კომპანიონი მოწყობილობების მენეჯერი"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"ნება დართეთ <strong><xliff:g id="APP_NAME">%1$s</xliff:g>-ს</strong>, რომ მართოს თქვენი <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"დაუშვით <strong><xliff:g id="APP_NAME">%1$s</xliff:g>-ის</strong>, წვდომა თქვენს <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g>-ზე</strong>"</string>
<string name="profile_name_watch" msgid="576290739483672360">"საათი"</string>
<string name="chooser_title" msgid="2262294130493605839">"აირჩიეთ <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, რომელიც უნდა მართოს <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>-მა"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> შეძლებს თქვენს შეტყობინებებთან ინტერაქციას და თქვენი ტელეფონის, SMS-ების, კონტაქტებისა და კალენდრის ნებართვებზე წვდომას."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> შეძლებს თქვენს შეტყობინებებთან ინტერაქციას და თქვენი ტელეფონის, SMS-ების, კონტაქტებისა და კალენდრის ნებართვებზე წვდომას."</string>
+ <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-ების, კონტაქტებისა, კალენდრის, ზარების ჟურნალისა და ახლომახლო მოწყობილობების ნებართვებზე წვდომას."</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>
@@ -44,4 +43,6 @@
<string name="consent_back" msgid="2560683030046918882">"უკან"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"გსურთ აპებს <strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong>-ზე იგივე ნებართვები მიანიჭოთ, როგორიც აქვს <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong>-ზე?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>აღნიშნული შეიძლება მოიცავდეს მიკროფონზე, კამერასა და მდებარეობაზე წვდომას თუ სხვა ნებართვას სენსიტიურ ინფორმაციაზე <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong>-ში.</p> <p>ამ ნებართვების შეცვლა ნებისმიერ დროს შეგიძლიათ თქვენი პარამეტრებიდან <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong>-ში.</p>"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"აპის ხატულა"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"დამატებითი ინფორმაციის ღილაკი"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-kk/strings.xml b/packages/CompanionDeviceManager/res/values-kk/strings.xml
index 93cb44c9..071e7b0 100644
--- a/packages/CompanionDeviceManager/res/values-kk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-kk/strings.xml
@@ -17,11 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> қолданбасына <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> құрылғысын басқаруға рұқсат беру"</string>
+ <!-- no translation found for confirmation_title (3785000297483688997) -->
+ <skip />
<string name="profile_name_watch" msgid="576290739483672360">"сағат"</string>
<string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> арқылы басқарылатын <xliff:g id="PROFILE_NAME">%1$s</xliff:g> құрылғысын таңдаңыз"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасы хабарландыруларды, телефонды, SMS хабардарын, контактілерді және күнтізбе рұқсаттарын пайдалана алады."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасы хабарландыруларды, телефонды, SMS хабардарын, контактілерді және күнтізбе рұқсаттарын пайдалана алады."</string>
+ <!-- no translation found for summary_watch (3002344206574997652) -->
+ <skip />
<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>
@@ -44,4 +45,8 @@
<string name="consent_back" msgid="2560683030046918882">"Артқа"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"<strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> құрылғысындағы қолданбаларға <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong> құрылғысындағыдай рұқсаттар берілсін бе?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>Оларға микрофонды, камераны және геодеректі пайдалану рұқсаттары, сондай-ақ <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong> құрылғысына берілетін басқа да құпия ақпарат рұқсаттары кіруі мүмкін.</p> <p>Бұл рұқсаттарды кез келген уақытта <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong> құрылғысындағы параметрлерден өзгерте аласыз.</p>"</string>
+ <!-- no translation found for vendor_icon_description (4445875290032225965) -->
+ <skip />
+ <!-- no translation found for vendor_header_button_description (6566660389500630608) -->
+ <skip />
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-km/strings.xml b/packages/CompanionDeviceManager/res/values-km/strings.xml
index 3e2ec4c..3219b82 100644
--- a/packages/CompanionDeviceManager/res/values-km/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-km/strings.xml
@@ -17,13 +17,14 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"កម្មវិធីគ្រប់គ្រងឧបករណ៍ដៃគូ"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"អនុញ្ញាតឱ្យ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> គ្រប់គ្រង <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> របស់អ្នក"</string>
+ <!-- no translation found for confirmation_title (3785000297483688997) -->
+ <skip />
<string name="profile_name_watch" msgid="576290739483672360">"នាឡិកា"</string>
<string name="chooser_title" msgid="2262294130493605839">"ជ្រើសរើស <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ដើម្បីឱ្យស្ថិតក្រោមការគ្រប់គ្រងរបស់ <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> នឹងត្រូវបានអនុញ្ញាតឱ្យធ្វើអន្តរកម្មជាមួយការជូនដំណឹងរបស់អ្នក និងចូលប្រើការអនុញ្ញាតប្រតិទិន, ទូរសព្ទ, SMS និងទំនាក់ទំនងរបស់អ្នក។"</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> នឹងត្រូវបានអនុញ្ញាតឱ្យធ្វើអន្តរកម្មជាមួយការជូនដំណឹងរបស់អ្នក និងចូលប្រើការអនុញ្ញាតប្រតិទិន, ទូរសព្ទ, SMS និងទំនាក់ទំនងរបស់អ្នក។"</string>
+ <!-- no translation found for summary_watch (3002344206574997652) -->
+ <skip />
<string name="permission_apps" msgid="6142133265286656158">"កម្មវិធី"</string>
- <string name="permission_apps_summary" msgid="798718816711515431">"បញ្ចាំងកម្មវិធីរបស់ទូរសព្ទអ្នក"</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="helper_title_app_streaming" msgid="4151687003439969765">"សេវាកម្មឆ្លងកាត់ឧបករណ៍"</string>
<string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> កំពុងស្នើសុំការអនុញ្ញាតជំនួសឱ្យ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> របស់អ្នក ដើម្បីចូលប្រើរូបថត មេឌៀ និងការជូនដំណឹងរបស់ទូរសព្ទអ្នក"</string>
@@ -44,4 +45,8 @@
<string name="consent_back" msgid="2560683030046918882">"ថយក្រោយ"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"ផ្ដល់ការអនុញ្ញាតឱ្យកម្មវិធីនៅលើ <strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> ដូចនៅលើ <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong> ឬ?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>សកម្មភាពនេះអាចរួមបញ្ចូលការចូលប្រើទីតាំង កាមេរ៉ា និងមីក្រូហ្វូន និងការអនុញ្ញាតដែលមានលក្ខណៈរសើបផ្សេងទៀតនៅលើ <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong>។</p> <p>អ្នកអាចប្ដូរការអនុញ្ញាតទាំងនេះបានគ្រប់ពេលវេលានៅក្នុងការកំណត់នៅលើ <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong>។</p>"</string>
+ <!-- no translation found for vendor_icon_description (4445875290032225965) -->
+ <skip />
+ <!-- no translation found for vendor_header_button_description (6566660389500630608) -->
+ <skip />
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-kn/strings.xml b/packages/CompanionDeviceManager/res/values-kn/strings.xml
index ef1ad49..5593d3d 100644
--- a/packages/CompanionDeviceManager/res/values-kn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-kn/strings.xml
@@ -17,11 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"ಕಂಪ್ಯಾನಿಯನ್ ಸಾಧನ ನಿರ್ವಾಹಕರು"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"ನಿಮ್ಮ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ಅನ್ನು ನಿರ್ವಹಿಸಲು <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ಅನ್ನು ಅನುಮತಿಸಿ"</string>
+ <!-- no translation found for confirmation_title (3785000297483688997) -->
+ <skip />
<string name="profile_name_watch" msgid="576290739483672360">"ವೀಕ್ಷಿಸಿ"</string>
<string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> ಮೂಲಕ ನಿರ್ವಹಿಸಬೇಕಾದ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ಅನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"ನಿಮ್ಮ ಅಧಿಸೂಚನೆಗಳೊಂದಿಗೆ ಸಂವಹನ ನಡೆಸಲು ಮತ್ತು ನಿಮ್ಮ ಫೋನ್, SMS, ಸಂಪರ್ಕಗಳು ಮತ್ತು Calendar ಅನುಮತಿಗಳನ್ನು ಪ್ರವೇಶಿಸಲು <xliff:g id="APP_NAME">%1$s</xliff:g> ಗೆ ಅನುಮತಿಸಲಾಗುತ್ತದೆ."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"ನಿಮ್ಮ ಅಧಿಸೂಚನೆಗಳೊಂದಿಗೆ ಸಂವಹನ ನಡೆಸಲು ಮತ್ತು ನಿಮ್ಮ ಫೋನ್, SMS, ಸಂಪರ್ಕಗಳು ಮತ್ತು Calendar ಅನುಮತಿಗಳನ್ನು ಪ್ರವೇಶಿಸಲು <xliff:g id="APP_NAME">%1$s</xliff:g> ಗೆ ಅನುಮತಿಸಲಾಗುತ್ತದೆ."</string>
+ <!-- no translation found for summary_watch (3002344206574997652) -->
+ <skip />
<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>
@@ -44,4 +45,8 @@
<string name="consent_back" msgid="2560683030046918882">"ಹಿಂದೆ"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"</strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong> ನಲ್ಲಿನ ಅನುಮತಿಗಳನ್ನೇ </strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> ನಲ್ಲಿನ ಆ್ಯಪ್ಗಳಿಗೆ ನೀಡಬೇಕೆ?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>ಇದು <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong> ನಲ್ಲಿನ ಮೈಕ್ರೊಫೋನ್, ಕ್ಯಾಮರಾ ಮತ್ತು ಸ್ಥಳ ಆ್ಯಕ್ಸೆಸ್ ಹಾಗೂ ಇತರ ಸೂಕ್ಷ್ಮ ಅನುಮತಿಗಳನ್ನು ಹೊಂದಿರಬಹುದು<p></p> <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong> ನಲ್ಲಿನ ನಿಮ್ಮ ಸೆಟ್ಟಿಂಗ್ಗಳಲ್ಲಿ ನೀವು ಈ ಅನುಮತಿಗಳನ್ನು ಯಾವಾಗ ಬೇಕಾದರೂ ಬದಲಾಯಿಸಬಹುದು.</p>"</string>
+ <!-- no translation found for vendor_icon_description (4445875290032225965) -->
+ <skip />
+ <!-- no translation found for vendor_header_button_description (6566660389500630608) -->
+ <skip />
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-ko/strings.xml b/packages/CompanionDeviceManager/res/values-ko/strings.xml
index 2c7d8da..cd24f52 100644
--- a/packages/CompanionDeviceManager/res/values-ko/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ko/strings.xml
@@ -17,11 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"부속 기기 관리자"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>에서 <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> 기기를 관리하도록 허용"</string>
+ <!-- no translation found for confirmation_title (3785000297483688997) -->
+ <skip />
<string name="profile_name_watch" msgid="576290739483672360">"시계"</string>
<string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>에서 관리할 <xliff:g id="PROFILE_NAME">%1$s</xliff:g>을(를) 선택"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g>에서 알림과 상호작용하고 전화, SMS, 연락처, 캘린더 권한에 액세스할 수 있게 됩니다."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g>에서 알림과 상호작용하고 전화, SMS, 연락처, 캘린더 권한에 액세스할 수 있게 됩니다."</string>
+ <!-- no translation found for summary_watch (3002344206574997652) -->
+ <skip />
<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>
@@ -41,7 +42,11 @@
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"허용"</string>
<string name="consent_no" msgid="2640796915611404382">"허용 안함"</string>
- <string name="consent_back" msgid="2560683030046918882">"뒤"</string>
+ <string name="consent_back" msgid="2560683030046918882">"뒤로"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"<strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong>에 설치된 앱에 <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong>에 설치된 앱과 동일한 권한을 부여하시겠습니까?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>여기에는 <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong>에서 허용했던 마이크, 카메라, 위치 정보 액세스 권한 및 기타 민감한 권한이 포함될 수 있습니다.</p> <p>언제든지 <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong>의 설정에서 이러한 권한을 변경할 수 있습니다.</p>"</string>
+ <!-- no translation found for vendor_icon_description (4445875290032225965) -->
+ <skip />
+ <!-- no translation found for vendor_header_button_description (6566660389500630608) -->
+ <skip />
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-ky/strings.xml b/packages/CompanionDeviceManager/res/values-ky/strings.xml
index 0311621..3e29f16 100644
--- a/packages/CompanionDeviceManager/res/values-ky/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ky/strings.xml
@@ -17,16 +17,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> колдонмосуна <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> түзмөгүңүздү башкарууга уруксат бериңиз"</string>
+ <!-- no translation found for confirmation_title (3785000297483688997) -->
+ <skip />
<string name="profile_name_watch" msgid="576290739483672360">"саат"</string>
<string name="chooser_title" msgid="2262294130493605839">"<xliff:g id="PROFILE_NAME">%1$s</xliff:g> <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> тарабынан башкарылсын"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> билдирмелериңизди көрүп, телефонуңуздун, SMS билдирүүлөрүңүздүн, байланыштарыңыздын жана жылнаамаңыздын уруксаттарын пайдалана алат."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> билдирмелериңизди көрүп, телефонуңуздун, SMS билдирүүлөрүңүздүн, байланыштарыңыздын жана жылнаамаңыздын уруксаттарын пайдалана алат."</string>
+ <!-- no translation found for summary_watch (3002344206574997652) -->
+ <skip />
<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="helper_title_app_streaming" msgid="4151687003439969765">"Түзмөктөр аралык кызматтар"</string>
- <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосу <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> түзмөгүңүздүн атынан телефондогу сүрөттөрдү, медианы жана билдирмелерди колдонууга уруксат сурап жатат"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<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>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> колдонмосуна телефонуңуздагы ушул маалыматты көрүүгө уруксат бериңиз"</string>
@@ -44,4 +45,6 @@
<string name="consent_back" msgid="2560683030046918882">"Артка"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"<strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> түзмөгүнө да <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong> түзмөгүнө берилген уруксаттар берилсинби?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>Бул уруксаттарга микрофонго, камерага жана жайгашкан жерге кирүү мүмкүнчүлүгү жана <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong> түзмөгүндөгү башка купуя маалыматты көрүүгө уруксаттар кириши мүмкүн.</p> <p>Бул уруксаттарды каалаган убакта <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong> түзмөгүндөгү Жөндөөлөрдөн өзгөртө аласыз.</p>"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Колдонмонун сүрөтчөсү"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Дагы маалымат баскычы"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-lo/strings.xml b/packages/CompanionDeviceManager/res/values-lo/strings.xml
index cd22d98..affc54c 100644
--- a/packages/CompanionDeviceManager/res/values-lo/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-lo/strings.xml
@@ -17,11 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"ຕົວຈັດການອຸປະກອນປະກອບ"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"ອະນຸຍາດໃຫ້ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ຈັດການ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ຂອງທ່ານໄດ້"</string>
+ <!-- no translation found for confirmation_title (3785000297483688997) -->
+ <skip />
<string name="profile_name_watch" msgid="576290739483672360">"ໂມງ"</string>
<string name="chooser_title" msgid="2262294130493605839">"ເລືອກ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ເພື່ອໃຫ້ຖືກຈັດການໂດຍ <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ຈະໄດ້ຮັບອະນຸຍາດໃຫ້ໂຕ້ຕອບກັບການແຈ້ງເຕືອນຂອງທ່ານ ແລະ ເຂົ້າເຖິງການອະນຸຍາດໂທລະສັບ, SMS, ລາຍຊື່ຜູ້ຕິດຕໍ່ ແລະ ປະຕິທິນຂອງທ່ານໄດ້."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ຈະໄດ້ຮັບອະນຸຍາດໃຫ້ໂຕ້ຕອບກັບການແຈ້ງເຕືອນຂອງທ່ານ ແລະ ເຂົ້າເຖິງການອະນຸຍາດໂທລະສັບ, SMS, ລາຍຊື່ຜູ້ຕິດຕໍ່ ແລະ ປະຕິທິນຂອງທ່ານໄດ້."</string>
+ <!-- no translation found for summary_watch (3002344206574997652) -->
+ <skip />
<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>
@@ -44,4 +45,8 @@
<string name="consent_back" msgid="2560683030046918882">"ກັບຄືນ"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"ໃຫ້ການອະນຸຍາດແອັບຢູ່ <strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> ເປັນການອະນຸຍາດດຽວກັນກັບຢູ່ <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong> ບໍ?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>ນີ້ອາດຮວມສິດເຂົ້າເຖິງໄມໂຄຣໂຟນ, ກ້ອງຖ່າຍຮູບ ແລະ ສະຖານທີ່, ຮວມທັງການອະນຸຍາດທີ່ລະອຽດອ່ອນອື່ນໆຢູ່ <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong>.</p> <p>ທ່ານສາມາດປ່ຽນການອະນຸຍາດເຫຼົ່ານີ້ຕອນໃດກໍໄດ້ໃນການຕັ້ງຄ່າຂອງທ່ານຢູ່ <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong>.</p>"</string>
+ <!-- no translation found for vendor_icon_description (4445875290032225965) -->
+ <skip />
+ <!-- no translation found for vendor_header_button_description (6566660389500630608) -->
+ <skip />
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-lt/strings.xml b/packages/CompanionDeviceManager/res/values-lt/strings.xml
index 248791d..57bae8a 100644
--- a/packages/CompanionDeviceManager/res/values-lt/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-lt/strings.xml
@@ -17,11 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Leisti <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> tvarkyti <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
+ <!-- no translation found for confirmation_title (3785000297483688997) -->
+ <skip />
<string name="profile_name_watch" msgid="576290739483672360">"laikrodį"</string>
<string name="chooser_title" msgid="2262294130493605839">"Jūsų <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, kurį valdys <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> (pasirinkite)"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ galės sąveikauti su pranešimų funkcija ir pasiekti telefoną, SMS, kontaktus ir kalendorių."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ galės sąveikauti su pranešimų funkcija ir pasiekti telefoną, SMS, kontaktus ir kalendorių."</string>
+ <!-- no translation found for summary_watch (3002344206574997652) -->
+ <skip />
<string name="permission_apps" msgid="6142133265286656158">"Programos"</string>
<string name="permission_apps_summary" msgid="798718816711515431">"Telefono programų perdavimas srautu"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Leisti <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> pasiekti šią informaciją iš jūsų telefono"</string>
@@ -44,4 +45,6 @@
<string name="consent_back" msgid="2560683030046918882">"Atgal"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Suteikti <strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> esančioms programoms tuos pačius leidimus kaip <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong> esančioms programoms?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>Gali būti įtraukti prieigos prie mikrofono, kameros ir vietovės leidimai ir kiti leidimai pasiekti neskelbtiną informaciją <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong> įrenginyje.</p> <p>Šiuos leidimus galite bet kada pakeisti „Nustatymų“ skiltyje <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong> įrenginyje.</p>"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Programos piktograma"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Mygtukas „Daugiau informacijos“"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-lv/strings.xml b/packages/CompanionDeviceManager/res/values-lv/strings.xml
index 5e1c16a..e8b4a4c 100644
--- a/packages/CompanionDeviceManager/res/values-lv/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-lv/strings.xml
@@ -17,11 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Palīgierīču pārzinis"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Atļauja lietotnei <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> pārvaldīt ierīci <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
+ <!-- no translation found for confirmation_title (3785000297483688997) -->
+ <skip />
<string name="profile_name_watch" msgid="576290739483672360">"pulkstenis"</string>
<string name="chooser_title" msgid="2262294130493605839">"Profila (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>) izvēle, ko pārvaldīt lietotnē <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"Lietotnei <xliff:g id="APP_NAME">%1$s</xliff:g> tiks atļauts mijiedarboties ar jūsu paziņojumiem un piekļūt šādām atļaujām: Tālrunis, Īsziņas, Kontaktpersonas un Kalendārs."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"Lietotnei <xliff:g id="APP_NAME">%1$s</xliff:g> tiks atļauts mijiedarboties ar jūsu paziņojumiem un piekļūt šādām atļaujām: Tālrunis, Īsziņas, Kontaktpersonas un Kalendārs."</string>
+ <!-- no translation found for summary_watch (3002344206574997652) -->
+ <skip />
<string name="permission_apps" msgid="6142133265286656158">"Lietotnes"</string>
<string name="permission_apps_summary" msgid="798718816711515431">"Var straumēt jūsu tālruņa lietotnes"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Atļaut lietotnei <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> piekļūt šai informācijai no jūsu tālruņa"</string>
@@ -44,4 +45,8 @@
<string name="consent_back" msgid="2560683030046918882">"Atpakaļ"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Vai lietotnēm ierīcē <strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> piešķirt tādas pašas atļaujas kā ierīcē <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>Tās var būt mikrofona, kameras, atrašanās vietas piekļuves atļaujas un citas sensitīvas atļaujas ierīcē <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong>.</p> <p>Atļaujas jebkurā brīdī varat mainīt ierīces <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong>.</p> iestatījumos."</string>
+ <!-- no translation found for vendor_icon_description (4445875290032225965) -->
+ <skip />
+ <!-- no translation found for vendor_header_button_description (6566660389500630608) -->
+ <skip />
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-mk/strings.xml b/packages/CompanionDeviceManager/res/values-mk/strings.xml
index d0b8bbe..3393f36 100644
--- a/packages/CompanionDeviceManager/res/values-mk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-mk/strings.xml
@@ -17,11 +17,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Дозволете <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> да управува со вашиот <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"Дозволете <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> да пристапува до вашиот <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
<string name="profile_name_watch" msgid="576290739483672360">"часовник"</string>
<string name="chooser_title" msgid="2262294130493605839">"Изберете <xliff:g id="PROFILE_NAME">%1$s</xliff:g> со којшто ќе управува <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ќе може да остварува интеракција со известувањата и да пристапува до дозволите за телефонот, SMS, контактите и календарот."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ќе може да остварува интеракција со известувањата и да пристапува до дозволите за телефонот, SMS, контактите и календарот."</string>
+ <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, контактите, календарот, евиденцијата на повици и уредите во близина."</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>
@@ -44,4 +43,6 @@
<string name="consent_back" msgid="2560683030046918882">"Назад"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Дасе дадат исти дозволи на апликациите на <strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> како на <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>Ова може да вклучува пристап до микрофон, камера и локација и други чувствителни дозволи на <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong>.</p> <p>Може да ги промените дозволиве во секое време во вашите „Поставки“ на <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong>.</p>"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Икона на апликацијата"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Копче за повеќе информации"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-ml/strings.xml b/packages/CompanionDeviceManager/res/values-ml/strings.xml
index 5f11bc2..be36c5c 100644
--- a/packages/CompanionDeviceManager/res/values-ml/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ml/strings.xml
@@ -17,11 +17,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"കമ്പാനിയൻ ഉപകരണ മാനേജർ"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"നിങ്ങളുടെ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> മാനേജ് ചെയ്യാൻ, <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> എന്നതിനെ അനുവദിക്കുക"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"നിങ്ങളുടെ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ആക്സസ് ചെയ്യാൻ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> എന്നതിനെ അനുവദിക്കുക"</string>
<string name="profile_name_watch" msgid="576290739483672360">"വാച്ച്"</string>
<string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> ഉപയോഗിച്ച് മാനേജ് ചെയ്യുന്നതിന് ഒരു <xliff:g id="PROFILE_NAME">%1$s</xliff:g> തിരഞ്ഞെടുക്കുക"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"നിങ്ങളുടെ അറിയിപ്പുകളുമായി സംവദിക്കാനും നിങ്ങളുടെ ഫോൺ, SMS, കോൺടാക്റ്റുകൾ, കലണ്ടർ അനുമതികൾ എന്നിവ ആക്സസ് ചെയ്യാനും <xliff:g id="APP_NAME">%1$s</xliff:g> എന്നതിനെ അനുവദിക്കും."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"നിങ്ങളുടെ അറിയിപ്പുകളുമായി സംവദിക്കാനും നിങ്ങളുടെ ഫോൺ, SMS, കോൺടാക്റ്റുകൾ, കലണ്ടർ അനുമതികൾ എന്നിവ ആക്സസ് ചെയ്യാനും <xliff:g id="APP_NAME">%1$s</xliff:g> എന്നതിനെ അനുവദിക്കും."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"നിങ്ങളുടെ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> മാനേജ് ചെയ്യാൻ ഈ ആപ്പ് ആവശ്യമാണ്. നിങ്ങളുടെ അറിയിപ്പുകളുമായി ആശയവിനിമയം നടത്താനും നിങ്ങളുടെ ഫോൺ, SMS, കോൺടാക്റ്റുകൾ, കലണ്ടർ, കോൾ ചരിത്രം, സമീപമുള്ള ഉപകരണങ്ങളുടെ അനുമതികൾ എന്നിവ ആക്സസ് ചെയ്യാനും <xliff:g id="APP_NAME">%2$s</xliff:g> എന്നതിനെ അനുവദിക്കും."</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>
@@ -44,4 +43,6 @@
<string name="consent_back" msgid="2560683030046918882">"മടങ്ങുക"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"<strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong> എന്നതിലെ അതേ അനുമതികൾ <strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> എന്നതിലെ ആപ്പുകൾക്ക് നൽകണോ?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p><strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong>.</p> എന്നതിലെ മൈക്രോഫോൺ, ക്യാമറ, ലൊക്കേഷൻ ആക്സസ്, സെൻസിറ്റീവ് വിവരങ്ങൾക്കുള്ള മറ്റ് അനുമതികൾ എന്നിവയും ഇതിൽ ഉൾപ്പെട്ടേക്കാം<p>നിങ്ങൾക്ക് <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong>.</p> എന്നതിലെ ക്രമീകരണത്തിൽ ഏതുസമയത്തും ഈ അനുമതികൾ മാറ്റാം."</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"ആപ്പ് ഐക്കൺ"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"കൂടുതൽ വിവരങ്ങൾ ബട്ടൺ"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-mn/strings.xml b/packages/CompanionDeviceManager/res/values-mn/strings.xml
index 58e1385..dc52154 100644
--- a/packages/CompanionDeviceManager/res/values-mn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-mn/strings.xml
@@ -17,11 +17,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>-г удирдахын тулд <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>-г зөвшөөрнө үү"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>-д таны <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>-д хандахыг зөвшөөрнө үү"</string>
<string name="profile_name_watch" msgid="576290739483672360">"цаг"</string>
<string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>-н удирдах<xliff:g id="PROFILE_NAME">%1$s</xliff:g>-г сонгоно уу"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g>-д таны мэдэгдлүүдтэй харилцаж, таны Утас, SMS, Харилцагчид болон Календарийн зөвшөөрөлд хандахыг зөвшөөрнө."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g>-д таны мэдэгдлүүдтэй харилцаж, таны Утас, SMS, Харилцагчид болон Календарийн зөвшөөрөлд хандахыг зөвшөөрнө."</string>
+ <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, Харилцагчид, Календарь, Дуудлагын жагсаалт болон Ойролцоох төхөөрөмжүүдийн зөвшөөрөлд хандахыг зөвшөөрнө."</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>
@@ -44,4 +43,6 @@
<string name="consent_back" msgid="2560683030046918882">"Буцах"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"<strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> дээрх аппуудад <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong> дээрхтэй адил зөвшөөрөл өгөх үү?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>Үүнд Микрофон, Камер болон Байршлын хандалт болон <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong> дээрх бусад эмзэг зөвшөөрөл багтаж болно.</p> <p>Та эдгээр зөвшөөрлийг <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong> дээрх Тохиргоо хэсэгтээ хүссэн үедээ өөрчлөх боломжтой.</p>"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Aппын дүрс тэмдэг"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Дэлгэрэнгүй мэдээллийн товчлуур"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-mr/strings.xml b/packages/CompanionDeviceManager/res/values-mr/strings.xml
index 1c38932..e5bdfd5 100644
--- a/packages/CompanionDeviceManager/res/values-mr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-mr/strings.xml
@@ -17,11 +17,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"सहयोगी डिव्हाइस व्यवस्थापक"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"तुमचे <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> व्यवस्थापित करण्यासाठी <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ला अनुमती द्या"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"तुमचे <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> अॅक्सेस करण्यासाठी <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ला अनुमती द्या"</string>
<string name="profile_name_watch" msgid="576290739483672360">"वॉच"</string>
<string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> द्वारे व्यवस्थापित करण्यासाठी <xliff:g id="PROFILE_NAME">%1$s</xliff:g> निवडा"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ला तुमच्या सूचनांशी संवाद साधण्याची आणि तुमचा फोन, एसएमएस, संपर्क आणि Calendar च्या परवानग्या अॅक्सेस करण्याची अनुमती मिळेल."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ला तुमच्या सूचनांशी संवाद साधण्याची आणि तुमचा फोन, एसएमएस, संपर्क आणि Calendar च्या परवानग्या अॅक्सेस करण्याची अनुमती मिळेल."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"तुमची <xliff:g id="DEVICE_NAME">%1$s</xliff:g> प्रोफाइल व्यवस्थापित करण्यासाठी हे ॲप आवश्यक आहे. <xliff:g id="APP_NAME">%2$s</xliff:g> ला तुमच्या सूचनांशी संवाद साधण्याची आणि तुमचा फोन, एसएमएस, संपर्क कॅलेंडर, कॉल लॉग व जवळपासच्या डिव्हाइसच्या परवानग्या अॅक्सेस करण्याची अनुमती मिळेल."</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>
@@ -44,4 +43,6 @@
<string name="consent_back" msgid="2560683030046918882">"मागे जा"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"<strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> वरील अॅप्सना <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong> प्रमाणेच परवानग्या द्यायच्या आहेत का?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>यामध्ये <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g><strong> वरील मायक्रोफोन, कॅमेरा आणि स्थान अॅक्सेस व इतर संवेदनशील परवानग्यांचा समावेश असू शकतो </strong>.</p> <p>तुम्ही <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong> वर तुमच्या सेटिंग्ज मध्ये या परवानग्या कधीही बदलू शकता</strong>.</p>"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"अॅप आयकन"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"अधिक माहिती बटण"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-ms/strings.xml b/packages/CompanionDeviceManager/res/values-ms/strings.xml
index a76f5e9..8ba0c73 100644
--- a/packages/CompanionDeviceManager/res/values-ms/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ms/strings.xml
@@ -17,11 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Pengurus Peranti Rakan"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Benarkan <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> untuk mengurus <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> anda"</string>
+ <!-- no translation found for confirmation_title (3785000297483688997) -->
+ <skip />
<string name="profile_name_watch" msgid="576290739483672360">"jam tangan"</string>
<string name="chooser_title" msgid="2262294130493605839">"Pilih <xliff:g id="PROFILE_NAME">%1$s</xliff:g> untuk diurus oleh <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> akan dibenarkan berinteraksi dengan pemberitahuan anda dan mengakses kebenaran Telefon, SMS, Kenalan dan Kalendar anda."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> akan dibenarkan berinteraksi dengan pemberitahuan anda dan mengakses kebenaran Telefon, SMS, Kenalan dan Kalendar anda."</string>
+ <!-- no translation found for summary_watch (3002344206574997652) -->
+ <skip />
<string name="permission_apps" msgid="6142133265286656158">"Apl"</string>
<string name="permission_apps_summary" msgid="798718816711515431">"Strim apl telefon anda"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Benarkan <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> mengakses maklumat ini daripada telefon anda"</string>
@@ -44,4 +45,8 @@
<string name="consent_back" msgid="2560683030046918882">"Kembali"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Berikan apl <strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> kebenaran yang sama seperti pada <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>Ini mungkin termasuk akses Mikrofon, Kamera dan Lokasi serta kebenaran sensitif lain pada <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong>.</p> <p>Anda boleh menukar kebenaran ini pada bila-bila masa dalam Tetapan anda pada <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong>.</p>"</string>
+ <!-- no translation found for vendor_icon_description (4445875290032225965) -->
+ <skip />
+ <!-- no translation found for vendor_header_button_description (6566660389500630608) -->
+ <skip />
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-my/strings.xml b/packages/CompanionDeviceManager/res/values-my/strings.xml
index 3950205..e47e834 100644
--- a/packages/CompanionDeviceManager/res/values-my/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-my/strings.xml
@@ -17,11 +17,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"တွဲဖက်ကိရိယာ မန်နေဂျာ"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"သင်၏ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ကို စီမံခန့်ခွဲရန် <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ကို ခွင့်ပြုပါ"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"သင်၏ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ကို သုံးရန် <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ကို ခွင့်ပြုပါ"</string>
<string name="profile_name_watch" msgid="576290739483672360">"နာရီ"</string>
<string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> က စီမံခန့်ခွဲရန် <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ကို ရွေးချယ်ပါ"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"သင်၏ ‘ဖုန်း’၊ ‘SMS စာတိုစနစ်’၊ ‘အဆက်အသွယ်များ’ နှင့် ‘ပြက္ခဒိန်’ ခွင့်ပြုချက်များကို သုံးရန်နှင့် အကြောင်းကြားချက်များကို ပြန်လှန်တုံ့ပြန်ရန် <xliff:g id="APP_NAME">%1$s</xliff:g> အား ခွင့်ပြုပါမည်။"</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"သင်၏ ‘ဖုန်း’၊ ‘SMS စာတိုစနစ်’၊ ‘အဆက်အသွယ်များ’ နှင့် ‘ပြက္ခဒိန်’ ခွင့်ပြုချက်များကို သုံးရန်နှင့် အကြောင်းကြားချက်များကို ပြန်လှန်တုံ့ပြန်ရန် <xliff:g id="APP_NAME">%1$s</xliff:g> အား ခွင့်ပြုပါမည်။"</string>
+ <string name="summary_watch" msgid="3002344206574997652">"သင်၏ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ကို စီမံခန့်ခွဲရန် ဤအက်ပ်ကိုလိုအပ်သည်။ သင်၏ ‘ဖုန်း’၊ ‘SMS စာတိုစနစ်’၊ ‘အဆက်အသွယ်များ’၊ ‘ပြက္ခဒိန်’၊ ‘ခေါ်ဆိုမှတ်တမ်း’ နှင့် \'အနီးတစ်ဝိုက်ရှိ စက်များ\' ခွင့်ပြုချက်များကို သုံးရန်နှင့် အကြောင်းကြားချက်များကို ပြန်လှန်တုံ့ပြန်ရန် <xliff:g id="APP_NAME">%2$s</xliff:g> အား ခွင့်ပြုပါမည်။"</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>
@@ -29,7 +28,7 @@
<string name="helper_summary_app_streaming" msgid="7380294597268573523">"<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>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
- <string name="title_computer" msgid="4693714143506569253">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ကို သင့်ဖုန်းမှ ဤအချက်အလက် သုံးခွင့်ပြုမည်"</string>
+ <string name="title_computer" msgid="4693714143506569253">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> အား သင့်ဖုန်းမှ ဤအချက်အလက် သုံးခွင့်ပြုခြင်း"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
<string name="permission_notification" msgid="693762568127741203">"အကြောင်းကြားချက်များ"</string>
<string name="permission_notification_summary" msgid="884075314530071011">"အဆက်အသွယ်၊ မက်ဆေ့ဂျ်နှင့် ဓာတ်ပုံကဲ့သို့ အချက်အလက်များအပါအဝင် အကြောင်းကြားချက်အားလုံးကို ဖတ်နိုင်သည်"</string>
@@ -44,4 +43,6 @@
<string name="consent_back" msgid="2560683030046918882">"နောက်သို့"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"အက်ပ်များကို <strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> တွင်ပေးထားသည့် ခွင့်ပြုချက်များအတိုင်း <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong> တွင် ပေးမလား။"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>၎င်းတွင် မိုက်ခရိုဖုန်း၊ ကင်မရာ၊ တည်နေရာ အသုံးပြုခွင့်အပြင် <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong>ပေါ်ရှိ အခြား သတိထားရမည့် ခွင့်ပြုချက်များ ပါဝင်နိုင်သည်။</p> <p>ဤခွင့်ပြုချက်များကို <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong>ပေါ်ရှိ သင်၏ဆက်တင်များတွင် အချိန်မရွေးပြောင်းနိုင်သည်။</p>"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"အက်ပ်သင်္ကေတ"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"နောက်ထပ်အချက်အလက်များ ခလုတ်"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-nb/strings.xml b/packages/CompanionDeviceManager/res/values-nb/strings.xml
index 9bbacb6..71afc20 100644
--- a/packages/CompanionDeviceManager/res/values-nb/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-nb/strings.xml
@@ -17,11 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Tillat at <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> administrerer <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
+ <!-- no translation found for confirmation_title (3785000297483688997) -->
+ <skip />
<string name="profile_name_watch" msgid="576290739483672360">"klokke"</string>
<string name="chooser_title" msgid="2262294130493605839">"Velg <xliff:g id="PROFILE_NAME">%1$s</xliff:g> som skal administreres av <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> får tillatelse til å samhandle med varslene dine og får tilgang til Telefon, SMS, kontakter og Kalender."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> får tillatelse til å samhandle med varslene dine og får tilgang til Telefon, SMS, kontakter og Kalender."</string>
+ <!-- no translation found for summary_watch (3002344206574997652) -->
+ <skip />
<string name="permission_apps" msgid="6142133265286656158">"Apper"</string>
<string name="permission_apps_summary" msgid="798718816711515431">"Strøm appene på telefonen"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Gi <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> tilgang til denne informasjonen fra telefonen din"</string>
@@ -44,4 +45,8 @@
<string name="consent_back" msgid="2560683030046918882">"Tilbake"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Vil du gi apper på <strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> de samme tillatelsene som på <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>Dette kan inkludere tilgang til mikrofon, kamera og posisjon samt andre sensitive tillatelser på <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong>.</p> <p>Du kan når som helst endre disse tillatelsene i innstillingene på <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong>.</p>"</string>
+ <!-- no translation found for vendor_icon_description (4445875290032225965) -->
+ <skip />
+ <!-- no translation found for vendor_header_button_description (6566660389500630608) -->
+ <skip />
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-ne/strings.xml b/packages/CompanionDeviceManager/res/values-ne/strings.xml
index cec076e..fa730bb 100644
--- a/packages/CompanionDeviceManager/res/values-ne/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ne/strings.xml
@@ -17,11 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"सहयोगी डिभाइसको प्रबन्धक"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"आफ्नो <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> लाई <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> व्यवस्थापन गर्ने अनुमति दिनुहोस्"</string>
+ <!-- no translation found for confirmation_title (3785000297483688997) -->
+ <skip />
<string name="profile_name_watch" msgid="576290739483672360">"घडी"</string>
<string name="chooser_title" msgid="2262294130493605839">"आफूले <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> प्रयोग गरी व्यवस्थापन गर्न चाहेको <xliff:g id="PROFILE_NAME">%1$s</xliff:g> चयन गर्नुहोस्"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> लाई तपाईंका सूचना हेर्ने र फोन, SMS, कन्ट्याक्ट तथा पात्रोसम्बन्धी अनुमतिहरू हेर्ने तथा प्रयोग गर्ने अनुमति दिइने छ।"</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> लाई तपाईंका सूचना हेर्ने र फोन, SMS, कन्ट्याक्ट तथा पात्रोसम्बन्धी अनुमतिहरू हेर्ने तथा प्रयोग गर्ने अनुमति दिइने छ।"</string>
+ <!-- no translation found for summary_watch (3002344206574997652) -->
+ <skip />
<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>
@@ -44,4 +45,6 @@
<string name="consent_back" msgid="2560683030046918882">"पछाडि"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"<strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> मा भएका एपहरूलाई पनि <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong> मा दिइएकै अनुमति दिने हो?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>यसअन्तर्गत <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong> का माइक्रोफोन, क्यामेरा र लोकेसन प्रयोग गर्ने अनुमतिका तथा अन्य संवेदनशील अनुमति समावेश हुन्छन्।</p> <p>तपाईं <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong> का सेटिङमा गई जुनसुकै बेला यी अनुमति परिवर्तन गर्न सक्नुहुन्छ।</p>"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"एपको आइकन"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"थप जानकारी देखाउने बटन"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-nl/strings.xml b/packages/CompanionDeviceManager/res/values-nl/strings.xml
index 1cd307a..a3b4cef 100644
--- a/packages/CompanionDeviceManager/res/values-nl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-nl/strings.xml
@@ -17,11 +17,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> toestaan je <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> te beheren"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> toegang geven tot je <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
<string name="profile_name_watch" msgid="576290739483672360">"horloge"</string>
<string name="chooser_title" msgid="2262294130493605839">"Een <xliff:g id="PROFILE_NAME">%1$s</xliff:g> kiezen om te beheren met <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> kan interactie hebben met je meldingen en toegang krijgen tot je rechten voor telefoon, sms, contacten en agenda."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> kan interactie hebben met je meldingen en toegang krijgen tot je rechten voor telefoon, sms, contacten en agenda."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"Deze app is vereist om je <xliff:g id="DEVICE_NAME">%1$s</xliff:g> te beheren. <xliff:g id="APP_NAME">%2$s</xliff:g> kan interactie hebben met je meldingen en toegang krijgen tot rechten voor Telefoon, Sms, Contacten, Agenda, Gesprekslijsten en Apparaten in de buurt."</string>
<string name="permission_apps" msgid="6142133265286656158">"Apps"</string>
<string name="permission_apps_summary" msgid="798718816711515431">"De apps van je telefoon streamen"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> toegang geven tot deze informatie op je telefoon"</string>
@@ -44,4 +43,6 @@
<string name="consent_back" msgid="2560683030046918882">"Terug"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Apps op <strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong&gt dezelfde rechten geven als op <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>Dit kan toegang tot de microfoon, camera en je locatie en andere gevoelige rechten op je <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong> omvatten.</p> <p>Je kunt deze rechten op elk moment wijzigen in je Instellingen op de <xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>.</p>"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"App-icoon"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Knop Meer informatie"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-or/strings.xml b/packages/CompanionDeviceManager/res/values-or/strings.xml
index e4b071c..b624a45 100644
--- a/packages/CompanionDeviceManager/res/values-or/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-or/strings.xml
@@ -17,11 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"ସହଯୋଗୀ ଡିଭାଇସ୍ ପରିଚାଳକ"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"ଆପଣଙ୍କ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>କୁ ପରିଚାଳନା କରିବା ପାଇଁ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>କୁ ଅନୁମତି ଦିଅନ୍ତୁ"</string>
+ <!-- no translation found for confirmation_title (3785000297483688997) -->
+ <skip />
<string name="profile_name_watch" msgid="576290739483672360">"ୱାଚ୍"</string>
<string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> ଦ୍ୱାରା ପରିଚାଳିତ ହେବା ପାଇଁ ଏକ <xliff:g id="PROFILE_NAME">%1$s</xliff:g>କୁ ବାଛନ୍ତୁ"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"ଆପଣଙ୍କ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ ସହ ଇଣ୍ଟରାକ୍ଟ କରିବା ଏବଂ ଆପଣଙ୍କ ଫୋନ, SMS, ଯୋଗାଯୋଗ ଓ କ୍ୟାଲେଣ୍ଡର ଅନୁମତିଗୁଡ଼ିକୁ ଆକ୍ସେସ କରିବା ପାଇଁ <xliff:g id="APP_NAME">%1$s</xliff:g>କୁ ଅନୁମତି ଦିଆଯିବ।"</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"ଆପଣଙ୍କ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ ସହ ଇଣ୍ଟରାକ୍ଟ କରିବା ଏବଂ ଆପଣଙ୍କ ଫୋନ, SMS, ଯୋଗାଯୋଗ ଓ କ୍ୟାଲେଣ୍ଡର ଅନୁମତିଗୁଡ଼ିକୁ ଆକ୍ସେସ କରିବା ପାଇଁ <xliff:g id="APP_NAME">%1$s</xliff:g>କୁ ଅନୁମତି ଦିଆଯିବ।"</string>
+ <!-- no translation found for summary_watch (3002344206574997652) -->
+ <skip />
<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>
@@ -44,4 +45,6 @@
<string name="consent_back" msgid="2560683030046918882">"ପଛକୁ ଫେରନ୍ତୁ"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"<strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong>ପରି <strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong>ରେ ଥିବା ଆପ୍ସକୁ ସମାନ ଅନୁମତିଗୁଡ଼ିକ ଦେବେ?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>ଏହା <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong>ରେ ମାଇକ୍ରୋଫୋନ, କ୍ୟାମେରା ଏବଂ ଲୋକେସନ ଆକ୍ସେସ ଓ ଅନ୍ୟ ସମ୍ବେଦନଶୀଳ ଅନୁମତିଗୁଡ଼ିକୁ ଅନ୍ତର୍ଭୁକ୍ତ କରିପାରେ।</p> <p>ଆପଣ <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong>ରେ ଯେ କୌଣସି ସମୟରେ ଆପଣଙ୍କ ସେଟିଂସରେ ଏହି ଅନୁମତିଗୁଡ଼ିକୁ ପରିବର୍ତ୍ତନ କରିପାରିବେ।</p>"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"ଆପ ଆଇକନ"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"ଅଧିକ ସୂଚନା ବଟନ"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-pa/strings.xml b/packages/CompanionDeviceManager/res/values-pa/strings.xml
index bffb7c3..9cac713 100644
--- a/packages/CompanionDeviceManager/res/values-pa/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pa/strings.xml
@@ -17,11 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"ਸੰਬੰਧੀ ਡੀਵਾਈਸ ਪ੍ਰਬੰਧਕ"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ਨੂੰ ਤੁਹਾਡੇ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ਦਾ ਪ੍ਰਬੰਧਨ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਦਿਓ"</string>
+ <!-- no translation found for confirmation_title (3785000297483688997) -->
+ <skip />
<string name="profile_name_watch" msgid="576290739483672360">"ਸਮਾਰਟ-ਵਾਚ"</string>
<string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> ਵੱਲੋਂ ਪ੍ਰਬੰਧਿਤ ਕੀਤੇ ਜਾਣ ਲਈ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ਚੁਣੋ"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਨੂੰ ਤੁਹਾਡੀਆਂ ਸੂਚਨਾਵਾਂ ਨਾਲ ਅੰਤਰਕਿਰਿਆ ਕਰਨ ਅਤੇ ਤੁਹਾਡੇ ਫ਼ੋਨ, SMS, ਸੰਪਰਕ ਅਤੇ ਕੈਲੰਡਰ ਦੀਆਂ ਇਜਾਜ਼ਤਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਹੋਵੇਗੀ।"</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਨੂੰ ਤੁਹਾਡੀਆਂ ਸੂਚਨਾਵਾਂ ਨਾਲ ਅੰਤਰਕਿਰਿਆ ਕਰਨ ਅਤੇ ਤੁਹਾਡੇ ਫ਼ੋਨ, SMS, ਸੰਪਰਕ ਅਤੇ ਕੈਲੰਡਰ ਦੀਆਂ ਇਜਾਜ਼ਤਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਹੋਵੇਗੀ।"</string>
+ <!-- no translation found for summary_watch (3002344206574997652) -->
+ <skip />
<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>
@@ -44,4 +45,8 @@
<string name="consent_back" msgid="2560683030046918882">"ਪਿੱਛੇ"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"ਕੀ <strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> \'ਤੇ ਮੌਜੂਦ ਐਪਾਂ ਨੂੰ <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong> \'ਤੇ ਮੌਜੂਦ ਐਪਾਂ ਵਾਂਗ ਇਜਾਜ਼ਤਾਂ ਦੇਣੀਆਂ ਹਨ?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>ਇਸ ਵਿੱਚ ਮਾਈਕ੍ਰੋਫ਼ੋਨ, ਕੈਮਰਾ, ਟਿਕਾਣਾ ਪਹੁੰਚ ਅਤੇ <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong> \'ਤੇ ਮੌਜੂਦ ਹੋਰ ਸੰਵੇਦਨਸ਼ੀਲ ਜਾਣਕਾਰੀ ਤੱਕ ਪਹੁੰਚ ਸੰਬੰਧੀ ਇਜਾਜ਼ਤਾਂ ਸ਼ਾਮਲ ਹੋ ਸਕਦੀਆਂ ਹਨ।</p> <p>ਤੁਸੀਂ <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong> \'ਤੇ ਮੌਜੂਦ ਆਪਣੀਆਂ ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਜਾ ਕੇ ਕਦੇ ਵੀ ਇਨ੍ਹਾਂ ਇਜਾਜ਼ਤਾਂ ਨੂੰ ਬਦਲ ਸਕਦੇ ਹੋ।</p>"</string>
+ <!-- no translation found for vendor_icon_description (4445875290032225965) -->
+ <skip />
+ <!-- no translation found for vendor_header_button_description (6566660389500630608) -->
+ <skip />
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-pl/strings.xml b/packages/CompanionDeviceManager/res/values-pl/strings.xml
index 704e402..a0aa8e1 100644
--- a/packages/CompanionDeviceManager/res/values-pl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pl/strings.xml
@@ -17,11 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Menedżer urządzeń towarzyszących"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Zezwól na zarządzanie urządzeniem <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> przez aplikację <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
+ <!-- no translation found for confirmation_title (3785000297483688997) -->
+ <skip />
<string name="profile_name_watch" msgid="576290739483672360">"zegarek"</string>
<string name="chooser_title" msgid="2262294130493605839">"Wybierz profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, którym ma zarządzać aplikacja <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> będzie mogła korzystać z powiadomień oraz uprawnień dotyczących Telefonu, SMS-ów, Kontaktów i Kalendarza."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> będzie mogła korzystać z powiadomień oraz uprawnień dotyczących Telefonu, SMS-ów, Kontaktów i Kalendarza."</string>
+ <!-- no translation found for summary_watch (3002344206574997652) -->
+ <skip />
<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>
@@ -44,4 +45,6 @@
<string name="consent_back" msgid="2560683030046918882">"Wstecz"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Czy aplikacjom na urządzeniu <strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> przyznać te same uprawnienia co na urządzeniu <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>Mogą one obejmować dane dostęp do Mikrofonu, Aparatu i lokalizacji oraz inne uprawnienia newralgiczne na urządzeniu <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong>.</p> <p>Możesz w dowolnym momencie zmienić uprawnienia na urządzeniu <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong>.</p>"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Ikona aplikacji"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Przycisk – więcej informacji"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml b/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml
index 6bd9bf9..3a33198 100644
--- a/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml
@@ -17,19 +17,20 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Gerenciador de dispositivos complementar"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Permitir que o app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> gerencie seu <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
+ <!-- no translation found for confirmation_title (3785000297483688997) -->
+ <skip />
<string name="profile_name_watch" msgid="576290739483672360">"relógio"</string>
<string name="chooser_title" msgid="2262294130493605839">"Escolha um <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para ser gerenciado pelo app <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> poderá interagir com suas notificações e acessar as permissões do Telefone, de SMS, de Contatos e da Agenda."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> poderá interagir com suas notificações e acessar as permissões do Telefone, de SMS, de Contatos e da Agenda."</string>
+ <!-- no translation found for summary_watch (3002344206574997652) -->
+ <skip />
<string name="permission_apps" msgid="6142133265286656158">"Apps"</string>
<string name="permission_apps_summary" msgid="798718816711515431">"Faça streaming dos apps do seu smartphone"</string>
- <string name="title_app_streaming" msgid="2270331024626446950">"Permitir que o app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acesse essas informações do smartphone"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Permitir que o app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acesse estas informações do smartphone"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Serviços entre dispositivos"</string>
<string name="helper_summary_app_streaming" msgid="7380294597268573523">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> está pedindo permissão em nome do seu <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> para acessar fotos, mídia e notificações do smartphone."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
- <string name="title_computer" msgid="4693714143506569253">"Autorizar que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acesse essas informações do smartphone"</string>
+ <string name="title_computer" msgid="4693714143506569253">"Autorizar que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acesse estas informações do smartphone"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
<string name="permission_notification" msgid="693762568127741203">"Notificações"</string>
<string name="permission_notification_summary" msgid="884075314530071011">"Pode ler todas as notificações, incluindo informações como contatos, mensagens e fotos"</string>
@@ -44,4 +45,6 @@
<string name="consent_back" msgid="2560683030046918882">"Voltar"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Dar aos apps no dispositivo <strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> as mesmas permissões do dispositivo <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>Isso pode incluir acesso a microfone, câmera e localização e outras permissões sensíveis no <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong>.</p> <p>Você pode mudar essas permissões a qualquer momento nas configurações do <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong>.</p>"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Ícone do app"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Botão \"Mais informações\""</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml b/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml
index 0b1ed8d..e988390 100644
--- a/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml
@@ -17,11 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Gestor de dispositivos associados"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Permita que a app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> faça a gestão do seu <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
+ <!-- no translation found for confirmation_title (3785000297483688997) -->
+ <skip />
<string name="profile_name_watch" msgid="576290739483672360">"relógio"</string>
<string name="chooser_title" msgid="2262294130493605839">"Escolha um <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para ser gerido pela app <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"A app <xliff:g id="APP_NAME">%1$s</xliff:g> poderá interagir com as suas notificações e aceder às autorizações do Telefone, SMS, Contactos e Calendário."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"A app <xliff:g id="APP_NAME">%1$s</xliff:g> poderá interagir com as suas notificações e aceder às autorizações do Telefone, SMS, Contactos e Calendário."</string>
+ <!-- no translation found for summary_watch (3002344206574997652) -->
+ <skip />
<string name="permission_apps" msgid="6142133265286656158">"Apps"</string>
<string name="permission_apps_summary" msgid="798718816711515431">"Faça stream das apps do telemóvel"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Permita que a app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> aceda a estas informações do seu telemóvel"</string>
@@ -44,4 +45,6 @@
<string name="consent_back" msgid="2560683030046918882">"Voltar"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Atribuir às apps no dispositivo <strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> as mesmas autorizações que no dispositivo <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>Isto pode incluir o acesso ao microfone, câmara e localização, bem como a outras autorizações confidenciais no dispositivo <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong>.</p> <p>Pode alterar estas autorizações em qualquer altura nas Definições do dispositivo <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong>.</p>"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Ícone da app"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Botão Mais informações"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-pt/strings.xml b/packages/CompanionDeviceManager/res/values-pt/strings.xml
index 6bd9bf9..3a33198 100644
--- a/packages/CompanionDeviceManager/res/values-pt/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pt/strings.xml
@@ -17,19 +17,20 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Gerenciador de dispositivos complementar"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Permitir que o app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> gerencie seu <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
+ <!-- no translation found for confirmation_title (3785000297483688997) -->
+ <skip />
<string name="profile_name_watch" msgid="576290739483672360">"relógio"</string>
<string name="chooser_title" msgid="2262294130493605839">"Escolha um <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para ser gerenciado pelo app <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> poderá interagir com suas notificações e acessar as permissões do Telefone, de SMS, de Contatos e da Agenda."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> poderá interagir com suas notificações e acessar as permissões do Telefone, de SMS, de Contatos e da Agenda."</string>
+ <!-- no translation found for summary_watch (3002344206574997652) -->
+ <skip />
<string name="permission_apps" msgid="6142133265286656158">"Apps"</string>
<string name="permission_apps_summary" msgid="798718816711515431">"Faça streaming dos apps do seu smartphone"</string>
- <string name="title_app_streaming" msgid="2270331024626446950">"Permitir que o app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acesse essas informações do smartphone"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Permitir que o app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acesse estas informações do smartphone"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Serviços entre dispositivos"</string>
<string name="helper_summary_app_streaming" msgid="7380294597268573523">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> está pedindo permissão em nome do seu <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> para acessar fotos, mídia e notificações do smartphone."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
- <string name="title_computer" msgid="4693714143506569253">"Autorizar que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acesse essas informações do smartphone"</string>
+ <string name="title_computer" msgid="4693714143506569253">"Autorizar que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acesse estas informações do smartphone"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
<string name="permission_notification" msgid="693762568127741203">"Notificações"</string>
<string name="permission_notification_summary" msgid="884075314530071011">"Pode ler todas as notificações, incluindo informações como contatos, mensagens e fotos"</string>
@@ -44,4 +45,6 @@
<string name="consent_back" msgid="2560683030046918882">"Voltar"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Dar aos apps no dispositivo <strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> as mesmas permissões do dispositivo <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>Isso pode incluir acesso a microfone, câmera e localização e outras permissões sensíveis no <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong>.</p> <p>Você pode mudar essas permissões a qualquer momento nas configurações do <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong>.</p>"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Ícone do app"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Botão \"Mais informações\""</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-ro/strings.xml b/packages/CompanionDeviceManager/res/values-ro/strings.xml
index 4227871..7eb8618 100644
--- a/packages/CompanionDeviceManager/res/values-ro/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ro/strings.xml
@@ -17,11 +17,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Manager de dispozitiv Companion"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Permiteți ca <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> să vă gestioneze dispozitivul <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"Permiteți ca <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> să vă acceseze dispozitivul <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ceas"</string>
<string name="chooser_title" msgid="2262294130493605839">"Alegeți un profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g> pe care să îl gestioneze <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> va putea să interacționeze cu notificările dvs. și să vă acceseze permisiunile pentru Telefon, SMS-uri, Agendă și Calendar."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> va putea să interacționeze cu notificările dvs. și să vă acceseze permisiunile pentru Telefon, SMS-uri, Agendă și Calendar."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"Această aplicație este necesară pentru a gestiona <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> va putea să interacționeze cu notificările dvs. și să vă acceseze permisiunile pentru Telefon, SMS, Agendă, Calendar, Jurnale de apeluri și Dispozitive din apropiere."</string>
<string name="permission_apps" msgid="6142133265286656158">"Aplicații"</string>
<string name="permission_apps_summary" msgid="798718816711515431">"Să redea în stream aplicațiile telefonului"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Permiteți ca <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> să acceseze aceste informații de pe telefon"</string>
@@ -44,4 +43,8 @@
<string name="consent_back" msgid="2560683030046918882">"Înapoi"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Oferiți aplicațiilor de pe <strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> aceleași permisiuni ca pe <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>Aici pot fi incluse accesul la microfon, la camera foto, la locație și alte permisiuni de accesare a informațiilor sensibile de pe <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong>.</p> <p>Puteți modifica oricând aceste permisiuni din Setările de pe <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong>.</p>"</string>
+ <!-- no translation found for vendor_icon_description (4445875290032225965) -->
+ <skip />
+ <!-- no translation found for vendor_header_button_description (6566660389500630608) -->
+ <skip />
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-ru/strings.xml b/packages/CompanionDeviceManager/res/values-ru/strings.xml
index bd50b08..e4bb646 100644
--- a/packages/CompanionDeviceManager/res/values-ru/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ru/strings.xml
@@ -17,11 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Управление подключенными устройствами"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Разрешите приложению <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> управлять этим устройством: <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
+ <!-- no translation found for confirmation_title (3785000297483688997) -->
+ <skip />
<string name="profile_name_watch" msgid="576290739483672360">"часы"</string>
<string name="chooser_title" msgid="2262294130493605839">"Выберите устройство (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>), которым будет управлять приложение <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"Приложению \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" будет предоставлен доступ к уведомлениям, а также следующие разрешения: телефон, SMS, контакты и календарь."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"Приложению \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" будет предоставлен доступ к уведомлениям, а также следующие разрешения: телефон, SMS, контакты и календарь."</string>
+ <!-- no translation found for summary_watch (3002344206574997652) -->
+ <skip />
<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>
@@ -44,4 +45,8 @@
<string name="consent_back" msgid="2560683030046918882">"Назад"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Предоставить приложениям на устройстве <strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> те же разрешения, что на устройстве <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>Сюда может входить доступ к микрофону, камере и данным о местоположении, а также другие разрешения на доступ к конфиденциальной информации на устройстве <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong>.</p> <p>Вы можете в любое время изменить разрешения в настройках устройства <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong>.</p>"</string>
+ <!-- no translation found for vendor_icon_description (4445875290032225965) -->
+ <skip />
+ <!-- no translation found for vendor_header_button_description (6566660389500630608) -->
+ <skip />
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-si/strings.xml b/packages/CompanionDeviceManager/res/values-si/strings.xml
index 440135b..df1bf08 100644
--- a/packages/CompanionDeviceManager/res/values-si/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-si/strings.xml
@@ -17,11 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"සහායක උපාංග කළමනාකරු"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> හට ඔබගේ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> කළමනාකරණය කිරීමට ඉඩ දෙන්න"</string>
+ <!-- no translation found for confirmation_title (3785000297483688997) -->
+ <skip />
<string name="profile_name_watch" msgid="576290739483672360">"ඔරලෝසුව"</string>
<string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> මගින් කළමනාකරණය කරනු ලැබීමට <xliff:g id="PROFILE_NAME">%1$s</xliff:g>ක් තෝරන්න"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ඔබගේ දැනුම්දීම් සමඟ අන්තර්ක්රියා කිරීමට සහ ඔබගේ දුරකථනය, කෙටි පණිවුඩ, සම්බන්ධතා සහ දින දර්ශන අවසර වෙත ප්රවේශ වීමට ඉඩ දෙනු ඇත."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ඔබගේ දැනුම්දීම් සමඟ අන්තර්ක්රියා කිරීමට සහ ඔබගේ දුරකථනය, කෙටි පණිවුඩ, සම්බන්ධතා සහ දින දර්ශන අවසර වෙත ප්රවේශ වීමට ඉඩ දෙනු ඇත."</string>
+ <!-- no translation found for summary_watch (3002344206574997652) -->
+ <skip />
<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>
@@ -44,4 +45,6 @@
<string name="consent_back" msgid="2560683030046918882">"ආපසු"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"<strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> the හි යෙදුම්වලට <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong> හි අවසරම දෙන්නද?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>මෙයට මයික්රෆෝනය, කැමරාව සහ ස්ථාන ප්රවේශය සහ <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong> හි අනෙකුත් සංවේදී අවසර ඇතුළත් විය හැකිය.</p> <p>ඔබට ඔබගේ සැකසීම් තුළ <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong> හිදී ඕනෑම වේලාවක මෙම අවසර වෙනස් කළ හැකිය.</p>"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"යෙදුම් නිරූපකය"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"වැඩිදුර තොරතුරු බොත්තම"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-sk/strings.xml b/packages/CompanionDeviceManager/res/values-sk/strings.xml
index 150b318..99c3bd7 100644
--- a/packages/CompanionDeviceManager/res/values-sk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sk/strings.xml
@@ -17,16 +17,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Správca sprievodných zariadení"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Povoliť aplikácii <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> spravovať zariadenie <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
+ <!-- no translation found for confirmation_title (3785000297483688997) -->
+ <skip />
<string name="profile_name_watch" msgid="576290739483672360">"hodinky"</string>
<string name="chooser_title" msgid="2262294130493605839">"Vyberte profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, ktorý bude spravovať aplikácia <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> bude môcť interagovať s vašimi upozorneniami a získavať prístup k povoleniam telefónu, SMS, kontaktov a kalendára."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> bude môcť interagovať s vašimi upozorneniami a získavať prístup k povoleniam telefónu, SMS, kontaktov a kalendára."</string>
+ <!-- no translation found for summary_watch (3002344206574997652) -->
+ <skip />
<string name="permission_apps" msgid="6142133265286656158">"Aplikácie"</string>
- <string name="permission_apps_summary" msgid="798718816711515431">"Streamujte aplikácie telefónu"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Streamovanie aplikácií v telefóne"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Povoľte aplikácii <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> prístup k týmto informáciám z vášho telefónu"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Služby pre viacero zariadení"</string>
- <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> vyžaduje povolenie na prístup k fotkám, médiám a upozorneniam vášho telefónu v mene tohto zariadenia (<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>)"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"Aplikácia <xliff:g id="APP_NAME">%1$s</xliff:g> vyžaduje povolenie na prístup k fotkám, médiám a upozorneniam vášho telefónu v mene tohto zariadenia (<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>)"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Povoľte aplikácii <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> prístup k týmto informáciám z vášho telefónu"</string>
@@ -44,4 +45,8 @@
<string name="consent_back" msgid="2560683030046918882">"Späť"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Chcete udeliť aplikáciám v zariadení <strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> rovnaké povolenia ako v zariadení <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>Môžu zahŕňať prístup k mikrofónu, kamere a polohe a ďalšie citlivé povolenia v zariadení <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong>.</p> <p>Tieto povolenia môžete kedykoľvek zmeniť v Nastaveniach v zariadení <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong>.</p>"</string>
+ <!-- no translation found for vendor_icon_description (4445875290032225965) -->
+ <skip />
+ <!-- no translation found for vendor_header_button_description (6566660389500630608) -->
+ <skip />
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-sl/strings.xml b/packages/CompanionDeviceManager/res/values-sl/strings.xml
index 49832fe..17c558c 100644
--- a/packages/CompanionDeviceManager/res/values-sl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sl/strings.xml
@@ -17,19 +17,20 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Upravitelj spremljevalnih naprav"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> dovolite upravljanje naprave <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
+ <!-- no translation found for confirmation_title (3785000297483688997) -->
+ <skip />
<string name="profile_name_watch" msgid="576290739483672360">"ura"</string>
<string name="chooser_title" msgid="2262294130493605839">"Izbira naprave <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, ki jo bo upravljala aplikacija <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"Aplikaciji <xliff:g id="APP_NAME">%1$s</xliff:g> bosta omogočena interakcija z obvestili in dostop do dovoljenj za telefon, sporočila SMS, stike in koledar."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"Aplikaciji <xliff:g id="APP_NAME">%1$s</xliff:g> bosta omogočena interakcija z obvestili in dostop do dovoljenj za telefon, sporočila SMS, stike in koledar."</string>
+ <!-- no translation found for summary_watch (3002344206574997652) -->
+ <skip />
<string name="permission_apps" msgid="6142133265286656158">"Aplikacije"</string>
<string name="permission_apps_summary" msgid="798718816711515431">"Pretočno predvajanje aplikacij telefona"</string>
- <string name="title_app_streaming" msgid="2270331024626446950">"Dovolite, da <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> dostopa do teh podatkov v vašem telefonu."</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Dovolite, da <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> dostopa do teh podatkov v vašem telefonu"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Storitve za zunanje naprave"</string>
<string name="helper_summary_app_streaming" msgid="7380294597268573523">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> v imenu naprave »<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>« zahteva dovoljenje za dostop do fotografij, predstavnosti in obvestil v telefonu."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
- <string name="title_computer" msgid="4693714143506569253">"Dovolite, da <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> dostopa do teh podatkov v vašem telefonu."</string>
+ <string name="title_computer" msgid="4693714143506569253">"Dovolite, da <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> dostopa do teh podatkov v vašem telefonu"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
<string name="permission_notification" msgid="693762568127741203">"Obvestila"</string>
<string name="permission_notification_summary" msgid="884075314530071011">"Lahko bere vsa obvestila, vključno s podatki, kot so stiki, sporočila in fotografije."</string>
@@ -44,4 +45,6 @@
<string name="consent_back" msgid="2560683030046918882">"Nazaj"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Ali želite aplikacijam v napravi <strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> odobriti enaka dovoljenja kot v napravi <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>To lahko vključuje dostop do mikrofona, fotoaparata in lokacije ter druga občutljiva dovoljenja v napravi <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong>.</p> <p>Ta dovoljenja lahko kadar koli spremenite v nastavitvah v napravi <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong>.</p>"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Ikona aplikacije"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Gumb za več informacij"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-sq/strings.xml b/packages/CompanionDeviceManager/res/values-sq/strings.xml
index e091807..0f5ba7a 100644
--- a/packages/CompanionDeviceManager/res/values-sq/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sq/strings.xml
@@ -17,16 +17,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Menaxheri i pajisjes shoqëruese"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Lejo që <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> të menaxhojë pajisjen tënde <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
+ <!-- no translation found for confirmation_title (3785000297483688997) -->
+ <skip />
<string name="profile_name_watch" msgid="576290739483672360">"ora inteligjente"</string>
<string name="chooser_title" msgid="2262294130493605839">"Zgjidh një profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g> që do të menaxhohet nga <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> do të lejohet të ndërveprojë me njoftimet e tua dhe të ketë qasje te lejet e \"Telefonit\", \"SMS-ve\", \"Kontakteve\" dhe \"Kalendarit\"."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> do të lejohet të ndërveprojë me njoftimet e tua dhe të ketë qasje te lejet e \"Telefonit\", \"SMS-ve\", \"Kontakteve\" dhe \"Kalendarit\"."</string>
+ <!-- no translation found for summary_watch (3002344206574997652) -->
+ <skip />
<string name="permission_apps" msgid="6142133265286656158">"Aplikacionet"</string>
<string name="permission_apps_summary" msgid="798718816711515431">"Transmeto aplikacionet e telefonit tënd"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Lejo që <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> të ketë qasje në këtë informacion nga telefoni yt"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Shërbimet mes pajisjeve"</string>
- <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> po kërkon leje në emër të <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> për të marrë qasje te fotografitë, media dhe njoftimet e telefonit tënd"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"\"<xliff:g id="APP_NAME">%1$s</xliff:g>\" po kërkon leje në emër të <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> për të marrë qasje te fotografitë, media dhe njoftimet e telefonit tënd"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Lejo që <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> të ketë qasje në këtë informacion nga telefoni yt"</string>
@@ -44,4 +45,6 @@
<string name="consent_back" msgid="2560683030046918882">"Pas"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"T\'i jepen aplikacioneve në <strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> të njëjtat leje si në <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>Kjo mund të përfshijë qasjen te \"Mikrofoni\", \"Kamera\", \"Vendndodhja\" dhe leje të tjera për informacione delikate në <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong>.</p> <p&gtTi mund t\'i ndryshosh këto leje në çdo kohë te \"Cilësimet\" në <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong>.</p>"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Ikona e aplikacionit"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Butoni \"Më shumë informacione\""</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-sr/strings.xml b/packages/CompanionDeviceManager/res/values-sr/strings.xml
index 8e50084..0168365 100644
--- a/packages/CompanionDeviceManager/res/values-sr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sr/strings.xml
@@ -17,16 +17,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Менаџер придруженог уређаја"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Дозволите апликацији <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> да управља уређајем <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
+ <!-- no translation found for confirmation_title (3785000297483688997) -->
+ <skip />
<string name="profile_name_watch" msgid="576290739483672360">"сат"</string>
<string name="chooser_title" msgid="2262294130493605839">"Одаберите профил <xliff:g id="PROFILE_NAME">%1$s</xliff:g> којим ће управљати апликација <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ће добити дозволу за интеракцију са обавештењима и приступ дозволама за телефон, SMS поруке, контакте и календар."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ће добити дозволу за интеракцију са обавештењима и приступ дозволама за телефон, SMS поруке, контакте и календар."</string>
+ <!-- no translation found for summary_watch (3002344206574997652) -->
+ <skip />
<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="helper_title_app_streaming" msgid="4151687003439969765">"Услуге на више уређаја"</string>
- <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> захтева дозволу у име уређаја <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> за приступ сликама, медијском садржају и обавештењима са телефона"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"Апликација <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>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Дозволите да <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> приступа овим информацијама са телефона"</string>
@@ -44,4 +45,6 @@
<string name="consent_back" msgid="2560683030046918882">"Назад"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Апликцијама на уређају <strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> дајте све дозволе као на уређају <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>То може да обухвата приступ микрофону, камери и локацији, као и другим осетљивим дозволама на уређају <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong>.</p> <p>У сваком тренутку можете да промените те дозволе у Подешавањима на уређају <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong>.</p>"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Икона апликације"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Дугме за више информација"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-sv/strings.xml b/packages/CompanionDeviceManager/res/values-sv/strings.xml
index 31f861d..aea3d4e 100644
--- a/packages/CompanionDeviceManager/res/values-sv/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sv/strings.xml
@@ -17,11 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Tillåt att <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> hanterar din <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
+ <!-- no translation found for confirmation_title (3785000297483688997) -->
+ <skip />
<string name="profile_name_watch" msgid="576290739483672360">"klocka"</string>
<string name="chooser_title" msgid="2262294130493605839">"Välj en <xliff:g id="PROFILE_NAME">%1$s</xliff:g> för hantering av <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> får behörighet att interagera med dina aviseringar och komma åt behörigheterna för Telefon, Sms, Kontakter och Kalender."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> får behörighet att interagera med dina aviseringar och komma åt behörigheterna för Telefon, Sms, Kontakter och Kalender."</string>
+ <!-- no translation found for summary_watch (3002344206574997652) -->
+ <skip />
<string name="permission_apps" msgid="6142133265286656158">"Appar"</string>
<string name="permission_apps_summary" msgid="798718816711515431">"Streama telefonens appar"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Ge <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> åtkomstbehörighet till denna information på telefonen"</string>
@@ -44,4 +45,8 @@
<string name="consent_back" msgid="2560683030046918882">"Tillbaka"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Vill du ge apparna på <strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> samma behörigheter som de har på <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>Det kan gälla behörighet till mikrofon, kamera och plats och åtkomstbehörighet till andra känsliga uppgifter på <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong>.</p> <p>Du kan när som helst ändra behörigheterna i inställningarna på <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong>.lt;/p>"</string>
+ <!-- no translation found for vendor_icon_description (4445875290032225965) -->
+ <skip />
+ <!-- no translation found for vendor_header_button_description (6566660389500630608) -->
+ <skip />
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-sw/strings.xml b/packages/CompanionDeviceManager/res/values-sw/strings.xml
index 8ae285f..835aec2 100644
--- a/packages/CompanionDeviceManager/res/values-sw/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sw/strings.xml
@@ -17,11 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Kidhibiti cha Vifaa Visaidizi"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Ruhusu <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> idhibiti <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> yako"</string>
+ <!-- no translation found for confirmation_title (3785000297483688997) -->
+ <skip />
<string name="profile_name_watch" msgid="576290739483672360">"saa"</string>
<string name="chooser_title" msgid="2262294130493605839">"Chagua <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ili idhibitiwe na <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> itaruhusiwa kufikia arifa zako na kufikia ruhusa za Simu, SMS, Anwani na Kalenda yako."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> itaruhusiwa kufikia arifa zako na kufikia ruhusa za Simu, SMS, Anwani na Kalenda yako."</string>
+ <!-- no translation found for summary_watch (3002344206574997652) -->
+ <skip />
<string name="permission_apps" msgid="6142133265286656158">"Programu"</string>
<string name="permission_apps_summary" msgid="798718816711515431">"Tiririsha programu za simu yako"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Ruhusu <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ifikie maelezo haya kutoka kwenye simu yako"</string>
@@ -44,4 +45,8 @@
<string name="consent_back" msgid="2560683030046918882">"Nyuma"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Zipatie programu katika <strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> ruhusa ile ile kama kwenye <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>Hii huenda ikajumuisha ufikiaji wa Maikrofoni, Kamera na Mahali, pamoja na ruhusa nyingine nyeti kwenye <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong>.</p> <p>Unaweza kubadilisha ruhusa hizi muda wowote katika Mipangilio yako kwenye <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong>.</p>"</string>
+ <!-- no translation found for vendor_icon_description (4445875290032225965) -->
+ <skip />
+ <!-- no translation found for vendor_header_button_description (6566660389500630608) -->
+ <skip />
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-ta/strings.xml b/packages/CompanionDeviceManager/res/values-ta/strings.xml
index 3e3daa9..2247321 100644
--- a/packages/CompanionDeviceManager/res/values-ta/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ta/strings.xml
@@ -17,11 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"கம்பேனியன் சாதன நிர்வாகி"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"உங்கள் <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ஐ நிர்வகிக்க <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ஆப்ஸை அனுமதியுங்கள்"</string>
+ <!-- no translation found for confirmation_title (3785000297483688997) -->
+ <skip />
<string name="profile_name_watch" msgid="576290739483672360">"வாட்ச்"</string>
<string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> ஆப்ஸ் நிர்வகிக்கக்கூடிய <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ஐத் தேர்ந்தெடுங்கள்"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"உங்கள் அறிவிப்புகளைப் பார்க்கவும் மொபைல், மெசேஜ், தொடர்புகள், கேலெண்டர் ஆகியவற்றை அணுகவும் <xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸுக்கு அனுமதி வழங்கப்படும்."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"உங்கள் அறிவிப்புகளைப் பார்க்கவும் மொபைல், மெசேஜ், தொடர்புகள், கேலெண்டர் ஆகியவற்றை அணுகவும் <xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸுக்கு அனுமதி வழங்கப்படும்."</string>
+ <!-- no translation found for summary_watch (3002344206574997652) -->
+ <skip />
<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>
@@ -44,4 +45,6 @@
<string name="consent_back" msgid="2560683030046918882">"பின்செல்"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"<strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong> சாதனத்தில் இருக்கும் அதே அனுமதிகளை <strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> சாதனத்தில் உள்ள ஆப்ஸுக்கும் வழங்கவா?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p><strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong>.</p> <p> சாதனத்தில் உள்ள மைக்ரோஃபோன், கேமரா, இருப்பிட அணுகல், பாதுகாக்கவேண்டிய பிற தகவல்கள் ஆகியவற்றுக்கான அனுமதிகள் இதிலடங்கும்.<strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong>.</p> சாதனத்தில் உள்ள அமைப்புகளில் இந்த அனுமதிகளை எப்போது வேண்டுமானாலும் நீங்கள் மாற்றிக்கொள்ளலாம்."</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"ஆப்ஸ் ஐகான்"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"கூடுதல் தகவல்கள் பட்டன்"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-te/strings.xml b/packages/CompanionDeviceManager/res/values-te/strings.xml
index 6ce530b..05a07cd 100644
--- a/packages/CompanionDeviceManager/res/values-te/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-te/strings.xml
@@ -17,15 +17,16 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"సహచర పరికర మేనేజర్"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"మీ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>ను మేనేజ్ చేయడానికి <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>ను అనుమతించండి;"</string>
+ <!-- no translation found for confirmation_title (3785000297483688997) -->
+ <skip />
<string name="profile_name_watch" msgid="576290739483672360">"వాచ్"</string>
<string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> ద్వారా మేనేజ్ చేయబడటానికి ఒక <xliff:g id="PROFILE_NAME">%1$s</xliff:g>ను ఎంచుకోండి"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"మీ నోటిఫికేషన్లతో ఇంటరాక్ట్ అవ్వడానికి ఇంకా మీ ఫోన్, SMS, కాంటాక్ట్లు, Calendar అనుమతులను యాక్సెస్ చేయడానికి <xliff:g id="APP_NAME">%1$s</xliff:g> అనుమతించబడుతుంది."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"మీ నోటిఫికేషన్లతో ఇంటరాక్ట్ అవ్వడానికి ఇంకా మీ ఫోన్, SMS, కాంటాక్ట్లు, Calendar అనుమతులను యాక్సెస్ చేయడానికి <xliff:g id="APP_NAME">%1$s</xliff:g> అనుమతించబడుతుంది."</string>
+ <!-- no translation found for summary_watch (3002344206574997652) -->
+ <skip />
<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="helper_title_app_streaming" msgid="4151687003439969765">"క్రాస్-డివైజ్ సర్వీసులు"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Cross-device services"</string>
<string name="helper_summary_app_streaming" msgid="7380294597268573523">"<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>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
@@ -44,4 +45,6 @@
<string name="consent_back" msgid="2560683030046918882">"వెనుకకు"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"<strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong>లోని యాప్లకు <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong>లో ఉన్న అనుమతులను ఇవ్వాలా?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p><strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong>లో మైక్రోఫోన్, కెమెరా, లొకేషన్ యాక్సెస్, ఇంకా ఇతర గోప్యమైన సమాచార యాక్సెస్ అనుమతులు ఇందులో ఉండవచ్చు.</p> <p>మీరు <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong>లో మీ సెట్టింగ్లలో ఎప్పుడైనా ఈ అనుమతులను మార్చవచ్చు.</p>"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"యాప్ చిహ్నం"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"మరింత సమాచారం బటన్"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-th/strings.xml b/packages/CompanionDeviceManager/res/values-th/strings.xml
index aa655a9..e9f21b3 100644
--- a/packages/CompanionDeviceManager/res/values-th/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-th/strings.xml
@@ -17,11 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"อนุญาตให้ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> จัดการ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ของคุณ"</string>
+ <!-- no translation found for confirmation_title (3785000297483688997) -->
+ <skip />
<string name="profile_name_watch" msgid="576290739483672360">"นาฬิกา"</string>
<string name="chooser_title" msgid="2262294130493605839">"เลือก<xliff:g id="PROFILE_NAME">%1$s</xliff:g>ที่จะให้มีการจัดการโดย <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> จะได้รับอนุญาตให้โต้ตอบกับการแจ้งเตือนและได้รับสิทธิ์เข้าถึงโทรศัพท์, SMS, รายชื่อติดต่อ และปฏิทิน"</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> จะได้รับอนุญาตให้โต้ตอบกับการแจ้งเตือนและได้รับสิทธิ์เข้าถึงโทรศัพท์, SMS, รายชื่อติดต่อ และปฏิทิน"</string>
+ <!-- no translation found for summary_watch (3002344206574997652) -->
+ <skip />
<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>
@@ -44,4 +45,6 @@
<string name="consent_back" msgid="2560683030046918882">"กลับ"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"ให้แอปใน <strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> มีสิทธิ์เหมือนกับใน <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong> ไหม"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>โดยอาจรวมถึงสิทธิ์เข้าถึงไมโครโฟน กล้อง และตำแหน่ง ตลอดจนสิทธิ์ที่มีความละเอียดอ่อนอื่นๆ ใน <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong>.</p> <p>คุณเปลี่ยนแปลงสิทธิ์เหล่านี้ได้ทุกเมื่อในการตั้งค่าใน <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong>.</p>"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"ไอคอนแอป"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"ปุ่มข้อมูลเพิ่มเติม"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-tl/strings.xml b/packages/CompanionDeviceManager/res/values-tl/strings.xml
index b9ce50b..06474ac 100644
--- a/packages/CompanionDeviceManager/res/values-tl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-tl/strings.xml
@@ -17,11 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Kasamang Device Manager"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Payagan ang <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> na pamahalaan ang iyong <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
+ <!-- no translation found for confirmation_title (3785000297483688997) -->
+ <skip />
<string name="profile_name_watch" msgid="576290739483672360">"relo"</string>
<string name="chooser_title" msgid="2262294130493605839">"Pumili ng <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para pamahalaan ng <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"Papayagan ang <xliff:g id="APP_NAME">%1$s</xliff:g> na makipag-ugnayan sa mga notification mo at ma-access ang iyong mga pahintulot sa Telepono, SMS, Mga Contact, at Kalendaryo."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"Papayagan ang <xliff:g id="APP_NAME">%1$s</xliff:g> na makipag-ugnayan sa mga notification mo at ma-access ang iyong mga pahintulot sa Telepono, SMS, Mga Contact, at Kalendaryo."</string>
+ <!-- no translation found for summary_watch (3002344206574997652) -->
+ <skip />
<string name="permission_apps" msgid="6142133265286656158">"Mga App"</string>
<string name="permission_apps_summary" msgid="798718816711515431">"I-stream ang mga app ng iyong telepono"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Payagan ang <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> na i-access ang impormasyong ito sa iyong telepono"</string>
@@ -44,4 +45,6 @@
<string name="consent_back" msgid="2560683030046918882">"Bumalik"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Bigyan ang mga app sa <strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> ng mga pahintulot na mayroon din sa <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>Posibleng kabilang dito ang access sa Mikropono, Camera, at Lokasyon, at iba pang pahintulot sa sensitibong impormasyon sa <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong>.</p> <p>Puwede mong baguhin ang mga pahintulot na ito anumang oras sa iyong Mga Setting sa <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong>.</p>"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Icon ng App"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Button ng Dagdag Impormasyon"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-tr/strings.xml b/packages/CompanionDeviceManager/res/values-tr/strings.xml
index 0528086..3cd0dbb 100644
--- a/packages/CompanionDeviceManager/res/values-tr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-tr/strings.xml
@@ -17,13 +17,14 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> uygulaması <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> cihazınızı yönetebilsin mi?"</string>
+ <!-- no translation found for confirmation_title (3785000297483688997) -->
+ <skip />
<string name="profile_name_watch" msgid="576290739483672360">"saat"</string>
<string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> tarafından yönetilecek bir <xliff:g id="PROFILE_NAME">%1$s</xliff:g> seçin"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> adlı uygulamanın bildirimlerinizle etkileşimde bulunup Telefon, SMS, Kişiler ve Takvim izinlerinize erişmesine izin verilir."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> adlı uygulamanın bildirimlerinizle etkileşimde bulunup Telefon, SMS, Kişiler ve Takvim izinlerinize erişmesine izin verilir."</string>
+ <!-- no translation found for summary_watch (3002344206574997652) -->
+ <skip />
<string name="permission_apps" msgid="6142133265286656158">"Uygulamalar"</string>
- <string name="permission_apps_summary" msgid="798718816711515431">"Telefonunuzun uygulamalarını akışla aktarın"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Telefonunuzun uygulamalarını yayınlama"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> uygulamasının, telefonunuzdaki bu bilgilere erişmesine izin verin"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Cihazlar arası hizmetler"</string>
<string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g>, telefonunuzdaki fotoğraf, medya ve bildirimlere erişmek için <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> cihazınız adına izin istiyor"</string>
@@ -44,4 +45,6 @@
<string name="consent_back" msgid="2560683030046918882">"Geri"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"<strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> cihazındaki uygulamalara, <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong> cihazındakiyle aynı izinler verilsin mi?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>Mikrofon, Kamera ve Konum erişiminin yanı sıra <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong> cihazındaki diğer hassas bilgilere erişim izinleri de bu kapsamda olabilir.</p> <p>Bu izinleri istediğiniz zaman <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong> cihazındaki Ayarlar bölümünden değiştirebilirsiniz.</p>"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Uygulama Simgesi"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Daha Fazla Bilgi Düğmesi"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-uk/strings.xml b/packages/CompanionDeviceManager/res/values-uk/strings.xml
index 220b1dc..ccbd8f2 100644
--- a/packages/CompanionDeviceManager/res/values-uk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-uk/strings.xml
@@ -17,11 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Диспетчер супутніх пристроїв"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Дозволити додатку <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> керувати вашим пристроєм <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
+ <!-- no translation found for confirmation_title (3785000297483688997) -->
+ <skip />
<string name="profile_name_watch" msgid="576290739483672360">"годинник"</string>
<string name="chooser_title" msgid="2262294130493605839">"Виберіть <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, яким керуватиме додаток <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"Додаток <xliff:g id="APP_NAME">%1$s</xliff:g> зможе взаємодіяти з вашими сповіщеннями та отримає дозволи \"Телефон\", \"SMS\", \"Контакти\" й \"Календар\"."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"Додаток <xliff:g id="APP_NAME">%1$s</xliff:g> зможе взаємодіяти з вашими сповіщеннями та отримає дозволи \"Телефон\", \"SMS\", \"Контакти\" й \"Календар\"."</string>
+ <!-- no translation found for summary_watch (3002344206574997652) -->
+ <skip />
<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>
@@ -29,7 +30,7 @@
<string name="helper_summary_app_streaming" msgid="7380294597268573523">"Додаток <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>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
- <string name="title_computer" msgid="4693714143506569253">"Надайте додатку <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> доступ до цієї інформації з телефона"</string>
+ <string name="title_computer" msgid="4693714143506569253">"Надайте пристрою <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> доступ до цієї інформації з телефона"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
<string name="permission_notification" msgid="693762568127741203">"Сповіщення"</string>
<string name="permission_notification_summary" msgid="884075314530071011">"Може читати всі сповіщення, зокрема таку інформацію, як контакти, повідомлення та фотографії"</string>
@@ -44,4 +45,8 @@
<string name="consent_back" msgid="2560683030046918882">"Назад"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Надати додаткам на пристрої <strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> такі самі дозволи, що й на пристрої <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>Це може бути доступ до мікрофона, камери та геоданих, а також до іншої конфіденційної інформації на пристрої <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong>.</p> <p>Ви можете будь-коли змінити ці дозволи в налаштуваннях на пристрої <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong>.</p>"</string>
+ <!-- no translation found for vendor_icon_description (4445875290032225965) -->
+ <skip />
+ <!-- no translation found for vendor_header_button_description (6566660389500630608) -->
+ <skip />
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-ur/strings.xml b/packages/CompanionDeviceManager/res/values-ur/strings.xml
index 5ca9fd06..ec77387 100644
--- a/packages/CompanionDeviceManager/res/values-ur/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ur/strings.xml
@@ -17,11 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"ساتھی آلہ مینیجر"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"اپنے <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> کا نظم کرنے کے لیے <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> کو اجازت دیں"</string>
+ <!-- no translation found for confirmation_title (3785000297483688997) -->
+ <skip />
<string name="profile_name_watch" msgid="576290739483672360">"دیکھیں"</string>
<string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> کے ذریعے نظم کئے جانے کیلئے <xliff:g id="PROFILE_NAME">%1$s</xliff:g> کو منتخب کریں"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> کو آپ کی اطلاعات کے ساتھ تعامل کرنے اور آپ کے فون، SMS، رابطوں اور کیلنڈر کی اجازتوں تک رسائی کی اجازت ہوگی۔"</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> کو آپ کی اطلاعات کے ساتھ تعامل کرنے اور آپ کے فون، SMS، رابطوں اور کیلنڈر کی اجازتوں تک رسائی کی اجازت ہوگی۔"</string>
+ <!-- no translation found for summary_watch (3002344206574997652) -->
+ <skip />
<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>
@@ -44,4 +45,8 @@
<string name="consent_back" msgid="2560683030046918882">"پیچھے"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"ایپس کو ;<strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong&gt پر اجازت دیں یکساں اجازتیں جو <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>;</strong&gt پر کے بطور ہیں؟"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>اس میں مائیکروفون، کیمرا اور مقام تک رسائی اور ;<strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong&gt پر دیگر حساس اجازتیں شامل ہو سکتی ہیں۔</p> <p>آپ <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>;</strong&gt پر کسی بھی وقت اپنی ترتیبات میں ان اجازتوں کو تبدیل کر سکتے ہیں۔</p>"</string>
+ <!-- no translation found for vendor_icon_description (4445875290032225965) -->
+ <skip />
+ <!-- no translation found for vendor_header_button_description (6566660389500630608) -->
+ <skip />
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-uz/strings.xml b/packages/CompanionDeviceManager/res/values-uz/strings.xml
index f2311fe..ac4f09b 100644
--- a/packages/CompanionDeviceManager/res/values-uz/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-uz/strings.xml
@@ -17,11 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> qurilmasini boshqarish uchun <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ilovasiga ruxsat bering"</string>
+ <!-- no translation found for confirmation_title (3785000297483688997) -->
+ <skip />
<string name="profile_name_watch" msgid="576290739483672360">"soat"</string>
<string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> boshqaradigan <xliff:g id="PROFILE_NAME">%1$s</xliff:g> qurilmasini tanlang"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ilovasiga bildirishnomalar bilan ishlash va telefon, SMS, kontaktlar va taqvimga kirishga ruxsat beriladi"</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ilovasiga bildirishnomalar bilan ishlash va telefon, SMS, kontaktlar va taqvimga kirishga ruxsat beriladi"</string>
+ <!-- no translation found for summary_watch (3002344206574997652) -->
+ <skip />
<string name="permission_apps" msgid="6142133265286656158">"Ilovalar"</string>
<string name="permission_apps_summary" msgid="798718816711515431">"Telefondagi ilovalarni translatsiya qilish"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ilovasiga telefondagi ushbu maʼlumot uchun ruxsat bering"</string>
@@ -44,4 +45,8 @@
<string name="consent_back" msgid="2560683030046918882">"Orqaga"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"<strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> ilovalariga <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong> qurilmasidagi kabi bir xil ruxsatlar berilsinmi?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>Bunga <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong> qurilmasidagi Mikrofon, Kamera, Joylashuv kabi muhim ruxsatlar kirishi mumkin.</p> <p>Bu ruxsatlarni istalgan vaqt <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong> Sozlamalari orqali oʻzgartirish mumkin.</p>"</string>
+ <!-- no translation found for vendor_icon_description (4445875290032225965) -->
+ <skip />
+ <!-- no translation found for vendor_header_button_description (6566660389500630608) -->
+ <skip />
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-vi/strings.xml b/packages/CompanionDeviceManager/res/values-vi/strings.xml
index 4ccb9d5..ff77a77 100644
--- a/packages/CompanionDeviceManager/res/values-vi/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-vi/strings.xml
@@ -17,11 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Cho phép <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> quản lý <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> của bạn"</string>
+ <!-- no translation found for confirmation_title (3785000297483688997) -->
+ <skip />
<string name="profile_name_watch" msgid="576290739483672360">"đồng hồ"</string>
<string name="chooser_title" msgid="2262294130493605839">"Chọn một <xliff:g id="PROFILE_NAME">%1$s</xliff:g> sẽ do <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> quản lý"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> sẽ được phép tương tác với thông báo cũng như truy cập vào Điện thoại, SMS, Danh bạ và Lịch."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> sẽ được phép tương tác với thông báo cũng như truy cập vào Điện thoại, SMS, Danh bạ và Lịch."</string>
+ <!-- no translation found for summary_watch (3002344206574997652) -->
+ <skip />
<string name="permission_apps" msgid="6142133265286656158">"Ứng dụng"</string>
<string name="permission_apps_summary" msgid="798718816711515431">"Truyền các ứng dụng trên điện thoại của bạn"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Cho phép <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> truy cập vào thông tin này trên điện thoại của bạn"</string>
@@ -44,4 +45,6 @@
<string name="consent_back" msgid="2560683030046918882">"Quay lại"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Cấp cho các ứng dụng trên <strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> các quyền giống như trên <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>Những quyền này có thể bao gồm quyền truy cập vào micrô, máy ảnh và thông tin vị trí, cũng như các quyền truy cập thông tin nhạy cảm khác trên <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong>.</p> <p>Bạn có thể thay đổi những quyền này bất cứ lúc nào trong phần Cài đặt trên <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong>.</p>"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Biểu tượng ứng dụng"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Nút thông tin khác"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml
index 7697c2f..06a8b3e 100644
--- a/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml
@@ -17,13 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"配套设备管理器"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"允许<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>管理您的<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"允许<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>访问您的<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
<string name="profile_name_watch" msgid="576290739483672360">"手表"</string>
<string name="chooser_title" msgid="2262294130493605839">"选择要由<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>管理的<xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"“<xliff:g id="APP_NAME">%1$s</xliff:g>”将能与通知互动,并可访问电话、短信、通讯录和日历。"</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"“<xliff:g id="APP_NAME">%1$s</xliff:g>”将能与通知互动,并可访问电话、短信、通讯录和日历。"</string>
+ <string name="summary_watch" msgid="3002344206574997652">"需要使用此应用,才能管理您的“<xliff:g id="DEVICE_NAME">%1$s</xliff:g>”。“<xliff:g id="APP_NAME">%2$s</xliff:g>”将能与通知互动,并可获得电话、短信、通讯录、日历、通话记录和附近的设备访问权限。"</string>
<string name="permission_apps" msgid="6142133265286656158">"应用"</string>
- <string name="permission_apps_summary" msgid="798718816711515431">"流式传输手机的应用内容"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"流式传输手机上的应用"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"允许“<xliff:g id="APP_NAME">%1$s</xliff:g>”<strong></strong>访问您手机中的这项信息"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"跨设备服务"</string>
<string name="helper_summary_app_streaming" msgid="7380294597268573523">"“<xliff:g id="APP_NAME">%1$s</xliff:g>”正代表您的<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>请求访问您手机上的照片、媒体内容和通知"</string>
@@ -44,4 +43,6 @@
<string name="consent_back" msgid="2560683030046918882">"返回"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"要授予<strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong>上的应用与<strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong>上相同的权限吗?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>这可能包括<strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong>的麦克风、摄像头和位置信息访问权限,以及其他敏感权限。</p> <p>您可以随时在<strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong>的“设置”中更改这些权限。</p>"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"应用图标"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"更多信息按钮"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml
index b8b8850..592b12e 100644
--- a/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml
@@ -17,11 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"隨附裝置管理工具"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"允許 <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> 管理您的<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
+ <!-- no translation found for confirmation_title (3785000297483688997) -->
+ <skip />
<string name="profile_name_watch" msgid="576290739483672360">"手錶"</string>
<string name="chooser_title" msgid="2262294130493605839">"選擇由 <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> 管理的<xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」將可存取通知、電話、短訊、聯絡人和日曆資料。"</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」將可存取通知、電話、短訊、聯絡人和日曆資料。"</string>
+ <!-- no translation found for summary_watch (3002344206574997652) -->
+ <skip />
<string name="permission_apps" msgid="6142133265286656158">"應用程式"</string>
<string name="permission_apps_summary" msgid="798718816711515431">"串流播放手機應用程式內容"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」<strong></strong>存取您手機中的這項資料"</string>
@@ -44,4 +45,6 @@
<string name="consent_back" msgid="2560683030046918882">"返回"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"要讓 <strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> 的應用程式沿用在 <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong> 上的權限嗎?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>這可能包括 <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong>.</p> <p> 的麥克風、相機和位置存取權和其他敏感資料權限。您隨時可透過 <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong>.</p> 變更這些權限。"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"應用程式圖示"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"「更多資料」按鈕"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml
index 52cc3ee..5097ed0 100644
--- a/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml
@@ -17,11 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"隨附裝置管理員"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」<strong></strong>管理你的「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」<strong></strong>"</string>
+ <!-- no translation found for confirmation_title (3785000297483688997) -->
+ <skip />
<string name="profile_name_watch" msgid="576290739483672360">"手錶"</string>
<string name="chooser_title" msgid="2262294130493605839">"選擇要讓「<xliff:g id="APP_NAME">%2$s</xliff:g>」<strong></strong>管理的<xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」將可存取通知、電話、簡訊、聯絡人和日曆資料。"</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」將可存取通知、電話、簡訊、聯絡人和日曆資料。"</string>
+ <!-- no translation found for summary_watch (3002344206574997652) -->
+ <skip />
<string name="permission_apps" msgid="6142133265286656158">"應用程式"</string>
<string name="permission_apps_summary" msgid="798718816711515431">"串流傳輸手機應用程式內容"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」<strong></strong>存取手機中的這項資訊"</string>
@@ -44,4 +45,6 @@
<string name="consent_back" msgid="2560683030046918882">"返回"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"要讓「<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>」<strong></strong>的應用程式沿用在「<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>」<strong></strong>上的權限嗎?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>這可能包括「<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>」<strong></strong>.</p>的麥克風、相機和位置資訊存取權和其他機密權限。</p> <p>你隨時可透過「<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>」<strong></strong>的設定變更這些權限。</p>"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"應用程式圖示"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"更多資訊按鈕"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-zu/strings.xml b/packages/CompanionDeviceManager/res/values-zu/strings.xml
index d677911..c669736 100644
--- a/packages/CompanionDeviceManager/res/values-zu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zu/strings.xml
@@ -17,11 +17,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Isiphathi sedivayisi esihambisanayo"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Vumela i-<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ukuthi iphathe i-<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> yakho"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"Vumela i-<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ukuthi ifinyelele i-<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> yakho"</string>
<string name="profile_name_watch" msgid="576290739483672360">"buka"</string>
<string name="chooser_title" msgid="2262294130493605839">"Khetha i-<xliff:g id="PROFILE_NAME">%1$s</xliff:g> ezophathwa yi-<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> izovunyelwa ukuxhumana nezaziso zakho futhi ifinyelele izimvume Zefoni yakho, -SMS, Abathintwayo kanye Nekhalenda."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> izovunyelwa ukuxhumana nezaziso zakho futhi ifinyelele izimvume Zefoni yakho, -SMS, Abathintwayo kanye Nekhalenda."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"I-app iyadingeka ukuphatha i-<xliff:g id="DEVICE_NAME">%1$s</xliff:g> yakho. I-<xliff:g id="APP_NAME">%2$s</xliff:g> izovunyelwa ukuthi ihlanganyele nezaziso zakho futhi ifinyelele Ifoni yakho, i-SMS, Oxhumana nabo, Ikhalenda, Amarekhodi wamakholi Nezimvume zamadivayisi aseduze."</string>
<string name="permission_apps" msgid="6142133265286656158">"Ama-app"</string>
<string name="permission_apps_summary" msgid="798718816711515431">"Sakaza ama-app wefoni yakho"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Vumela i-<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ifinyelele lolu lwazi kusukela efonini yakho"</string>
@@ -44,4 +43,6 @@
<string name="consent_back" msgid="2560683030046918882">"Emuva"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Nikeza ama-app <strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> izimvume ezifanayot <strong>njengaku-<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="permission_sync_summary" msgid="4866838188678457084">"<p>Lokhu kungase kuhlanganisa Imakrofoni, Ikhamera, kanye Nokufinyelela kwendawo, kanye nezinye izimvume ezibucayi <strong>ku-<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong>.</p> <p>Ungashintsha lezi zimvume nganoma yisiphi isikhathi Kumasethingi akho <strong>ku-<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong>.</p>"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Isithonjana Se-app"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Inkinobho Yolwazi Olwengeziwe"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values/strings.xml b/packages/CompanionDeviceManager/res/values/strings.xml
index 572abd4..cea9a68 100644
--- a/packages/CompanionDeviceManager/res/values/strings.xml
+++ b/packages/CompanionDeviceManager/res/values/strings.xml
@@ -20,7 +20,7 @@
<string name="app_label">Companion Device Manager</string>
<!-- Title of the device association confirmation dialog. -->
- <string name="confirmation_title">Allow <strong><xliff:g id="app_name" example="Android Wear">%1$s</xliff:g></strong> to manage your <strong><xliff:g id="device_name" example="ASUS ZenWatch 2">%2$s</xliff:g></strong></string>
+ <string name="confirmation_title">Allow <strong><xliff:g id="app_name" example="Android Wear">%1$s</xliff:g></strong> to access your <strong><xliff:g id="device_name" example="ASUS ZenWatch 2">%2$s</xliff:g></strong></string>
<!-- ================= DEVICE_PROFILE_WATCH and null profile ================= -->
@@ -31,10 +31,7 @@
<string name="chooser_title">Choose a <xliff:g id="profile_name" example="watch">%1$s</xliff:g> to be managed by <strong><xliff:g id="app_name" example="Android Wear">%2$s</xliff:g></strong></string>
<!-- Description of the privileges the application will get if associated with the companion device of WATCH profile (type) [CHAR LIMIT=NONE] -->
- <string name="summary_watch" product="default"><xliff:g id="app_name" example="Wear">%1$s</xliff:g> will be allowed to interact with your notifications and access your Phone, SMS, Contacts and Calendar permissions.</string>
-
- <!-- Description of the privileges the application will get if associated with the companion device of WATCH profile (type) [CHAR LIMIT=NONE] -->
- <string name="summary_watch" product="tablet"><xliff:g id="app_name" example="Wear">%1$s</xliff:g> will be allowed to interact with your notifications and access your Phone, SMS, Contacts and Calendar permissions.</string>
+ <string name="summary_watch">This app is needed to manage your <xliff:g id="device_name" example="My Watch">%1$s</xliff:g>. <xliff:g id="app_name" example="Android Wear">%2$s</xliff:g> will be allowed to interact with your notifications and access your Phone, SMS, Contacts, Calendar, Call logs and Nearby devices permissions.</string>
<!-- ================= DEVICE_PROFILE_APP_STREAMING ================= -->
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
index d1f088f..10d46d6 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
@@ -498,18 +498,19 @@
}
final String deviceName = mSelectedDevice.getDisplayName();
- mRequest.setDisplayName(deviceName);
- final Spanned title = getHtmlFromResources(
- this, R.string.confirmation_title, appLabel, deviceName);
+ final String profileName = getString(R.string.profile_name_watch);
+ final Spanned title;
final Spanned summary;
final Drawable profileIcon;
if (deviceProfile == null) {
+ title = getHtmlFromResources(this, R.string.confirmation_title, appLabel, deviceName);
summary = getHtmlFromResources(this, R.string.summary_generic);
profileIcon = getIcon(this, R.drawable.ic_device_other);
mSummary.setVisibility(View.GONE);
} else if (deviceProfile.equals(DEVICE_PROFILE_WATCH)) {
- summary = getHtmlFromResources(this, R.string.summary_watch, appLabel, deviceName);
+ title = getHtmlFromResources(this, R.string.confirmation_title, appLabel, profileName);
+ summary = getHtmlFromResources(this, R.string.summary_watch, deviceName, appLabel);
profileIcon = getIcon(this, R.drawable.ic_watch);
} else {
throw new RuntimeException("Unsupported profile " + deviceProfile);
@@ -537,7 +538,7 @@
mSummary.setVisibility(View.GONE);
} else if (deviceProfile.equals(DEVICE_PROFILE_WATCH)) {
profileName = getString(R.string.profile_name_watch);
- summary = getHtmlFromResources(this, R.string.summary_watch, appLabel);
+ summary = getHtmlFromResources(this, R.string.summary_watch, profileName, appLabel);
profileIcon = getIcon(this, R.drawable.ic_watch);
} else {
throw new RuntimeException("Unsupported profile " + deviceProfile);
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java
index f333b86..fc5ff08 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java
@@ -123,6 +123,7 @@
intent.setAction(ACTION_START_DISCOVERY);
intent.putExtra(EXTRA_ASSOCIATION_REQUEST, associationRequest);
sStateLiveData.setValue(DiscoveryState.STARTING);
+ sScanResultsLiveData.setValue(Collections.emptyList());
context.startService(intent);
}
@@ -173,7 +174,6 @@
@Override
public void onDestroy() {
- sScanResultsLiveData.setValue(Collections.emptyList());
super.onDestroy();
if (DEBUG) Log.d(TAG, "onDestroy()");
}
@@ -187,7 +187,6 @@
mStopAfterFirstMatch = request.isSingleDevice();
mDiscoveryStarted = true;
sStateLiveData.setValue(DiscoveryState.DISCOVERY_IN_PROGRESS);
- sScanResultsLiveData.setValue(Collections.emptyList());
final List<DeviceFilter<?>> allFilters = request.getDeviceFilters();
final List<BluetoothDeviceFilter> btFilters =
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceFilterPair.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceFilterPair.java
index faca1ae..1f59d30 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceFilterPair.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceFilterPair.java
@@ -47,7 +47,7 @@
}
String getDisplayName() {
- if (mFilter != null) mFilter.getDeviceDisplayName(mDevice);
+ if (mFilter != null) return mFilter.getDeviceDisplayName(mDevice);
if (mDevice instanceof BluetoothDevice) {
return getDeviceDisplayNameInternal((BluetoothDevice) mDevice);
diff --git a/packages/CtsShim/apk/arm/CtsShim.apk b/packages/CtsShim/apk/arm/CtsShim.apk
index 0c3c4bb..fb09286 100644
--- a/packages/CtsShim/apk/arm/CtsShim.apk
+++ b/packages/CtsShim/apk/arm/CtsShim.apk
Binary files differ
diff --git a/packages/CtsShim/apk/arm/CtsShimPriv.apk b/packages/CtsShim/apk/arm/CtsShimPriv.apk
index ee42d08..07915ce 100644
--- a/packages/CtsShim/apk/arm/CtsShimPriv.apk
+++ b/packages/CtsShim/apk/arm/CtsShimPriv.apk
Binary files differ
diff --git a/packages/CtsShim/apk/x86/CtsShim.apk b/packages/CtsShim/apk/x86/CtsShim.apk
index 0c3c4bb..fb09286 100644
--- a/packages/CtsShim/apk/x86/CtsShim.apk
+++ b/packages/CtsShim/apk/x86/CtsShim.apk
Binary files differ
diff --git a/packages/CtsShim/apk/x86/CtsShimPriv.apk b/packages/CtsShim/apk/x86/CtsShimPriv.apk
index 2bb3750..20e94b6 100644
--- a/packages/CtsShim/apk/x86/CtsShimPriv.apk
+++ b/packages/CtsShim/apk/x86/CtsShimPriv.apk
Binary files differ
diff --git a/packages/CtsShim/build/Android.bp b/packages/CtsShim/build/Android.bp
index 7cf5385..af3e210 100644
--- a/packages/CtsShim/build/Android.bp
+++ b/packages/CtsShim/build/Android.bp
@@ -47,6 +47,7 @@
uses_libs: ["android.test.runner"],
apex_available: [
+ "//apex_available:platform",
"com.android.apex.cts.shim.v2_apk_in_apex_upgrades",
],
}
diff --git a/packages/SettingsLib/ActionBarShadow/Android.bp b/packages/SettingsLib/ActionBarShadow/Android.bp
index 4a07d49..2c86201 100644
--- a/packages/SettingsLib/ActionBarShadow/Android.bp
+++ b/packages/SettingsLib/ActionBarShadow/Android.bp
@@ -20,4 +20,8 @@
sdk_version: "system_current",
min_sdk_version: "28",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.permission",
+ ],
}
diff --git a/packages/SettingsLib/AndroidManifest.xml b/packages/SettingsLib/AndroidManifest.xml
index 3e67abf..13f8a37 100644
--- a/packages/SettingsLib/AndroidManifest.xml
+++ b/packages/SettingsLib/AndroidManifest.xml
@@ -22,16 +22,6 @@
<activity
android:name="com.android.settingslib.users.AvatarPickerActivity"
android:theme="@style/SudThemeGlifV2.DayNight"/>
-
- <activity
- android:name="com.android.settingslib.qrcode.QrCodeScanModeActivity"
- android:exported="true">
- <intent-filter>
- <action android:name="android.settings.BLUETOOTH_LE_AUDIO_QR_CODE_SCANNER"/>
- <category android:name="android.intent.category.DEFAULT"/>
- </intent-filter>
- </activity>
-
</application>
</manifest>
diff --git a/packages/SettingsLib/AppPreference/Android.bp b/packages/SettingsLib/AppPreference/Android.bp
index 1817a77..122f606 100644
--- a/packages/SettingsLib/AppPreference/Android.bp
+++ b/packages/SettingsLib/AppPreference/Android.bp
@@ -20,4 +20,8 @@
],
sdk_version: "system_current",
min_sdk_version: "21",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.permission",
+ ],
}
diff --git a/packages/SettingsLib/AppPreference/res/layout/preference_app_header.xml b/packages/SettingsLib/AppPreference/res/layout/preference_app_header.xml
new file mode 100644
index 0000000..e0d01f9
--- /dev/null
+++ b/packages/SettingsLib/AppPreference/res/layout/preference_app_header.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.
+ -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+ android:paddingBottom="16dp"
+ android:paddingTop="8dp"
+ android:clickable="false">
+
+ <TextView
+ android:id="@+id/apps_top_intro_text"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textDirection="locale"
+ android:clickable="false"
+ android:longClickable="false"
+ android:textAppearance="@style/TextAppearance.TopIntroText" />
+
+</LinearLayout>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-gl/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-gl/strings.xml
index d787626..816cbf6 100644
--- a/packages/SettingsLib/BannerMessagePreference/res/values-gl/strings.xml
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-gl/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"Ignorar"</string>
+ <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"Pechar"</string>
</resources>
diff --git a/packages/SettingsLib/BarChartPreference/Android.bp b/packages/SettingsLib/BarChartPreference/Android.bp
index 4f65373..5c5da98 100644
--- a/packages/SettingsLib/BarChartPreference/Android.bp
+++ b/packages/SettingsLib/BarChartPreference/Android.bp
@@ -19,4 +19,8 @@
sdk_version: "system_current",
min_sdk_version: "21",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.permission",
+ ],
}
diff --git a/packages/SettingsLib/HelpUtils/Android.bp b/packages/SettingsLib/HelpUtils/Android.bp
index 5826047..aea51b1 100644
--- a/packages/SettingsLib/HelpUtils/Android.bp
+++ b/packages/SettingsLib/HelpUtils/Android.bp
@@ -19,4 +19,8 @@
sdk_version: "system_current",
min_sdk_version: "21",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.permission",
+ ],
}
diff --git a/packages/SettingsLib/LayoutPreference/Android.bp b/packages/SettingsLib/LayoutPreference/Android.bp
index 8a4e53d..aaffdc9 100644
--- a/packages/SettingsLib/LayoutPreference/Android.bp
+++ b/packages/SettingsLib/LayoutPreference/Android.bp
@@ -14,9 +14,13 @@
resource_dirs: ["res"],
static_libs: [
- "androidx.preference_preference",
+ "androidx.preference_preference",
],
sdk_version: "system_current",
min_sdk_version: "21",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.permission",
+ ],
}
diff --git a/packages/SettingsLib/ProgressBar/Android.bp b/packages/SettingsLib/ProgressBar/Android.bp
index b5bc8f7..fb3c4e6 100644
--- a/packages/SettingsLib/ProgressBar/Android.bp
+++ b/packages/SettingsLib/ProgressBar/Android.bp
@@ -15,4 +15,8 @@
sdk_version: "system_current",
min_sdk_version: "21",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.permission",
+ ],
}
diff --git a/packages/SettingsLib/RestrictedLockUtils/Android.bp b/packages/SettingsLib/RestrictedLockUtils/Android.bp
index ef548b5..6a8fef3 100644
--- a/packages/SettingsLib/RestrictedLockUtils/Android.bp
+++ b/packages/SettingsLib/RestrictedLockUtils/Android.bp
@@ -25,4 +25,8 @@
sdk_version: "system_current",
min_sdk_version: "21",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.permission",
+ ],
}
diff --git a/packages/SettingsLib/SearchWidget/Android.bp b/packages/SettingsLib/SearchWidget/Android.bp
index b7367b4..5aaee2a 100644
--- a/packages/SettingsLib/SearchWidget/Android.bp
+++ b/packages/SettingsLib/SearchWidget/Android.bp
@@ -14,4 +14,8 @@
resource_dirs: ["res"],
sdk_version: "system_current",
min_sdk_version: "21",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.permission",
+ ],
}
diff --git a/packages/SettingsLib/SettingsTheme/Android.bp b/packages/SettingsLib/SettingsTheme/Android.bp
index 73459c2..da01f62 100644
--- a/packages/SettingsLib/SettingsTheme/Android.bp
+++ b/packages/SettingsLib/SettingsTheme/Android.bp
@@ -13,13 +13,14 @@
resource_dirs: ["res"],
static_libs: [
- "androidx.preference_preference",
- ],
+ "androidx.preference_preference",
+ ],
sdk_version: "system_current",
min_sdk_version: "21",
apex_available: [
"//apex_available:platform",
"com.android.cellbroadcast",
+ "com.android.permission",
],
}
diff --git a/packages/SettingsLib/SettingsTheme/res/values/styles.xml b/packages/SettingsLib/SettingsTheme/res/values/styles.xml
index aaab0f0..00bd141 100644
--- a/packages/SettingsLib/SettingsTheme/res/values/styles.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values/styles.xml
@@ -26,4 +26,11 @@
<style name="TextAppearance.CategoryTitle.SettingsLib"
parent="@android:style/TextAppearance.DeviceDefault.Medium">
</style>
+
+ <style name="TextAppearance.TopIntroText"
+ parent="@android:style/TextAppearance.DeviceDefault">
+ <item name="android:textSize">14sp</item>
+ <item name="android:textColor">?android:attr/textColorSecondary</item>
+ </style>
+
</resources>
diff --git a/packages/SettingsLib/TopIntroPreference/Android.bp b/packages/SettingsLib/TopIntroPreference/Android.bp
index cd0bdea..ecf2a72 100644
--- a/packages/SettingsLib/TopIntroPreference/Android.bp
+++ b/packages/SettingsLib/TopIntroPreference/Android.bp
@@ -16,6 +16,7 @@
static_libs: [
"androidx.annotation_annotation",
"androidx.preference_preference",
+ "SettingsLibSettingsTheme",
],
sdk_version: "system_current",
min_sdk_version: "21",
diff --git a/packages/SettingsLib/TopIntroPreference/res/values/styles.xml b/packages/SettingsLib/TopIntroPreference/res/values/styles.xml
deleted file mode 100644
index b6ca41f..0000000
--- a/packages/SettingsLib/TopIntroPreference/res/values/styles.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2021 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-<resources>
- <style name="TextAppearance.TopIntroText"
- parent="@android:style/TextAppearance.DeviceDefault">
- <item name="android:textSize">14sp</item>
- <item name="android:textColor">?android:attr/textColorSecondary</item>
- </style>
-</resources>
diff --git a/packages/SettingsLib/Utils/src/com/android/settingslib/utils/WorkPolicyUtils.java b/packages/SettingsLib/Utils/src/com/android/settingslib/utils/WorkPolicyUtils.java
index 5693c2f..281f7ba6 100644
--- a/packages/SettingsLib/Utils/src/com/android/settingslib/utils/WorkPolicyUtils.java
+++ b/packages/SettingsLib/Utils/src/com/android/settingslib/utils/WorkPolicyUtils.java
@@ -27,17 +27,20 @@
import android.os.UserManager;
import android.provider.Settings;
+import androidx.annotation.Nullable;
+
import java.util.List;
+
/**
* Utility class for find out when to show WorkPolicyInfo
*/
public class WorkPolicyUtils {
- Context mContext;
- PackageManager mPackageManager;
- UserManager mUserManager;
- DevicePolicyManager mDevicePolicyManager;
+ private final Context mContext;
+ private final PackageManager mPackageManager;
+ private final UserManager mUserManager;
+ private final DevicePolicyManager mDevicePolicyManager;
private static final int USER_NULL = -10000;
@@ -81,7 +84,12 @@
return false;
}
- private Intent getWorkPolicyInfoIntentDO() {
+ /**
+ * Returns the work policy info intent if the device owner component exists,
+ * and returns {@code null} otherwise
+ */
+ @Nullable
+ public Intent getWorkPolicyInfoIntentDO() {
final ComponentName ownerComponent = getDeviceOwnerComponent();
if (ownerComponent == null) {
return null;
@@ -99,43 +107,55 @@
return null;
}
- private Intent getWorkPolicyInfoIntentPO() {
+ @Nullable
+ private ComponentName getManagedProfileOwnerComponent(int managedUserId) {
+ if (managedUserId == USER_NULL) {
+ return null;
+ }
+ Context managedProfileContext;
try {
- final int managedUserId = getManagedProfileUserId();
- if (managedUserId == USER_NULL) {
- return null;
- }
-
- Context managedProfileContext =
+ managedProfileContext =
mContext.createPackageContextAsUser(
mContext.getPackageName(), 0, UserHandle.of(managedUserId)
);
-
- DevicePolicyManager managedProfileDevicePolicyManager =
- (DevicePolicyManager)
- managedProfileContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
- ComponentName ownerComponent = managedProfileDevicePolicyManager.getProfileOwner();
- if (ownerComponent == null) {
- return null;
- }
-
- // Only search for the required action in the Profile Owner's package
- final Intent intent =
- new Intent(Settings.ACTION_SHOW_WORK_POLICY_INFO)
- .setPackage(ownerComponent.getPackageName());
- final List<ResolveInfo> activities =
- mPackageManager.queryIntentActivitiesAsUser(
- intent, 0, UserHandle.of(managedUserId));
- if (activities.size() != 0) {
- return intent;
- }
-
- return null;
} catch (PackageManager.NameNotFoundException e) {
return null;
}
+
+ DevicePolicyManager managedProfileDevicePolicyManager =
+ (DevicePolicyManager)
+ managedProfileContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
+ ComponentName ownerComponent = managedProfileDevicePolicyManager.getProfileOwner();
+ return ownerComponent;
}
+ /**
+ * Returns the work policy info intent if the profile owner component exists,
+ * and returns {@code null} otherwise
+ */
+ @Nullable
+ public Intent getWorkPolicyInfoIntentPO() {
+ final int managedUserId = getManagedProfileUserId();
+ ComponentName ownerComponent = getManagedProfileOwnerComponent(managedUserId);
+ if (ownerComponent == null) {
+ return null;
+ }
+
+ // Only search for the required action in the Profile Owner's package
+ final Intent intent =
+ new Intent(Settings.ACTION_SHOW_WORK_POLICY_INFO)
+ .setPackage(ownerComponent.getPackageName());
+ final List<ResolveInfo> activities =
+ mPackageManager.queryIntentActivitiesAsUser(
+ intent, 0, UserHandle.of(managedUserId));
+ if (activities.size() != 0) {
+ return intent;
+ }
+
+ return null;
+ }
+
+ @Nullable
private ComponentName getDeviceOwnerComponent() {
if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN)) {
return null;
@@ -143,7 +163,10 @@
return mDevicePolicyManager.getDeviceOwnerComponentOnAnyUser();
}
- private int getManagedProfileUserId() {
+ /**
+ * Returns the user id of the managed profile, and returns {@code USER_NULL} otherwise
+ */
+ public int getManagedProfileUserId() {
List<UserHandle> allProfiles = mUserManager.getAllProfiles();
for (UserHandle uh : allProfiles) {
int id = uh.getIdentifier();
diff --git a/packages/SettingsLib/res/drawable/ic_qr_code_scanner.xml b/packages/SettingsLib/res/drawable/ic_qr_code_scanner.xml
deleted file mode 100644
index f6f63c5..0000000
--- a/packages/SettingsLib/res/drawable/ic_qr_code_scanner.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?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.
--->
-
-<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="M2,7V2H7V4H4V7ZM2,22V17H4V20H7V22ZM17,22V20H20V17H22V22ZM20,7V4H17V2H22V7ZM17.5,17.5H19V19H17.5ZM17.5,14.5H19V16H17.5ZM16,16H17.5V17.5H16ZM14.5,17.5H16V19H14.5ZM13,16H14.5V17.5H13ZM16,13H17.5V14.5H16ZM14.5,14.5H16V16H14.5ZM13,13H14.5V14.5H13ZM19,5V11H13V5ZM11,13V19H5V13ZM11,5V11H5V5ZM9.5,17.5V14.5H6.5V17.5ZM9.5,9.5V6.5H6.5V9.5ZM17.5,9.5V6.5H14.5V9.5Z"/>
-</vector>
\ No newline at end of file
diff --git a/packages/SettingsLib/res/layout/qrcode_scanner_fragment.xml b/packages/SettingsLib/res/layout/qrcode_scanner_fragment.xml
deleted file mode 100644
index 0a7fe09..0000000
--- a/packages/SettingsLib/res/layout/qrcode_scanner_fragment.xml
+++ /dev/null
@@ -1,102 +0,0 @@
-<?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"
- xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
-
- <LinearLayout
- android:id="@+id/sud_layout_icon_container"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_weight="3"
- android:layout_marginBottom="35dp">
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="bottom"
- android:gravity="center"
- android:orientation="vertical">
- <ImageView
- android:id="@+id/sud_layout_icon"
- android:src="@drawable/ic_qr_code_scanner"
- android:tint="?androidprv:attr/colorAccentPrimaryVariant"
- android:layout_width="@dimen/qrcode_icon_size"
- android:layout_height="@dimen/qrcode_icon_size"
- android:contentDescription="@null"/>
-
- <TextView
- android:id="@+id/sud_layout_title"
- style="@style/QrCodeScanner"
- android:textSize="24sp"
- android:text="@string/bt_le_audio_scan_qr_code"
- android:gravity="center"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="19dp"/>
-
- <TextView
- android:id="@+id/sud_layout_subtitle"
- style="@style/QrCodeScanner"
- android:text="@string/bt_le_audio_scan_qr_code_scanner"
- android:gravity="center"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="8dp"/>
- </LinearLayout>
- </LinearLayout>
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_weight="7"
- android:orientation="vertical">
-
- <FrameLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="top"
- android:gravity="center"
- android:clipChildren="true">
- <TextureView
- android:id="@+id/preview_view"
- android:layout_marginStart="@dimen/qrcode_preview_margin"
- android:layout_marginEnd="@dimen/qrcode_preview_margin"
- android:layout_width="match_parent"
- android:layout_height="@dimen/qrcode_preview_size"/>
- </FrameLayout>
-
- <TextView
- android:id="@+id/error_message"
- style="@style/TextAppearance.ErrorText"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="16dp"
- android:layout_marginStart="?attr/sudMarginStart"
- android:layout_marginEnd="?attr/sudMarginEnd"
- android:gravity="center"
- android:layout_gravity="center"
- android:visibility="invisible"/>
-
- </LinearLayout>
-
-
-</LinearLayout>
-
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 9f5cf35..7b8bdb2 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -612,7 +612,7 @@
<string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Verlaat gasmodus"</string>
<string name="guest_notification_ephemeral" msgid="7263252466950923871">"Alle aktiwiteit sal uitgevee word wanneer jy uitgaan"</string>
<string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Jy kan jou aktiwiteit stoor of uitvee wanneer jy uitgaan"</string>
- <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Stel terug om sessie-aktiwiteit nou uit te vee, of jy kan aktiwiteit stoor of uitvee wanneer jy uitgaan"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Stel terug om aktiwiteit nou uit te vee, of stoor of vee aktiwiteit uit wanneer jy uitgaan"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Neem \'n foto"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Kies \'n prent"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Kies foto"</string>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index f85d314..78ea818 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -594,7 +594,7 @@
<string name="guest_exit_guest" msgid="5908239569510734136">"Ukloni gosta"</string>
<string name="guest_reset_guest" msgid="6110013010356013758">"Resetuj sesiju gosta"</string>
<string name="guest_reset_guest_dialog_title" msgid="8047270010895437534">"Želite li da resetujete sesiju gosta?"</string>
- <string name="guest_remove_guest_dialog_title" msgid="4548511006624088072">"Želite li da uklonite gosta?"</string>
+ <string name="guest_remove_guest_dialog_title" msgid="4548511006624088072">"Želite da uklonite gosta?"</string>
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Resetuj"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"Ukloni"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Sesija gosta se resetuje…"</string>
@@ -612,7 +612,7 @@
<string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Izađi iz režima gosta"</string>
<string name="guest_notification_ephemeral" msgid="7263252466950923871">"Sve aktivnosti će biti izbrisane pri izlazu"</string>
<string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Možete da sačuvate ili izbrišete aktivnosti pri izlazu"</string>
- <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Resetujete da biste izbrisali aktivnosti sesije odmah ili možete da sačuvate ili izbrišete aktivnosti pri izlazu"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Resetujete za brisanje aktivnosti sesije, ili sačuvajte ili izbrišite aktivnosti pri izlazu"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Slikaj"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Odaberi sliku"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Izaberite sliku"</string>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index 6188dc1..013cffa 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -612,7 +612,7 @@
<string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Выйсці з гасцявога рэжыму"</string>
<string name="guest_notification_ephemeral" msgid="7263252466950923871">"Падчас выхаду будуць выдалены ўсе звесткі пра дзеянні"</string>
<string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Падчас выхаду можна захаваць ці выдаліць звесткі пра дзеянні"</string>
- <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Скіньце налады, каб выдаліць звесткі пра дзеянні падчас сеанса. Таксама можна захаваць ці выдаліць гэтыя звесткі ў час выхаду"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Скіньце звесткі пра дзеянні падчас сеанса зараз. Вы таксама можаце захаваць ці выдаліць іх у час выхаду."</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Зрабіць фота"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Выбраць відарыс"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Выбраць фота"</string>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index 4375eb6..1ecdb09 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -603,7 +603,7 @@
<string name="guest_exit_dialog_title" msgid="1846494656849381804">"Изход от режима на гост?"</string>
<string name="guest_exit_dialog_message" msgid="1743218864242719783">"Така ще изтриете приложенията и данните от текущата сесия като гост"</string>
<string name="guest_exit_dialog_button" msgid="1736401897067442044">"Изход"</string>
- <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Активност като гост – запазване?"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Запазване на активността като гост?"</string>
<string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Можете да запазите активността от сесията или да изтриете всички прил. и данни"</string>
<string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Изтриване"</string>
<string name="guest_exit_save_data_button" msgid="3690974510644963547">"Запазване"</string>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index f3f5b3d..548a4f6 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -603,7 +603,7 @@
<string name="guest_exit_dialog_title" msgid="1846494656849381804">"\'অতিথি মোড\' ছেড়ে বেরিয়ে আসবেন?"</string>
<string name="guest_exit_dialog_message" msgid="1743218864242719783">"এটি বর্তমান অতিথি সেশন থেকে অ্যাপ ও ডেটা মুছে দেবে"</string>
<string name="guest_exit_dialog_button" msgid="1736401897067442044">"বেরিয়ে আসুন"</string>
- <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"অতিথি অ্যাক্টিভিটি সেভ করবেন?"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"অতিথি মোডের অ্যাক্টিভিটি সেভ করবেন?"</string>
<string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"আপনি বর্তমান সেশন থেকে অ্যাক্টিভিটি সেভ করতে বা সব অ্যাপ ও ডেটা মুছতে পারবেন"</string>
<string name="guest_exit_clear_data_button" msgid="3425812652180679014">"মুছুন"</string>
<string name="guest_exit_save_data_button" msgid="3690974510644963547">"সেভ করুন"</string>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index dc74450..d10faed 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -604,15 +604,15 @@
<string name="guest_exit_dialog_message" msgid="1743218864242719783">"Ovim ćete izbrisati aplikacije i podatke iz trenutne sesije gosta"</string>
<string name="guest_exit_dialog_button" msgid="1736401897067442044">"Napusti"</string>
<string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Sačuvati aktivnost gosta?"</string>
- <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Možete sačuvati aktivnost iz sesije ili izbrisati sve aplikacije i podatke"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Možete sačuvati aktivnost iz ove sesije ili izbrisati sve aplikacije i podatke"</string>
<string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Izbriši"</string>
<string name="guest_exit_save_data_button" msgid="3690974510644963547">"Sačuvaj"</string>
<string name="guest_exit_button" msgid="5774985819191803960">"Napusti način rada za gosta"</string>
<string name="guest_reset_button" msgid="2515069346223503479">"Poništi sesiju gosta"</string>
<string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Izlazak iz sesije gosta"</string>
<string name="guest_notification_ephemeral" msgid="7263252466950923871">"Sva aktivnost će biti izbrisana kada napustite sesiju"</string>
- <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Možete sačuvati ili izbrisati svoju aktivnost pri napuštanju"</string>
- <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Poništite da sada izbrišete aktivnost iz sesije ili možete sačuvati ili izbrisati aktivnost pri napuštanju"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Možete sačuvati ili izbrisati svoju aktivnost pri izlasku"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Poništite da odmah izbrišete aktivnost iz sesije ili je možete sačuvati ili izbrisati pri izlasku"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Snimite fotografiju"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Odaberite sliku"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Odabir fotografije"</string>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 8ec8f0f..82d2de3 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -612,7 +612,7 @@
<string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Surt del mode de convidat"</string>
<string name="guest_notification_ephemeral" msgid="7263252466950923871">"Se suprimirà tota l\'activitat en sortir"</string>
<string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Pots desar o suprimir l\'activitat en sortir"</string>
- <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Restableix per suprimir l\'activitat de la sessió ara. També pots desar o suprimir l\'activitat en sortir."</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Restableix la sessió per suprimir l\'activitat ara, o desa o suprimeix l\'activitat en sortir."</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Fes una foto"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Tria una imatge"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Selecciona una foto"</string>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index 0ef99e9..32d5e0b 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -612,7 +612,7 @@
<string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Afslut gæstesession"</string>
<string name="guest_notification_ephemeral" msgid="7263252466950923871">"Al aktivitet slettes ved afslutning"</string>
<string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Du kan gemme eller slette din aktivitet ved afslutning"</string>
- <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Nulstil for at slette sessionsaktiviteten nu, eller du kan gemme eller slette aktivitet ved afslutning"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Nulstil for at slette sessionsaktiviteten nu, eller gem eller slet aktivitet ved afslutning"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Tag et billede"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Vælg et billede"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Vælg billede"</string>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index f94d43a..6af29cf 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -600,19 +600,19 @@
<string name="guest_resetting" msgid="7822120170191509566">"Επαναφορά επισκέπτη…"</string>
<string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"Επαναφορά περιόδου σύνδεσης επισκέπτη;"</string>
<string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"Με αυτόν τον τρόπο θα ξεκινήσει μια νέα περίοδος σύνδεσης επισκέπτη και θα διαγραφούν όλες οι εφαρμογές και τα δεδομένα από την τρέχουσα περίοδο σύνδεσης"</string>
- <string name="guest_exit_dialog_title" msgid="1846494656849381804">"Έξοδος από λειτουργία επισκέπτη;"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"Έξοδος από λειτ. επισκέπτη;"</string>
<string name="guest_exit_dialog_message" msgid="1743218864242719783">"Θα διαγραφούν εφαρμογές και δεδομένα από την τρέχουσα περίοδο σύνδεσης επισκέπτη"</string>
<string name="guest_exit_dialog_button" msgid="1736401897067442044">"Έξοδος"</string>
<string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Αποθήκευση δραστ. επισκέπτη;"</string>
<string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Αποθήκευση δραστ. τρέχουσας περιόδου σύνδεσης ή διαγραφή εφαρμογών και δεδομένων"</string>
<string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Διαγραφή"</string>
<string name="guest_exit_save_data_button" msgid="3690974510644963547">"Αποθήκευση"</string>
- <string name="guest_exit_button" msgid="5774985819191803960">"Έξοδος από λειτουργία επισκέπτη"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"Έξοδος από λειτ. επισκέπτη"</string>
<string name="guest_reset_button" msgid="2515069346223503479">"Επαναφορά περ. σύνδεσης επισκέπτη"</string>
<string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Έξοδος επισκέπτη"</string>
<string name="guest_notification_ephemeral" msgid="7263252466950923871">"Όλη η δραστηριότητα θα διαγραφεί κατά την έξοδο"</string>
<string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Αποθηκεύστε ή διαγράψτε τη δραστηριότητά σας κατά την έξοδο"</string>
- <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Κάντε επαναφορά για να διαγράψετε τη δραστηριότητα της περιόδου σύνδεσης τώρα ή μπορείτε να αποθηκεύσετε ή να διαγράψετε τη δραστηριότητα κατά την έξοδο"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Επαναφορά για διαγραφή της δραστηριότητας της περιόδου σύνδεσης ή αποθήκευση ή διαγραφή κατά την έξοδο."</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Λήψη φωτογραφίας"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Επιλογή εικόνας"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Επιλογή φωτογραφίας"</string>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index afdfa92..d57b79a 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -612,7 +612,7 @@
<string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Salir del modo de invitado"</string>
<string name="guest_notification_ephemeral" msgid="7263252466950923871">"Cuando salgas, se borrará toda la actividad"</string>
<string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Puedes guardar o borrar la actividad cuando salgas"</string>
- <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Restablece la sesión para borrar la actividad ahora, o bien guarda y borra la actividad cuando salgas"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Restablece la sesión para eliminar la actividad ahora; o guarda o borra la actividad cuando salgas"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Tomar una foto"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Elegir una imagen"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Seleccionar foto"</string>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index ba723ac..bbf4e41 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -570,7 +570,7 @@
<string name="user_add_profile_item_title" msgid="3111051717414643029">"Perfil restringido"</string>
<string name="user_add_user_title" msgid="5457079143694924885">"¿Añadir nuevo usuario?"</string>
<string name="user_add_user_message_long" msgid="1527434966294733380">"Puedes compartir este dispositivo si creas más usuarios. Cada uno tendrá su propio espacio y podrá personalizarlo con aplicaciones, un fondo de pantalla y mucho más. Los usuarios también pueden ajustar opciones del dispositivo, como la conexión Wi‑Fi, que afectan a todos los usuarios.\n\nCuando añadas un usuario, tendrá que configurar su espacio.\n\nCualquier usuario puede actualizar aplicaciones de todos los usuarios. Es posible que no se transfieran los servicios y opciones de accesibilidad al nuevo usuario."</string>
- <string name="user_add_user_message_short" msgid="3295959985795716166">"Al añadir un usuario nuevo, debe configurar su espacio.\n\nCualquier usuario puede actualizar las aplicaciones del resto de usuarios."</string>
+ <string name="user_add_user_message_short" msgid="3295959985795716166">"Al añadir un nuevo usuario, dicha persona debe configurar su espacio.\n\nCualquier usuario puede actualizar las aplicaciones del resto de usuarios."</string>
<string name="user_setup_dialog_title" msgid="8037342066381939995">"¿Configurar usuario ahora?"</string>
<string name="user_setup_dialog_message" msgid="269931619868102841">"Asegúrate de que la persona está disponible en este momento para usar el dispositivo y configurar su espacio."</string>
<string name="user_setup_profile_dialog_message" msgid="4788197052296962620">"¿Quieres configurar un perfil ahora?"</string>
@@ -600,19 +600,19 @@
<string name="guest_resetting" msgid="7822120170191509566">"Restableciendo invitado…"</string>
<string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"¿Restablecer sesión de invitado?"</string>
<string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"Se iniciará una nueva sesión de invitado y se borrarán todas las aplicaciones y datos de esta sesión"</string>
- <string name="guest_exit_dialog_title" msgid="1846494656849381804">"¿Salir del modo Invitados?"</string>
- <string name="guest_exit_dialog_message" msgid="1743218864242719783">"Se eliminarán todas las aplicaciones y datos de la sesión de invitado"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"¿Salir del modo Invitado?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"Se eliminarán todas las aplicaciones y datos de la sesión de invitado actual"</string>
<string name="guest_exit_dialog_button" msgid="1736401897067442044">"Salir"</string>
- <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"¿Guardar actividad de invitados?"</string>
- <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Puedes guardar la actividad de esta sesión o eliminar las aplicaciones y datos"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"¿Guardar actividad de invitado?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Puedes guardar la actividad de esta sesión o eliminar todas las aplicaciones y datos"</string>
<string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Eliminar"</string>
<string name="guest_exit_save_data_button" msgid="3690974510644963547">"Guardar"</string>
- <string name="guest_exit_button" msgid="5774985819191803960">"Salir del modo Invitados"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"Salir del modo Invitado"</string>
<string name="guest_reset_button" msgid="2515069346223503479">"Restablecer sesión de invitado"</string>
- <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Salir del modo Invitados"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Salir del modo Invitado"</string>
<string name="guest_notification_ephemeral" msgid="7263252466950923871">"Toda la actividad se eliminará cuando salgas"</string>
- <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Puedes guardar o eliminar tu actividad cuando salgas"</string>
- <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Restablece la sesión para eliminar la actividad ahora, o guarda o elimina la actividad cuando salgas"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Puedes guardar o eliminar tu actividad al salir"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Restablece la sesión para eliminar la actividad ahora, o guarda o borra la actividad al salir"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Hacer foto"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Seleccionar una imagen"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Seleccionar foto"</string>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index a42fc4d..67a92e9 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -599,7 +599,7 @@
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"Eemalda"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Külastajaseansi lähtestamine …"</string>
<string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"Kas lähtestada külastajaseanss?"</string>
- <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"See alustab uut külastajaseanssi ning kustutab kõik praeguse seansi rakendused ja andmed"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"See alustab uut külastajaseanssi ning kustutab kõik praeguse seansi rakendused ja andmed."</string>
<string name="guest_exit_dialog_title" msgid="1846494656849381804">"Kas väljuda külalisrežiimist?"</string>
<string name="guest_exit_dialog_message" msgid="1743218864242719783">"See kustutab praeguse külastajaseansi rakendused ja andmed"</string>
<string name="guest_exit_dialog_button" msgid="1736401897067442044">"Välju"</string>
@@ -611,8 +611,8 @@
<string name="guest_reset_button" msgid="2515069346223503479">"Lähtesta külastajaseanss"</string>
<string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Välju külastajaseansist"</string>
<string name="guest_notification_ephemeral" msgid="7263252466950923871">"Kõik tegevused kustutatakse väljumisel"</string>
- <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Võite tegevused salvestada või kustutada väljumisel"</string>
- <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Lähtestage, et seansi tegevused kohe kustutada; samuti võite tegevused salvestada või kustutada väljumisel"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Võite tegevused salvestada või kustutada väljumisel."</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Seansi tegevuste kohe kustutamiseks lähtestage; või salvestage või kustutage need väljumisel."</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Pildistage"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Valige pilt"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Valige foto"</string>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index 7597147..0ec5c6f 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -446,7 +446,7 @@
<string name="daltonizer_mode_monochromacy" msgid="362060873835885014">"Ikusmen-monokromia"</string>
<string name="daltonizer_mode_deuteranomaly" msgid="3507284319584683963">"Daltonismoa (gorri-berdeak)"</string>
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanopia (gorri-berdeak)"</string>
- <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanopia (urdin-horia)"</string>
+ <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalia (urdin-horia)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Koloreen zuzenketa"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Baliteke koloreen zuzenketa lagungarria izatea hauek egin nahi dituzunean:<br/> <ol> <li>&nbsp;Koloreak zehaztasun handiagoz ikusi.</li> <li>&nbsp;Koloreak kendu, arreta gal ez dezazun.</li> </ol>"</string>
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> hobespena gainjarri zaio"</string>
@@ -569,7 +569,7 @@
<string name="user_add_user_item_title" msgid="2394272381086965029">"Erabiltzailea"</string>
<string name="user_add_profile_item_title" msgid="3111051717414643029">"Profil murriztua"</string>
<string name="user_add_user_title" msgid="5457079143694924885">"Beste erabiltzaile bat gehitu nahi duzu?"</string>
- <string name="user_add_user_message_long" msgid="1527434966294733380">"Gailu hau beste pertsona batzuekin partekatzeko, sortu erabiltzaile gehiago. Erabiltzaile bakoitzak bere eremua izango du eta, bertan, aplikazioak, horma-papera eta antzekoak pertsonalizatu ahal izango ditu. Horrez gain, erabiltzaile guztiei eragin diezaieketen ezarpen batzuk ere doi daitezke; adibidez, wifi-konexioarena.\n\nErabiltzaile bat gehitzen duzunean, pertsona horrek berak konfiguratu beharko du bere eremua.\n\nEdozein erabiltzailek egunera ditzake beste erabiltzaile guztien aplikazioak. Baliteke erabilerraztasun-ezarpenak eta -zerbitzuak ez transferitzea erabiltzaile berriei."</string>
+ <string name="user_add_user_message_long" msgid="1527434966294733380">"Gailu hau beste pertsona batzuekin partekatzeko, sortu erabiltzaile gehiago. Erabiltzaile bakoitzak bere eremua izango du eta, bertan, aplikazioak, horma-papera eta antzekoak pertsonalizatu ahal izango ditu. Horrez gain, agian erabiltzaile guztiei eragingo dieten ezarpen batzuk ere doi daitezke; adibidez, wifi-konexioarena.\n\nErabiltzaile bat gehitzen duzunean, pertsona horrek berak konfiguratu beharko du bere eremua.\n\nEdozein erabiltzailek egunera ditzake beste erabiltzaile guztien aplikazioak. Baliteke erabilerraztasun-ezarpenak eta -zerbitzuak ez transferitzea erabiltzaile berriei."</string>
<string name="user_add_user_message_short" msgid="3295959985795716166">"Erabiltzaile bat gehitzen duzunean, erabiltzaile horrek bere eremua konfiguratu beharko du.\n\nEdozein erabiltzailek egunera ditzake beste erabiltzaile guztien aplikazioak."</string>
<string name="user_setup_dialog_title" msgid="8037342066381939995">"Erabiltzailea konfiguratu?"</string>
<string name="user_setup_dialog_message" msgid="269931619868102841">"Ziurtatu pertsona horrek gailua hartu eta bere eremua konfigura dezakeela"</string>
@@ -610,9 +610,9 @@
<string name="guest_exit_button" msgid="5774985819191803960">"Irten gonbidatu modutik"</string>
<string name="guest_reset_button" msgid="2515069346223503479">"Berrezarri gonbidatuentzako saioa"</string>
<string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Irten gonbidatu modutik"</string>
- <string name="guest_notification_ephemeral" msgid="7263252466950923871">"Saiotik irtetean, jarduera guztiak ezabatuko dira"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"Irtetean, jarduera guztiak ezabatuko dira"</string>
<string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Irtetean, jarduerak gorde edo ezabatu egin ditzakezu"</string>
- <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Berrezarri saioa jarduerak ezabatzeko (bestela, jarduerak gordetzea edo ezabatzea aukera dezakezu irtetean)"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Berrezarri saioa jarduerak ezabatzeko; bestela, aukeratu jarduerak irtetean gordetzea edo ezabatzea"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Atera argazki bat"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Aukeratu irudi bat"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Hautatu argazki bat"</string>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index 15df12c..fb7a2e3 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -612,7 +612,7 @@
<string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Quitter le mode Invité"</string>
<string name="guest_notification_ephemeral" msgid="7263252466950923871">"Toute l\'activité sera supprimée une fois la session quittée"</string>
<string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Vous pouvez enregistrer ou supprimer l\'activité en quittant"</string>
- <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Réinitialisez la session pour supprimer immédiatement l\'activité, qui pourra aussi être enregistrée ou supprimée lorsque vous quitterez la session"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Réinitialisez la session pour supprimer immédiatement l\'activité. Vous pourrez aussi l\'enregistrer ou la supprimer en quittant la session."</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Prendre une photo"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Choisir une image"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Sélectionner une photo"</string>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index cd002d5..8710dd9 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -619,7 +619,7 @@
<string name="failed_attempts_now_wiping_device" msgid="4016329172216428897">"Realizaches demasiados intentos incorrectos. Eliminaranse os datos deste dispositivo."</string>
<string name="failed_attempts_now_wiping_user" msgid="469060411789668050">"Realizaches demasiados intentos incorrectos. Eliminarase este usuario."</string>
<string name="failed_attempts_now_wiping_profile" msgid="7626589520888963129">"Realizaches demasiados intentos incorrectos. Eliminaranse este perfil de traballo e os datos asociados."</string>
- <string name="failed_attempts_now_wiping_dialog_dismiss" msgid="2749889771223578925">"Ignorar"</string>
+ <string name="failed_attempts_now_wiping_dialog_dismiss" msgid="2749889771223578925">"Pechar"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Funcionamento predeterminado"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Desactivado"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Activado"</string>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index a1722d7..9de0a50 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -583,7 +583,7 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"Profilni podaci"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"Prije izrade ograničenog profila trebate postaviti zaključavanje zaslona radi zaštite svojih aplikacija i osobnih podataka."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Postavi zaključavanje"</string>
- <string name="user_switch_to_user" msgid="6975428297154968543">"Prelazak na korisnika <xliff:g id="USER_NAME">%s</xliff:g>"</string>
+ <string name="user_switch_to_user" msgid="6975428297154968543">"Prijeđi na korisnika <xliff:g id="USER_NAME">%s</xliff:g>"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Izrada novog korisnika…"</string>
<string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Izrada novog gosta…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"Izrada novog korisnika nije uspjela"</string>
@@ -591,7 +591,7 @@
<string name="user_nickname" msgid="262624187455825083">"Nadimak"</string>
<string name="user_add_user" msgid="7876449291500212468">"Dodavanje korisnika"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Dodavanje gosta"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"Uklanjanje gosta"</string>
+ <string name="guest_exit_guest" msgid="5908239569510734136">"Ukloni gosta"</string>
<string name="guest_reset_guest" msgid="6110013010356013758">"Poništi gostujuću sesiju"</string>
<string name="guest_reset_guest_dialog_title" msgid="8047270010895437534">"Poništiti gostujuću sesiju?"</string>
<string name="guest_remove_guest_dialog_title" msgid="4548511006624088072">"Želite li ukloniti gosta?"</string>
@@ -611,8 +611,8 @@
<string name="guest_reset_button" msgid="2515069346223503479">"Poništi gostujuću sesiju"</string>
<string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Izlaz iz gostujuće sesije"</string>
<string name="guest_notification_ephemeral" msgid="7263252466950923871">"Sve će se aktivnosti izbrisati na izlasku"</string>
- <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Možete spremiti ili izbrisati svoje aktivnosti na izlasku"</string>
- <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Poništite da biste odmah izbrisali aktivnost sesije, a možete i spremiti ili izbrisati aktivnost na izlasku."</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Svoje aktivnosti možete spremiti ili izbrisati na izlasku."</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Poništite da odmah izbrišete aktivnost sesije. Inače je možete spremiti ili izbrisati na izlasku."</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Fotografiraj"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Odaberi sliku"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Odabir slike"</string>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index fe6bc88..fe69a82 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -612,7 +612,7 @@
<string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Vendég kiléptetése"</string>
<string name="guest_notification_ephemeral" msgid="7263252466950923871">"A kilépéssel minden tevékenység törlődik"</string>
<string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"A kilépéskor mentheti vagy törölheti a tevékenységeket"</string>
- <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Visszaállítással azonnal törölheti a munkamenethez tartozó tevékenységeket, illetve kilépéskor mentheti vagy törölheti a tevékenységeket"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Visszaállítással azonnal törölheti, illetve kilépéskor mentheti vagy törölheti a tevékenységeket"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Fotó készítése"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Kép kiválasztása"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Fotó kiválasztása"</string>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index 9b4b217..5f6d240 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -593,12 +593,12 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Ավելացնել հյուր"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Հեռացնել հյուրին"</string>
<string name="guest_reset_guest" msgid="6110013010356013758">"Վերակայել հյուրի աշխատաշրջանը"</string>
- <string name="guest_reset_guest_dialog_title" msgid="8047270010895437534">"Վերակայե՞լ հյուրի աշխատաշրջանը"</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_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>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"Զրոյացնե՞լ հյուրի աշխատաշրջանը"</string>
<string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"Կսկսվի հյուրի նոր աշխատաշրջան, իսկ նախորդ աշխատաշրջանի բոլոր հավելվածներն ու տվյալները կջնջվեն"</string>
<string name="guest_exit_dialog_title" msgid="1846494656849381804">"Դուրս գա՞լ հյուրի ռեժիմից"</string>
<string name="guest_exit_dialog_message" msgid="1743218864242719783">"Հյուրի ընթացիկ աշխատաշրջանի բոլոր հավելվածներն ու տվյալները կջնջվեն"</string>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index 96e129a..0d1efbb 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -612,7 +612,7 @@
<string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Keluar dari mode tamu"</string>
<string name="guest_notification_ephemeral" msgid="7263252466950923871">"Semua aktivitas akan dihapus saat Anda keluar"</string>
<string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Anda dapat menyimpan atau menghapus aktivitas saat keluar"</string>
- <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Reset untuk menghapus aktivitas sesi sekarang, atau Anda dapat menyimpan atau menghapus aktivitas saat keluar"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Reset untuk hapus aktivitas sesi sekarang, atau simpan atau hapus aktivitas saat keluar"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Ambil foto"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Pilih gambar"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Pilih foto"</string>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index 3a1ab7f..48fd849 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -612,7 +612,7 @@
<string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Loka gestastillingu"</string>
<string name="guest_notification_ephemeral" msgid="7263252466950923871">"Öllum aðgerðum verður eytt þegar lotu er lokað"</string>
<string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Þú getur vistað eða eytt aðgerðum þegar þú lokar"</string>
- <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Endurstilltu til að eyða aðgerðum lotu núna, eða þú getur vistað eða eytt aðgerðum þegar þú lokar"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Endurstilltu til að eyða aðgerðum lotu núna, eða vistaðu eða eyddu aðgerðum þegar þú lokar"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Taka mynd"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Velja mynd"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Velja mynd"</string>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index e312fa7..f41b78e 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -604,7 +604,7 @@
<string name="guest_exit_dialog_message" msgid="1743218864242719783">"Verranno eliminati i dati e le app della sessione Ospite corrente"</string>
<string name="guest_exit_dialog_button" msgid="1736401897067442044">"Esci"</string>
<string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Vuoi salvare l\'attività Ospite?"</string>
- <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Puoi salvare l\'attività della sessione corrente o eliminare tutti i dati e app"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Puoi salvare l\'attività della sessione corrente o eliminare tutti i dati e le app"</string>
<string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Elimina"</string>
<string name="guest_exit_save_data_button" msgid="3690974510644963547">"Salva"</string>
<string name="guest_exit_button" msgid="5774985819191803960">"Esci dalla modalità Ospite"</string>
@@ -612,7 +612,7 @@
<string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Esci dalla modalità Ospite"</string>
<string name="guest_notification_ephemeral" msgid="7263252466950923871">"Quando esci verrà eliminata tutta l\'attività"</string>
<string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Quando esci puoi salvare o eliminare la tua attività"</string>
- <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Reimposta per eliminare subito l\'attività della sessione oppure puoi salvare o eliminare l\'attività quando esci"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Reimposta la sessione per eliminare subito l\'attività, oppure salvala o eliminala quando esci"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Scatta una foto"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Scegli un\'immagine"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Seleziona la foto"</string>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index 6f0759d..f3472fa 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -569,8 +569,8 @@
<string name="user_add_user_item_title" msgid="2394272381086965029">"ユーザー"</string>
<string name="user_add_profile_item_title" msgid="3111051717414643029">"制限付きプロファイル"</string>
<string name="user_add_user_title" msgid="5457079143694924885">"新しいユーザーを追加しますか?"</string>
- <string name="user_add_user_message_long" msgid="1527434966294733380">"追加ユーザーを作成して、このデバイスを他のユーザーと共有できます。各ユーザーは各自のスペースを所有して、アプリや壁紙などのカスタマイズを行うことができます。Wi-Fi など、すべてのユーザーに影響するデバイス設定を変更することもできます。\n\n新しく追加したユーザーは各自でスペースをセットアップする必要があります。\n\nすべてのユーザーは他のユーザーに代わってアプリを更新できます。ユーザー補助機能の設定とサービスは新しいユーザーに適用されないことがあります。"</string>
- <string name="user_add_user_message_short" msgid="3295959985795716166">"新しく追加したユーザーは各自でスペースをセットアップする必要があります。\n\nすべてのユーザーは他のユーザーに代わってアプリを更新できます。"</string>
+ <string name="user_add_user_message_long" msgid="1527434966294733380">"追加ユーザーを作成して、このデバイスを他のユーザーと共有できます。各ユーザーは各自のスペースを所有して、アプリや壁紙などのカスタマイズを行うことができます。Wi-Fi など、すべてのユーザーに影響するデバイス設定を変更することもできます。\n\n新しく追加したユーザーは各自でスペースをセットアップする必要があります。\n\nすべてのユーザーがアプリを更新でき、その影響は他のユーザーにも及びます。ユーザー補助機能の設定とサービスは新しいユーザーに適用されないことがあります。"</string>
+ <string name="user_add_user_message_short" msgid="3295959985795716166">"新しく追加したユーザーは各自でスペースをセットアップする必要があります。\n\nすべてのユーザーがアプリを更新でき、その影響は他のユーザーにも及びます。"</string>
<string name="user_setup_dialog_title" msgid="8037342066381939995">"ユーザーを今すぐセットアップ"</string>
<string name="user_setup_dialog_message" msgid="269931619868102841">"ユーザーがデバイスを使って各自のスペースをセットアップできるようにします"</string>
<string name="user_setup_profile_dialog_message" msgid="4788197052296962620">"プロファイルを今すぐセットアップしますか?"</string>
@@ -603,7 +603,7 @@
<string name="guest_exit_dialog_title" msgid="1846494656849381804">"ゲストモードを終了しますか?"</string>
<string name="guest_exit_dialog_message" msgid="1743218864242719783">"現在のゲスト セッションからすべてのアプリとデータが削除されます"</string>
<string name="guest_exit_dialog_button" msgid="1736401897067442044">"終了"</string>
- <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"ゲストのアクティビティを保存しますか?"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"ゲストアクティビティの保存"</string>
<string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"現在のセッションのアクティビティの保存や、すべてのアプリとデータの削除を行えます"</string>
<string name="guest_exit_clear_data_button" msgid="3425812652180679014">"削除"</string>
<string name="guest_exit_save_data_button" msgid="3690974510644963547">"保存"</string>
@@ -612,7 +612,7 @@
<string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"ゲストを終了"</string>
<string name="guest_notification_ephemeral" msgid="7263252466950923871">"終了時にすべてのアクティビティが削除されます"</string>
<string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"終了時にアクティビティを保存、削除できます"</string>
- <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"リセットして今すぐセッションのアクティビティを削除します(終了時にアクティビティを保存、削除することもできます)"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"アクティビティは、リセットして今すぐ削除するか、終了時に保存または削除できます"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"写真を撮る"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"画像を選択"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"写真を選択"</string>
diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml
index 525a0d2..d5ecf14 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/strings.xml
@@ -612,7 +612,7 @@
<string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"სტუმრის გასვლა"</string>
<string name="guest_notification_ephemeral" msgid="7263252466950923871">"გასვლისას ყველა აქტივობა წაიშლება"</string>
<string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"გასვლისას შეგიძლიათ შეინახოთ ან წაშალოთ თქვენი აქტივობა"</string>
- <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"გადააყენეთ სესიის აქტივობის ახლავე წასაშლელად, ასევე, შეინახეთ ან წაშალეთ აქტივობა გასვლისას"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"გადააყენეთ სესიის აქტივობის ახლა წასაშლელად. შენახვა/წაშლა გასვლისასაც შეიძლება."</string>
<string name="user_image_take_photo" msgid="467512954561638530">"ფოტოს გადაღება"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"აირჩიეთ სურათი"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"ფოტოს არჩევა"</string>
diff --git a/packages/SettingsLib/res/values-kk/arrays.xml b/packages/SettingsLib/res/values-kk/arrays.xml
index a831df1..33fd25b 100644
--- a/packages/SettingsLib/res/values-kk/arrays.xml
+++ b/packages/SettingsLib/res/values-kk/arrays.xml
@@ -54,9 +54,9 @@
<item msgid="9048424957228926377">"Әрқашан тексеру"</item>
</string-array>
<string-array name="hdcp_checking_summaries">
- <item msgid="4045840870658484038">"Ешқашан HDCP (жоғары кең жолақты сандық мазмұн қорғаушы) тексерулерін қолданбаңыз"</item>
+ <item msgid="4045840870658484038">"Ешқашан HDCP (жоғары кең жолақты цифрлық мазмұн қорғаушы) тексерулерін қолданбаңыз"</item>
<item msgid="8254225038262324761">"HDCP тексерісін DRM мазмұны үшін ғана қолдану"</item>
- <item msgid="6421717003037072581">"Әрқашан HDCP (жоғары кең жолақты сандық мазмұн қорғаушы) тексерулерін қолданыңыз"</item>
+ <item msgid="6421717003037072581">"Әрқашан HDCP (жоғары кең жолақты цифрлық мазмұн қорғаушы) тексерулерін қолданыңыз"</item>
</string-array>
<string-array name="bt_hci_snoop_log_entries">
<item msgid="695678520785580527">"Өшірулі"</item>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index 2f53894..79ba213 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -344,7 +344,7 @@
<string name="enable_terminal_title" msgid="3834790541986303654">"Жергілікті терминал"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"Жергілікті шелл-код қол жетімділігін ұсынатын терминалды қолданбаны қосу"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"HDCP тексерісі"</string>
- <string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"HDCP (кең жолақты сандық мазмұн қорғау) тексеру мүмкіндігін орнату"</string>
+ <string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"HDCP (кең жолақты цифрлық мазмұн қорғау) тексеру мүмкіндігін орнату"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"Түзету"</string>
<string name="debug_app" msgid="8903350241392391766">"Түзету қолданбасын таңдау"</string>
<string name="debug_app_not_set" msgid="1934083001283807188">"Түзету қолданбалары орнатылмаған."</string>
@@ -612,7 +612,7 @@
<string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Қонақ режимінен шығу"</string>
<string name="guest_notification_ephemeral" msgid="7263252466950923871">"Шыққанда барлық әрекет жойылады."</string>
<string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Шыққанда барлық әрекетті сақтай немесе жоя аласыз."</string>
- <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Сеанс әрекетін қазір жою үшін оны бастапқы күйге қайтарыңыз. Әрекетті сақтау немесе жою шешімін шыққан кезде қабылдай аласыз."</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Сеанс дерегін жою үшін оны бастапқы күйге қайтарыңыз. Деректі шығар кезде де сақтауға не жоюға болады."</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Фотосуретке түсіру"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Сурет таңдау"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Фотосурет таңдау"</string>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index 69cb714..abd61c6 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -599,9 +599,9 @@
<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>
- <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"이렇게 하면 새로운 게스트 세션이 시작되고 기존 세션의 모든 앱과 데이터가 삭제됩니다."</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"새로운 게스트 세션이 시작되고 기존 세션의 모든 앱과 데이터가 삭제됩니다."</string>
<string name="guest_exit_dialog_title" msgid="1846494656849381804">"게스트 모드를 종료하시겠습니까?"</string>
- <string name="guest_exit_dialog_message" msgid="1743218864242719783">"기존 게스트 세션의 앱과 데이터가 삭제됩니다."</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"현재 게스트 세션의 앱과 데이터가 삭제됩니다."</string>
<string name="guest_exit_dialog_button" msgid="1736401897067442044">"종료"</string>
<string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"게스트 활동을 저장하시겠습니까?"</string>
<string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"기존 세션의 활동을 저장하거나 모든 앱과 데이터를 삭제할 수 있습니다."</string>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index 341cdeb..441c79a 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -569,7 +569,7 @@
<string name="user_add_user_item_title" msgid="2394272381086965029">"Колдонуучу"</string>
<string name="user_add_profile_item_title" msgid="3111051717414643029">"Чектелген профайл"</string>
<string name="user_add_user_title" msgid="5457079143694924885">"Жаңы колдонуучу кошосузбу?"</string>
- <string name="user_add_user_message_long" msgid="1527434966294733380">"Эгер түзмөгүңүздү дагы бир адам колдонуп жаткан болсо, кошумча профилдерди түзүп коюңуз. Профилдин ээси аны өзү каалагандай жөндөп, тушкагаздарды коюп, керектүү колдонмолорду орнотуп алат. Мындан тышкары, колдонуучулар түзмөктүн Wi‑Fi´ды өчүрүү/күйгүзүү сыяктуу жалпы жөндөөлөрүн өзгөртө алат.\n\nПрофиль түзүлгөндөн кийин, аны жөндөп алуу керек.\n\nЖалпы колдонмолорду баары жаңырта алат, бирок атайын мүмкүнчүлүктөр өз-өзүнчө жөндөлөт."</string>
+ <string name="user_add_user_message_long" msgid="1527434966294733380">"Эгер түзмөгүңүздү дагы бир адам колдонуп жаткан болсо, кошумча профилдерди түзүп коюңуз. Профилдин ээси аны өзү каалагандай тууралап, тушкагаздарды коюп, керектүү колдонмолорду орнотуп алат. Мындан тышкары, колдонуучулар түзмөктүн Wi‑Fi´ды өчүрүү/күйгүзүү сыяктуу жалпы параметрлерин өзгөртө алышат.\n\nПрофиль түзүлгөндөн кийин, аны тууралап алуу керек.\n\nЖалпы колдонмолорду баары жаңырта алат, бирок атайын мүмкүнчүлүктөр өз-өзүнчө жөндөлөт."</string>
<string name="user_add_user_message_short" msgid="3295959985795716166">"Жаңы колдонуучу кошулганда, ал өз мейкиндигин түзүп алышы керек.\n\nКолдонмолорду бир колдонуучу жаңыртканда, ал калган бардык колдонуучулар үчүн да жаңырат."</string>
<string name="user_setup_dialog_title" msgid="8037342066381939995">"Профилди жөндөйсүзбү?"</string>
<string name="user_setup_dialog_message" msgid="269931619868102841">"Өз мейкиндигин жөндөп алышы үчүн, түзмөктү колдонуучуга беришиңиз керек."</string>
@@ -598,12 +598,12 @@
<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>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"Конок сеансын баштапкы абалга келтиресизби?"</string>
<string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"Бул аракет жаңы конок сеансын баштап, учурдагы сеанстагы бардык колдонмолорду жана алардагы нерселерди жок кылат"</string>
<string name="guest_exit_dialog_title" msgid="1846494656849381804">"Конок режиминен чыгасызбы?"</string>
<string name="guest_exit_dialog_message" msgid="1743218864242719783">"Бул учурдагы конок сеансындагы колдонмолорду жана алардагы нерселерди жок кылат"</string>
<string name="guest_exit_dialog_button" msgid="1736401897067442044">"Чыгуу"</string>
- <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Коноктун аракеттери сакталсынбы?"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Коноктун аракеттерин сактайсызбы?"</string>
<string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Учурдагы сеанстагы аракеттерди сактап же бардык колдонмолорду жана алардагы нерселерди жок кылсаңыз болот"</string>
<string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Өчүрүү"</string>
<string name="guest_exit_save_data_button" msgid="3690974510644963547">"Сактоо"</string>
@@ -612,7 +612,7 @@
<string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Конок режиминен чыгуу"</string>
<string name="guest_notification_ephemeral" msgid="7263252466950923871">"Чыксаңыз, бардык аракеттер өчүрүлөт"</string>
<string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Чыгуудан мурун аракеттериңизди сактап же жок кылсаңыз болот"</string>
- <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Сеанстагы аракеттерди азыр жок кылуу үчүн баштапкы абалга келтириңиз, же болбосо чыгуу учурунда аракеттерди сактап же жок кылсаңыз болот"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Сеанстагы аракеттерди азыр өчүрсөңүз болот же чыгып баратып өчүрүп же сактап коюңуз"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Сүрөткө тартуу"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Сүрөт тандаңыз"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Сүрөт тандаңыз"</string>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index 5f42f5c..13ad87c 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -598,7 +598,7 @@
<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>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"ຣີເຊັດເຊດຊັນຂອງແຂກບໍ?"</string>
<string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"ນີ້ຈະເລີ່ມໄລຍະເວລາຂອງແຂກໃໝ່ ແລະ ລຶບແອັບ ແລະ ຂໍ້ມູນທັງໝົດອອກຈາກເຊດຊັນປັດຈຸບັນ"</string>
<string name="guest_exit_dialog_title" msgid="1846494656849381804">"ອອກຈາກໂໝດແຂກບໍ?"</string>
<string name="guest_exit_dialog_message" msgid="1743218864242719783">"ນີ້ຈະລຶບແອັບ ແລະ ຂໍ້ມູນອອກຈາກໄລຍະເວລາຂອງແຂກປັດຈຸບັນ"</string>
@@ -608,7 +608,7 @@
<string name="guest_exit_clear_data_button" msgid="3425812652180679014">"ລຶບ"</string>
<string name="guest_exit_save_data_button" msgid="3690974510644963547">"ບັນທຶກ"</string>
<string name="guest_exit_button" msgid="5774985819191803960">"ອອກຈາກໂໝດແຂກ"</string>
- <string name="guest_reset_button" msgid="2515069346223503479">"ຣີເຊັດໄລຍະເວລາຂອງແຂກ"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"ຣີເຊັດເຊດຊັນຂອງແຂກ"</string>
<string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"ອອກຈາກແຂກ"</string>
<string name="guest_notification_ephemeral" msgid="7263252466950923871">"ການເຄື່ອນໄຫວທັງໝົດຈະຖືກລຶບໃນຕອນອອກ"</string>
<string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"ທ່ານສາມາດບັນທຶກ ຫຼື ລຶບການເຄື່ອນໄຫວຂອງທ່ານໃນຕອນອອກໄດ້"</string>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index a38dace..2a8f685 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -569,7 +569,7 @@
<string name="user_add_user_item_title" msgid="2394272381086965029">"ഉപയോക്താവ്"</string>
<string name="user_add_profile_item_title" msgid="3111051717414643029">"നിയന്ത്രിത പ്രൊഫൈൽ"</string>
<string name="user_add_user_title" msgid="5457079143694924885">"പുതിയ ഉപയോക്താവിനെ ചേർക്കണോ?"</string>
- <string name="user_add_user_message_long" msgid="1527434966294733380">"കൂടുതൽ ഉപയോക്താക്കളെ സൃഷ്ടിച്ചുകൊണ്ട് ഈ ഉപകരണം മറ്റുള്ളവരുമായി നിങ്ങൾക്ക് പങ്കിടാം. ആപ്പുകളും വാൾപേപ്പറുകളും മറ്റും ഉപയോഗിച്ച് ഇഷ്ടാനുസൃതമാക്കാൻ ഓരോ ഉപയോക്താവിനും സാധിക്കും. വൈഫൈ പോലെ എല്ലാവരെയും ബാധിക്കുന്ന ഉപകരണ ക്രമീകരണവും ഉപയോക്താക്കൾക്ക് ക്രമീകരിക്കാം.\n\nനിങ്ങളൊരു പുതിയ ഉപയോക്താവിനെ ചേർക്കുമ്പോൾ, ആ വ്യക്തിക്ക് സ്വന്തമായ ഇടം സജ്ജീകരിക്കേണ്ടതുണ്ട്.\n\n എല്ലാ ഉപയോക്താക്കൾക്കുമായി ആപ്പുകൾ അപ്ഡേറ്റ് ചെയ്യാൻ ഏതൊരു ഉപയോക്താവിനുമാവും. ഉപയോഗസഹായി ക്രമീകരണവും സേവനങ്ങളും പുതിയ ഉപയോക്താവിന് കൈമാറുകയില്ല."</string>
+ <string name="user_add_user_message_long" msgid="1527434966294733380">"കൂടുതൽ ഉപയോക്താക്കളെ സൃഷ്ടിച്ചുകൊണ്ട് ഈ ഉപകരണം മറ്റുള്ളവരുമായി നിങ്ങൾക്ക് പങ്കിടാം. ആപ്പുകളും വാൾപേപ്പറുകളും മറ്റും ഉപയോഗിച്ച് ഇഷ്ടാനുസൃതമാക്കാൻ ഓരോ ഉപയോക്താവിനും സാധിക്കും. വൈഫൈ പോലെ എല്ലാവരെയും ബാധിക്കുന്ന ഉപകരണ ക്രമീകരണവും ഉപയോക്താക്കൾക്ക് അഡ്ജസ്റ്റ് ചെയ്യാം.\n\nനിങ്ങളൊരു പുതിയ ഉപയോക്താവിനെ ചേർക്കുമ്പോൾ, ആ വ്യക്തി സ്വന്തമായ ഇടം സജ്ജീകരിക്കേണ്ടതുണ്ട്.\n\n ഏതെങ്കിലും ഉപയോക്താവിന് എല്ലാ ഉപയോക്താക്കൾക്കുമായി ആപ്പുകൾ അപ്ഡേറ്റ് ചെയ്യാനാകും. ഉപയോഗസഹായി ക്രമീകരണവും സേവനങ്ങളും പുതിയ ഉപയോക്താവിന് കൈമാറുകയില്ല."</string>
<string name="user_add_user_message_short" msgid="3295959985795716166">"നിങ്ങൾ ഒരു പുതിയ ഉപയോക്താവിനെ ചേർക്കുമ്പോൾ, ആ വ്യക്തിയ്ക്ക് അവരുടെ ഇടം സജ്ജീകരിക്കേണ്ടതുണ്ട്.\n\nമറ്റ് എല്ലാ ഉപയോക്താക്കൾക്കുമായി ഏതൊരു ഉപയോക്താവിനും ആപ്പുകൾ അപ്ഡേറ്റ് ചെയ്യാനാവും."</string>
<string name="user_setup_dialog_title" msgid="8037342066381939995">"ഉപയോക്താവിനെ ഇപ്പോൾ സജ്ജീകരിക്കണോ?"</string>
<string name="user_setup_dialog_message" msgid="269931619868102841">"ഉപകരണം എടുത്ത് ഇടം സജ്ജീകരിക്കുന്നതിന് വ്യക്തി ലഭ്യമാണെന്ന് ഉറപ്പാക്കുക"</string>
@@ -607,7 +607,7 @@
<string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"നിലവിലെ സെഷനിൽ നിന്നുള്ള ആക്റ്റിവിറ്റി സംരക്ഷിക്കാം അല്ലെങ്കിൽ എല്ലാ ആപ്പുകളും ഡാറ്റയും ഇല്ലാതാക്കാം"</string>
<string name="guest_exit_clear_data_button" msgid="3425812652180679014">"ഇല്ലാതാക്കുക"</string>
<string name="guest_exit_save_data_button" msgid="3690974510644963547">"സംരക്ഷിക്കുക"</string>
- <string name="guest_exit_button" msgid="5774985819191803960">"അതിഥി മോഡിൽ നിന്ന് പുറത്തുകടക്കുക"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"പുറത്തുകടക്കുക"</string>
<string name="guest_reset_button" msgid="2515069346223503479">"അതിഥി സെഷൻ റീസെറ്റ് ചെയ്യുക"</string>
<string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"അതിഥി മോഡിൽ നിന്ന് പുറത്തുകടക്കുക"</string>
<string name="guest_notification_ephemeral" msgid="7263252466950923871">"പുറത്തുകടക്കുമ്പോൾ എല്ലാ ആക്റ്റിവിറ്റിയും ഇല്ലാതാക്കും"</string>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index 5eef7d3..d61c071 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -569,7 +569,7 @@
<string name="user_add_user_item_title" msgid="2394272381086965029">"Хэрэглэгч"</string>
<string name="user_add_profile_item_title" msgid="3111051717414643029">"Хязгаарлагдсан профайл"</string>
<string name="user_add_user_title" msgid="5457079143694924885">"Шинэ хэрэглэгч нэмэх үү?"</string>
- <string name="user_add_user_message_long" msgid="1527434966294733380">"Та нэмэлт хэрэглэгч үүсгэх замаар бусад хүмүүстэй энэ төхөөрөмжийг хуваалцаж болно. Хэрэглэгч тус бүр апп, дэлгэцийн зураг болон бусад зүйлээ өөрчлөх боломжтой хувийн орон зайтай байдаг. Түүнчлэн хэрэглэгч нь бүх хэрэглэгчид нөлөөлөх боломжтой Wi-Fi зэрэг төхөөрөмжийн тохиргоог өөрчлөх боломжтой.\n\nХэрэв та шинэ хэрэглэгч нэмэх бол тухайн хүн хувийн орон зайгаа бүрдүүлэх ёстой.\n\nХэрэглэгч бүр бусад бүх хэрэглэгчийн өмнөөс апп шинэчилж болно. Хүртээмжийн тохиргоо болон үйлчилгээг шинэ хэрэглэгчид шилжүүлэх боломжгүй байж болзошгүй."</string>
+ <string name="user_add_user_message_long" msgid="1527434966294733380">"Та нэмэлт хэрэглэгч үүсгэх замаар бусад хүмүүстэй энэ төхөөрөмжийг хуваалцаж болно. Хэрэглэгч тус бүр апп, дэлгэцийн зураг болон бусад зүйлээ өөрчлөх боломжтой хувийн орон зайтай байна. Түүнчлэн хэрэглэгч нь бүх хэрэглэгчид нөлөөлөх боломжтой Wi-Fi зэрэг төхөөрөмжийн тохиргоог өөрчлөх боломжтой.\n\nХэрэв та шинэ хэрэглэгч нэмэх бол тухайн хүн хувийн орон зайгаа бүрдүүлэх ёстой.\n\nХэрэглэгч бүр бусад бүх хэрэглэгчийн өмнөөс апп шинэчилж болно. Хандалтын тохиргоо болон үйлчилгээг шинэ хэрэглэгчид шилжүүлэх боломжгүй байж болзошгүй."</string>
<string name="user_add_user_message_short" msgid="3295959985795716166">"Та шинэ хэрэглэгч нэмбэл тухайн хүн өөрийн профайлыг тохируулах шаардлагатай.\n\nАль ч хэрэглэгч бүх хэрэглэгчийн апп-уудыг шинэчлэх боломжтой."</string>
<string name="user_setup_dialog_title" msgid="8037342066381939995">"Хэрэглэгчийг одоо тохируулах уу?"</string>
<string name="user_setup_dialog_message" msgid="269931619868102841">"Хэрэглэгч төхөөрөмжийг авч өөрийн профайлыг тохируулах боломжтой эсэхийг шалгана уу"</string>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index a432531..b1026c0 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -613,7 +613,7 @@
<string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"ဧည့်သည့်မှ ထွက်ရန်"</string>
<string name="guest_notification_ephemeral" msgid="7263252466950923871">"ထွက်သည့်အခါ လုပ်ဆောင်ချက်အားလုံးကို ဖျက်လိုက်မည်"</string>
<string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"ထွက်သည့်အခါ လုပ်ဆောင်ချက်ကို သိမ်းနိုင် (သို့) ဖျက်နိုင်သည်"</string>
- <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"စက်ရှင်လုပ်ဆောင်ချက်ကို ယခုဖျက်ရန် ပြင်ဆင်သတ်မှတ်နိုင်သည် (သို့) ထွက်သည့်အခါ လုပ်ဆောင်ချက်ကို သိမ်းနိုင် (သို့) ဖျက်နိုင်သည်"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"စက်ရှင်လုပ်ဆောင်ချက်ကို ယခုဖျက်ရန် ပြင်ဆင်သတ်မှတ်နိုင်သည် (သို့) ထွက်သည့်အခါ သိမ်းနိုင်၊ ဖျက်နိုင်သည်"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"ဓာတ်ပုံရိုက်ရန်"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"ပုံရွေးရန်"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"ဓာတ်ပုံရွေးရန်"</string>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index a626274..9765892 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -569,7 +569,7 @@
<string name="user_add_user_item_title" msgid="2394272381086965029">"ਵਰਤੋਂਕਾਰ"</string>
<string name="user_add_profile_item_title" msgid="3111051717414643029">"ਪ੍ਰਤਿਬੰਧਿਤ ਪ੍ਰੋਫਾਈਲ"</string>
<string name="user_add_user_title" msgid="5457079143694924885">"ਕੀ ਨਵਾਂ ਵਰਤੋਂਕਾਰ ਸ਼ਾਮਲ ਕਰਨਾ ਹੈ?"</string>
- <string name="user_add_user_message_long" msgid="1527434966294733380">"ਤੁਸੀਂ ਵਾਧੂ ਵਰਤੋਂਕਾਰ ਬਣਾ ਕੇ ਹੋਰਾਂ ਲੋਕਾਂ ਨਾਲ ਇਹ ਡੀਵਾਈਸ ਸਾਂਝਾ ਕਰ ਸਕਦੇ ਹੋ। ਹਰੇਕ ਵਰਤੋਂਕਾਰ ਦੀ ਆਪਣੀ ਖੁਦ ਦੀ ਜਗ੍ਹਾ ਹੁੰਦੀ ਹੈ, ਜਿਸਨੂੰ ਉਹ ਐਪਾਂ ਅਤੇ ਵਾਲਪੇਪਰ ਆਦਿ ਨਾਲ ਵਿਉਂਤਬੱਧ ਕਰ ਸਕਦੇ ਹਨ। ਵਰਤੋਂਕਾਰ ਡੀਵਾਈਸ ਸੈਟਿੰਗਾਂ ਵੀ ਵਿਵਸਥਿਤ ਕਰ ਸਕਦੇ ਹਨ ਜਿਵੇਂ ਵਾਈ‑ਫਾਈ ਜੋ ਹਰੇਕ \'ਤੇ ਅਸਰ ਪਾਉਂਦੀ ਹੈ।\n\nਜਦੋਂ ਤੁਸੀਂ ਇੱਕ ਨਵਾਂ ਵਰਤੋਂਕਾਰ ਸ਼ਾਮਲ ਕਰਦੇ ਹੋ, ਉਸ ਵਿਅਕਤੀ ਨੂੰ ਆਪਣੀ ਜਗ੍ਹਾ ਸੈੱਟ ਅੱਪ ਕਰਨੀ ਪੈਂਦੀ ਹੈ।\n\nਕੋਈ ਵੀ ਵਰਤੋਂਕਾਰ ਬਾਕੀ ਸਾਰੇ ਵਰਤੋਂਕਾਰਾਂ ਦੀਆਂ ਐਪਾਂ ਨੂੰ ਅੱਪਡੇਟ ਕਰ ਸਕਦਾ ਹੈ। ਸ਼ਾਇਦ ਪਹੁੰਚਯੋਗਤਾ ਸੈਟਿੰਗਾਂ ਅਤੇ ਸੇਵਾਵਾਂ ਨੂੰ ਕਿਸੇ ਨਵੇਂ ਵਰਤੋਂਕਾਰ ਨੂੰ ਟ੍ਰਾਂਸਫਰ ਨਾ ਕੀਤਾ ਜਾ ਸਕੇ।"</string>
+ <string name="user_add_user_message_long" msgid="1527434966294733380">"ਤੁਸੀਂ ਵਾਧੂ ਵਰਤੋਂਕਾਰ ਬਣਾ ਕੇ ਹੋਰਾਂ ਲੋਕਾਂ ਨਾਲ ਇਹ ਡੀਵਾਈਸ ਸਾਂਝਾ ਕਰ ਸਕਦੇ ਹੋ। ਹਰੇਕ ਵਰਤੋਂਕਾਰ ਦੀ ਆਪਣੀ ਖੁਦ ਦੀ ਜਗ੍ਹਾ ਹੁੰਦੀ ਹੈ, ਜਿਸਨੂੰ ਉਹ ਐਪਾਂ ਅਤੇ ਵਾਲਪੇਪਰ ਆਦਿ ਨਾਲ ਵਿਉਂਤਬੱਧ ਕਰ ਸਕਦੇ ਹਨ। ਵਰਤੋਂਕਾਰ ਵਾਈ-ਫਾਈ ਵਰਗੀਆਂ ਡੀਵਾਈਸ ਸੈਟਿੰਗਾਂ ਨੂੰ ਵੀ ਵਿਵਸਥਿਤ ਕਰ ਸਕਦੇ ਹਨ, ਜਿਸ ਨਾਲ ਹਰੇਕ ਵਰਤੋਂਕਾਰ \'ਤੇ ਅਸਰ ਪੈਂਦਾ ਹੈ।\n\nਜਦੋਂ ਤੁਸੀਂ ਇੱਕ ਨਵਾਂ ਵਰਤੋਂਕਾਰ ਸ਼ਾਮਲ ਕਰਦੇ ਹੋ, ਉਸ ਵਿਅਕਤੀ ਨੂੰ ਆਪਣੀ ਜਗ੍ਹਾ ਸੈੱਟ ਅੱਪ ਕਰਨੀ ਪੈਂਦੀ ਹੈ।\n\nਕੋਈ ਵੀ ਵਰਤੋਂਕਾਰ ਬਾਕੀ ਸਾਰੇ ਵਰਤੋਂਕਾਰਾਂ ਦੀਆਂ ਐਪਾਂ ਨੂੰ ਅੱਪਡੇਟ ਕਰ ਸਕਦਾ ਹੈ। ਸ਼ਾਇਦ ਪਹੁੰਚਯੋਗਤਾ ਸੈਟਿੰਗਾਂ ਅਤੇ ਸੇਵਾਵਾਂ ਨੂੰ ਕਿਸੇ ਨਵੇਂ ਵਰਤੋਂਕਾਰ ਨੂੰ ਟ੍ਰਾਂਸਫਰ ਨਾ ਕੀਤਾ ਜਾ ਸਕੇ।"</string>
<string name="user_add_user_message_short" msgid="3295959985795716166">"ਜਦੋਂ ਤੁਸੀਂ ਇੱਕ ਨਵਾਂ ਵਰਤੋਂਕਾਰ ਸ਼ਾਮਲ ਕਰਦੇ ਹੋ, ਉਸ ਵਿਅਕਤੀ ਨੂੰ ਆਪਣੀ ਜਗ੍ਹਾ ਸੈੱਟਅੱਪ ਕਰਨ ਦੀ ਲੋੜ ਹੁੰਦੀ ਹੈ।\n\nਕੋਈ ਵੀ ਵਰਤੋਂਕਾਰ ਹੋਰ ਸਾਰੇ ਵਰਤੋਂਕਾਰਾਂ ਦੀਆਂ ਐਪਾਂ ਨੂੰ ਅੱਪਡੇਟ ਕਰ ਸਕਦਾ ਹੈ।"</string>
<string name="user_setup_dialog_title" msgid="8037342066381939995">"ਕੀ ਹੁਣ ਵਰਤੋਂਕਾਰ ਸੈੱਟ ਅੱਪ ਕਰਨਾ ਹੈ?"</string>
<string name="user_setup_dialog_message" msgid="269931619868102841">"ਇਹ ਪੱਕਾ ਕਰੋ ਕਿ ਵਿਅਕਤੀ ਡੀਵਾਈਸ ਵਰਤਣ ਅਤੇ ਆਪਣੀ ਜਗ੍ਹਾ ਦੇ ਸੈੱਟ ਅੱਪ ਲਈ ਉਪਲਬਧ ਹੈ"</string>
@@ -611,8 +611,8 @@
<string name="guest_reset_button" msgid="2515069346223503479">"ਮਹਿਮਾਨ ਸੈਸ਼ਨ ਨੂੰ ਰੀਸੈੱਟ ਕਰੋ"</string>
<string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"ਮਹਿਮਾਨ ਮੋਡ ਤੋਂ ਬਾਹਰ ਜਾਓ"</string>
<string name="guest_notification_ephemeral" msgid="7263252466950923871">"ਬਾਹਰ ਜਾਣ \'ਤੇ ਸਾਰੀ ਸਰਗਰਮੀ ਮਿਟਾਈ ਜਾਵੇਗੀ"</string>
- <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"ਤੁਸੀਂ ਬਾਹਰ ਜਾਣ \'ਤੇ ਆਪਣੀ ਸਭ ਸਰਗਰਮੀ ਰੱਖਿਅਤ ਕਰ ਜਾਂ ਮਿਟਾ ਸਕਦੇ ਹੋ"</string>
- <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"ਸੈਸ਼ਨ ਦੀ ਸਰਗਰਮੀ ਮਿਟਾਉਣ ਹੁਣੇ ਲਈ ਰੀਸੈੱਟ ਕਰੋ ਜਾਂ ਤੁਸੀਂ ਬਾਹਰ ਜਾਣ \'ਤੇ ਸਰਗਰਮੀ ਨੂੰ ਰੱਖਿਅਤ ਕਰ ਜਾਂ ਮਿਟਾ ਸਕਦੇ ਹੋ"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"ਤੁਸੀਂ ਬਾਹਰ ਜਾਣ \'ਤੇ ਆਪਣੀ ਸਰਗਰਮੀ ਰੱਖਿਅਤ ਕਰ ਜਾਂ ਮਿਟਾ ਸਕਦੇ ਹੋ"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"ਸੈਸ਼ਨ ਦੀ ਸਰਗਰਮੀ ਹੁਣੇ ਮਿਟਾਉਣ ਲਈ ਰੀਸੈੱਟ ਕਰੋ ਜਾਂ ਤੁਸੀਂ ਬਾਹਰ ਜਾਣ \'ਤੇ ਸਰਗਰਮੀ ਨੂੰ ਰੱਖਿਅਤ ਕਰ ਜਾਂ ਮਿਟਾ ਸਕਦੇ ਹੋ"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"ਇੱਕ ਫ਼ੋਟੋ ਖਿੱਚੋ"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"ਕੋਈ ਚਿੱਤਰ ਚੁਣੋ"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"ਫ਼ੋਟੋ ਚੁਣੋ"</string>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index 658a63b..bf0c246 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -611,8 +611,8 @@
<string name="guest_reset_button" msgid="2515069346223503479">"Zresetuj sesję gościa"</string>
<string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Zakończ tryb gościa"</string>
<string name="guest_notification_ephemeral" msgid="7263252466950923871">"Cała aktywność zostanie usunięta po zamknięciu"</string>
- <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Możesz zapisać lub usunąć swoją aktywność podczas zamykania"</string>
- <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Zresetuj, aby usunąć aktywność w sesji w tym momencie. Możesz też ją zapisać lub usunąć podczas zamykania"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Możesz zapisać lub usunąć swoją aktywność podczas zamykania."</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Zresetuj, aby teraz usunąć aktywność z tej sesji. Możesz też ją zapisać lub usunąć podczas zamykania sesji."</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Zrób zdjęcie"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Wybierz obraz"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Wybierz zdjęcie"</string>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index 06faf68..f893d63 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -612,7 +612,7 @@
<string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Sair do modo visitante"</string>
<string name="guest_notification_ephemeral" msgid="7263252466950923871">"Todas as atividades serão excluídas ao sair"</string>
<string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Você pode salvar ou excluir sua atividade ao sair"</string>
- <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Faça uma redefinição para excluir a atividade da sessão agora. Você também pode salvar ou excluir a atividade ao sair"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Redefina para excluir a atividade da sessão agora. Salve ou exclua a atividade ao sair"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Tirar uma foto"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Escolher uma imagem"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Selecionar foto"</string>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index 4fc5728..9491126 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -569,7 +569,7 @@
<string name="user_add_user_item_title" msgid="2394272381086965029">"Utilizador"</string>
<string name="user_add_profile_item_title" msgid="3111051717414643029">"Perfil restrito"</string>
<string name="user_add_user_title" msgid="5457079143694924885">"Adicionar novo utilizador?"</string>
- <string name="user_add_user_message_long" msgid="1527434966294733380">"Pode partilhar este dispositivo com outras pessoas ao criar utilizadores adicionais. Cada utilizador possui o seu próprio espaço, que pode ser personalizado com aplicações, imagens de fundo, etc. Os utilizadores também podem ajustar as definições do dispositivo, como o Wi‑Fi, que afetam os restantes utilizadores.\n\nAo adicionar um novo utilizador, essa pessoa tem de configurar o respetivo espaço.\n\nQualquer utilizador pode atualizar aplicações para todos os outros utilizadores. Os serviços e as definições de acessibilidade podem não ser transferidos para o novo utilizador."</string>
+ <string name="user_add_user_message_long" msgid="1527434966294733380">"Pode partilhar este dispositivo com outras pessoas ao criar utilizadores adicionais. Cada utilizador possui o seu próprio espaço, que pode ser personalizado com apps, imagens de fundo, etc. Os utilizadores também podem ajustar as definições do dispositivo, como o Wi‑Fi, que afetam os restantes utilizadores.\n\nAo adicionar um novo utilizador, essa pessoa tem de configurar o respetivo espaço.\n\nQualquer utilizador pode atualizar apps para todos os outros utilizadores. Os serviços e as definições de acessibilidade podem não ser transferidos para o novo utilizador."</string>
<string name="user_add_user_message_short" msgid="3295959985795716166">"Ao adicionar um novo utilizador, essa pessoa tem de configurar o respetivo espaço.\n\nQualquer utilizador pode atualizar aplicações para todos os outros utilizadores."</string>
<string name="user_setup_dialog_title" msgid="8037342066381939995">"Configurar o utilizador agora?"</string>
<string name="user_setup_dialog_message" msgid="269931619868102841">"Certifique-se de que a pessoa está disponível para levar o dispositivo e configurar o seu espaço"</string>
@@ -607,12 +607,12 @@
<string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Pode guardar a atividade da sessão atual ou eliminar todas as apps e dados"</string>
<string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Eliminar"</string>
<string name="guest_exit_save_data_button" msgid="3690974510644963547">"Guardar"</string>
- <string name="guest_exit_button" msgid="5774985819191803960">"Sair do modo de convidado"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"Sair do modo convidado"</string>
<string name="guest_reset_button" msgid="2515069346223503479">"Repor sessão de convidado"</string>
<string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Sair do modo de convidado"</string>
<string name="guest_notification_ephemeral" msgid="7263252466950923871">"Toda a atividade é eliminada ao sair"</string>
<string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Pode guardar ou eliminar a sua atividade ao sair"</string>
- <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Reponha para eliminar agora a atividade da sessão. Em alternativa, pode guardar ou eliminar a atividade ao sair"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Reponha para eliminar agora a atividade da sessão. Pode ainda guardar ou eliminar a atividade ao sair"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Tirar uma foto"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Escolher uma imagem"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Selecionar foto"</string>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index 06faf68..f893d63 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -612,7 +612,7 @@
<string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Sair do modo visitante"</string>
<string name="guest_notification_ephemeral" msgid="7263252466950923871">"Todas as atividades serão excluídas ao sair"</string>
<string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Você pode salvar ou excluir sua atividade ao sair"</string>
- <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Faça uma redefinição para excluir a atividade da sessão agora. Você também pode salvar ou excluir a atividade ao sair"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Redefina para excluir a atividade da sessão agora. Salve ou exclua a atividade ao sair"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Tirar uma foto"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Escolher uma imagem"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Selecionar foto"</string>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index 2910ebc..df9e883 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -612,7 +612,7 @@
<string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Выйти из гостевого режима"</string>
<string name="guest_notification_ephemeral" msgid="7263252466950923871">"История будет удалена сразу после выхода."</string>
<string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"При выходе вы можете сохранить или удалить историю."</string>
- <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Сбросьте историю сеанса прямо сейчас и удалите или сохраните ее при выходе."</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Можно сбросить историю сеанса прямо сейчас, либо удалить или сохранить ее при выходе."</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Сделать снимок"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Выбрать фото"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Выбрать фотографию"</string>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index 5ad8071..897fcf9 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -280,7 +280,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"Certifikácia bezdrôtového zobrazenia"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Podrobné denníky Wi‑Fi"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Pribrzdiť vyhľadávanie sietí Wi‑Fi"</string>
- <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Randomizácia dočasnej adresy MAC siete Wi‑Fi"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Randomizovať dočasnú adresu MAC siete Wi‑Fi"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"Mobilné dáta ponechať vždy aktívne"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"Hardvérová akcelerácia tetheringu"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Zobrazovať zariadenia Bluetooth bez názvov"</string>
@@ -381,7 +381,7 @@
<string name="debug_layout_summary" msgid="8825829038287321978">"Zobraziť vo výstrižku ohraničenie, okraje a pod."</string>
<string name="force_rtl_layout_all_locales" msgid="8690762598501599796">"Rozloženie sprava doľava"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="6663016859517239880">"Vynútiť pre všetky jazyky rozloženie obrazovky sprava doľava"</string>
- <string name="window_blurs" msgid="6831008984828425106">"Povolenie rozmazania na úrovni okna"</string>
+ <string name="window_blurs" msgid="6831008984828425106">"Povoliť rozmazanie na úrovni okna"</string>
<string name="force_msaa" msgid="4081288296137775550">"Vynútiť 4x MSAA"</string>
<string name="force_msaa_summary" msgid="9070437493586769500">"Povoliť 4x MSAA v aplikáciách OpenGL ES 2.0"</string>
<string name="show_non_rect_clip" msgid="7499758654867881817">"Ladiť operácie s neobdĺžnikovými výstrižkami"</string>
@@ -600,11 +600,11 @@
<string name="guest_resetting" msgid="7822120170191509566">"Relácia hosťa sa resetuje…"</string>
<string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"Chcete resetovať reláciu hosťa?"</string>
<string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"Týmto sa spustí nová relácia hosťa a odstránia sa všetky aplikácie a údaje z aktuálnej relácie"</string>
- <string name="guest_exit_dialog_title" msgid="1846494656849381804">"Chcete skončiť režim pre hostí?"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"Chcete ukončiť režim pre hostí?"</string>
<string name="guest_exit_dialog_message" msgid="1743218864242719783">"Ukončí sa režim pre hostí a odstránia sa aplikácie a údaje z relácie hosťa"</string>
<string name="guest_exit_dialog_button" msgid="1736401897067442044">"Ukončiť"</string>
<string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Chcete uložiť aktivitu hosťa?"</string>
- <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Aktivitu v aktuálnej relácii uložte alebo odstráňte všetky aplikácie a údaje"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Môžte uložiť aktivitu aktuálnej relácie alebo odstrániť všetky aplikácie a údaje"</string>
<string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Odstrániť"</string>
<string name="guest_exit_save_data_button" msgid="3690974510644963547">"Uložiť"</string>
<string name="guest_exit_button" msgid="5774985819191803960">"Ukončiť režim pre hostí"</string>
@@ -612,7 +612,7 @@
<string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Ukončiť režim pre hostí"</string>
<string name="guest_notification_ephemeral" msgid="7263252466950923871">"Pri ukončení sa všetka aktivita odstráni"</string>
<string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Aktivitu môžete pri ukončení uložiť alebo odstrániť"</string>
- <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Resetovaním ihneď odstráňte aktivitu relácie alebo ju uložte či odstráňte pri ukončení relácie"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Resetovaním ihneď odstránite aktivitu relácie alebo ju uložte či odstráňte pri ukončení relácie"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Odfotiť"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Vybrať obrázok"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Vybrať fotku"</string>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index 34bfa8e..1b97e08 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -568,7 +568,7 @@
<string name="user_add_profile_item_summary" msgid="5418602404308968028">"Dostop do aplikacij in vsebine iz vašega računa lahko omejite"</string>
<string name="user_add_user_item_title" msgid="2394272381086965029">"Uporabnik"</string>
<string name="user_add_profile_item_title" msgid="3111051717414643029">"Omejen profil"</string>
- <string name="user_add_user_title" msgid="5457079143694924885">"Dodajanje novega uporabnika?"</string>
+ <string name="user_add_user_title" msgid="5457079143694924885">"Želite dodati uporabnika?"</string>
<string name="user_add_user_message_long" msgid="1527434966294733380">"To napravo lahko delite z drugimi tako, da ustvarite dodatne uporabnike. Vsak ima svoj prostor, ki ga lahko prilagodi z aplikacijami, ozadji in drugim. Uporabniki lahko tudi prilagodijo nastavitve naprave, ki vplivajo na vse, na primer nastavitve omrežja Wi-Fi.\n\nKo dodate novega uporabnika, mora ta nastaviti svoj prostor.\n\nVsak uporabnik lahko posodobi aplikacije za vse druge uporabnike. Nastavitve in storitve funkcij za ljudi s posebnimi potrebami morda ne bodo prenesene v prostor novega uporabnika."</string>
<string name="user_add_user_message_short" msgid="3295959985795716166">"Ko dodate novega uporabnika, mora ta nastaviti svoj prostor.\n\nVsak uporabnik lahko posodobi aplikacije za vse druge uporabnike."</string>
<string name="user_setup_dialog_title" msgid="8037342066381939995">"Želite uporabnika nastaviti zdaj?"</string>
@@ -600,7 +600,7 @@
<string name="guest_resetting" msgid="7822120170191509566">"Ponastavljanje gosta …"</string>
<string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"Želite ponastaviti sejo gosta?"</string>
<string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"S tem boste začeli novo sejo gosta ter izbrisali vse aplikacije in podatke v trenutni seji."</string>
- <string name="guest_exit_dialog_title" msgid="1846494656849381804">"Zapri način za goste"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"Želite zapreti način za goste?"</string>
<string name="guest_exit_dialog_message" msgid="1743218864242719783">"S tem boste izbrisali aplikacije in podatke v trenutni seji gosta."</string>
<string name="guest_exit_dialog_button" msgid="1736401897067442044">"Zapri"</string>
<string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Želite shraniti dejavnost gosta?"</string>
@@ -610,9 +610,9 @@
<string name="guest_exit_button" msgid="5774985819191803960">"Zapri način za goste"</string>
<string name="guest_reset_button" msgid="2515069346223503479">"Ponastavi sejo gosta"</string>
<string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Zapri sejo gosta"</string>
- <string name="guest_notification_ephemeral" msgid="7263252466950923871">"Ko zaprete sejo, bo vsa dejavnost izbrisana."</string>
- <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Ko zaprete sejo, lahko shranite ali izbrišete dejavnost."</string>
- <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Ponastavite, če želite dejavnost v seji izbrisati zdaj, lahko pa jo shranite ali izbrišete, ko zaprete sejo."</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"Ko zaprete način za goste, bo vsa dejavnost izbrisana."</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Ob zaprtju načina lahko shranite ali izbrišete dejavnost."</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Ponastavite za izbris dejavnosti v seji zdaj, lahko pa jo shranite ali izbrišete, ko zaprete način za goste."</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Fotografiranje"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Izberi sliko"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Izbira fotografije"</string>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index 381cd97..5a3be35 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -594,7 +594,7 @@
<string name="guest_exit_guest" msgid="5908239569510734136">"Уклони госта"</string>
<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_remove_guest_dialog_title" msgid="4548511006624088072">"Желите да уклоните госта?"</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>
@@ -612,7 +612,7 @@
<string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Изађи из режима госта"</string>
<string name="guest_notification_ephemeral" msgid="7263252466950923871">"Све активности ће бити избрисане при излазу"</string>
<string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Можете да сачувате или избришете активности при излазу"</string>
- <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Ресетујете да бисте избрисали активности сесије одмах или можете да сачувате или избришете активности при излазу"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Ресетујете за брисање активности сесије, или сачувајте или избришите активности при излазу"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Сликај"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Одабери слику"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Изаберите слику"</string>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index 683619a..c2fa3f7 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -569,7 +569,7 @@
<string name="user_add_user_item_title" msgid="2394272381086965029">"Användare"</string>
<string name="user_add_profile_item_title" msgid="3111051717414643029">"Begränsad profil"</string>
<string name="user_add_user_title" msgid="5457079143694924885">"Lägga till ny användare?"</string>
- <string name="user_add_user_message_long" msgid="1527434966294733380">"Du kan dela enheten med andra om du skapar flera användare. Alla användare får sitt eget utrymme som de kan anpassa som de vill med appar, bakgrund och så vidare. Användarna kan även ändra enhetsinställningar som påverkar alla, till exempel Wi‑Fi.\n\nNär du lägger till en ny användare måste han eller hon konfigurera sitt utrymme.\n\nAlla användare kan uppdatera appar för samtliga användares räkning. Tillgänglighetsinställningar och tjänster kanske inte överförs till den nya användaren."</string>
+ <string name="user_add_user_message_long" msgid="1527434966294733380">"Du kan dela enheten med andra om du skapar flera användare. Alla användare får sitt eget utrymme som de kan anpassa som de vill med appar, bakgrund och så vidare. Användarna kan även ändra enhetsinställningar som påverkar alla, till exempel wifi.\n\nNär du lägger till en ny användare måste han eller hon konfigurera sitt utrymme.\n\nAlla användare kan uppdatera appar för samtliga användares räkning. Tillgänglighetsinställningar och tjänster kanske inte överförs till den nya användaren."</string>
<string name="user_add_user_message_short" msgid="3295959985795716166">"När du lägger till en ny användare måste den personen konfigurera sitt utrymme.\n\nAlla användare kan uppdatera appar för samtliga användares räkning."</string>
<string name="user_setup_dialog_title" msgid="8037342066381939995">"Konfigurera användare nu?"</string>
<string name="user_setup_dialog_message" msgid="269931619868102841">"Kontrollera att personen finns tillgänglig för att konfigurera sitt utrymme på enheten"</string>
@@ -612,7 +612,7 @@
<string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Avsluta gästsession"</string>
<string name="guest_notification_ephemeral" msgid="7263252466950923871">"All aktivitet raderas när du avslutar"</string>
<string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Du kan spara eller radera aktivitet när du avslutar"</string>
- <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Återställ om du vill radera sessionsaktiviteten nu. Du kan också spara eller radera aktivitet när du avslutar"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Återställ om du vill radera sessionsaktiviteten nu, eller spara eller radera aktivitet när du avslutar"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Ta ett foto"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Välj en bild"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Välj foto"</string>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index f6612b8..9fefab3 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -583,7 +583,7 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"ప్రొఫైల్ సమాచారం"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"మీరు పరిమితం చేయబడిన ప్రొఫైల్ను క్రియేట్ చేయడానికి ముందు, మీ యాప్లు మరియు వ్యక్తిగత డేటాను రక్షించడానికి స్క్రీన్ లాక్ను సెటప్ చేయాల్సి ఉంటుంది."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"లాక్ను సెట్ చేయి"</string>
- <string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g>కు స్విచ్ చేయి"</string>
+ <string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g>కు స్విచ్ చేయి"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"కొత్త యూజర్ను క్రియేట్ చేస్తోంది…"</string>
<string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"కొత్త అతిథిని క్రియేట్ చేస్తోంది…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"కొత్త యూజర్ను క్రియేట్ చేయడం విఫలమైంది"</string>
@@ -599,7 +599,7 @@
<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>
- <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"ఇది కొత్త గెస్ట్ సెషన్ను ప్రారంభిస్తుంది, ప్రస్తుత సెషన్ నుండి అన్ని యాప్లు, డేటాను తొలగించండి"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"ఇది కొత్త గెస్ట్ సెషన్ను ప్రారంభిస్తుంది, ప్రస్తుత సెషన్ నుండి అన్ని యాప్లు, డేటాను తొలగిస్తుంది."</string>
<string name="guest_exit_dialog_title" msgid="1846494656849381804">"గెస్ట్ మోడ్ నిష్క్రమించాలా?"</string>
<string name="guest_exit_dialog_message" msgid="1743218864242719783">"ఇది ప్రస్తుత గెస్ట్ సెషన్ నుండి యాప్లు, డేటాను తొలగిస్తుంది"</string>
<string name="guest_exit_dialog_button" msgid="1736401897067442044">"నిష్క్రమించండి"</string>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index 7299ab5..4783ac9 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -569,7 +569,7 @@
<string name="user_add_user_item_title" msgid="2394272381086965029">"ผู้ใช้"</string>
<string name="user_add_profile_item_title" msgid="3111051717414643029">"โปรไฟล์ที่ถูกจำกัด"</string>
<string name="user_add_user_title" msgid="5457079143694924885">"ต้องการเพิ่มผู้ใช้ใหม่ใช่ไหม"</string>
- <string name="user_add_user_message_long" msgid="1527434966294733380">"คุณมีสิทธิ์แชร์อุปกรณ์นี้กับผู้อื่นได้โดยการเพิ่มผู้ใช้ ซึ่งแต่ละคนจะมีพื้นที่ของตนเองและปรับใช้กับแอป วอลเปเปอร์ และรายการอื่นๆ ได้ อีกทั้งยังปรับการตั้งค่าอุปกรณ์ได้ด้วย เช่น Wi‑Fi ซึ่งจะมีผลกับทุกคน\n\nเมื่อคุณเพิ่มผู้ใช้ใหม่ ผู้ใช้ดังกล่าวจะต้องตั้งค่าพื้นที่ของตน\n\nผู้ใช้ทุกคนมีสิทธิ์อัปเดตแอปให้กับผู้ใช้รายอื่น การตั้งค่าและบริการสำหรับการช่วยเหลือพิเศษอาจโอนไปยังผู้ใช้ใหม่ไม่ได้"</string>
+ <string name="user_add_user_message_long" msgid="1527434966294733380">"คุณมีสิทธิ์แชร์อุปกรณ์นี้กับผู้อื่นได้โดยการเพิ่มผู้ใช้ แต่ละคนจะมีพื้นที่ของตนเองซึ่งปรับใช้กับแอป วอลเปเปอร์ และรายการอื่นๆ ได้ อีกทั้งยังปรับการตั้งค่าอุปกรณ์ได้ด้วย เช่น Wi‑Fi ซึ่งจะมีผลกับทุกคน\n\nเมื่อคุณเพิ่มผู้ใช้ใหม่ ผู้ใช้ดังกล่าวจะต้องตั้งค่าพื้นที่ของตน\n\nผู้ใช้ทุกคนมีสิทธิ์อัปเดตแอปให้ผู้ใช้รายอื่น การตั้งค่าและบริการสำหรับการช่วยเหลือพิเศษอาจโอนไปยังผู้ใช้ใหม่ไม่ได้"</string>
<string name="user_add_user_message_short" msgid="3295959985795716166">"เมื่อคุณเพิ่มผู้ใช้ใหม่ ผู้ใช้ดังกล่าวจะต้องตั้งค่าพื้นที่ของตนเอง\n\nผู้ใช้ทุกคนสามารถอัปเดตแอปสำหรับผู้ใช้รายอื่นได้"</string>
<string name="user_setup_dialog_title" msgid="8037342066381939995">"ตั้งค่าผู้ใช้เลยไหม"</string>
<string name="user_setup_dialog_message" msgid="269931619868102841">"ตรวจสอบว่าบุคคลดังกล่าวสามารถนำอุปกรณ์ไปตั้งค่าพื้นที่ของตนได้"</string>
@@ -598,21 +598,21 @@
<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>
- <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"การดำเนินการนี้จะเริ่มเซสชันผู้มาเยือนใหม่ และจะลบแอปและข้อมูลทั้งหมดจากเซสชันปัจจุบัน"</string>
- <string name="guest_exit_dialog_title" msgid="1846494656849381804">"ออกจากโหมดผู้มาเยือนไหม"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"รีเซ็ตเซสชันผู้ใช้ชั่วคราวไหม"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"การดำเนินการนี้จะเริ่มเซสชันผู้ใช้ชั่วคราวใหม่ และจะลบแอปและข้อมูลทั้งหมดจากเซสชันปัจจุบัน"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"ออกจากโหมดผู้ใช้ชั่วคราวไหม"</string>
<string name="guest_exit_dialog_message" msgid="1743218864242719783">"การดำเนินการนี้จะลบแอปและข้อมูลออกจากเซสชันผู้มาเยือนในปัจจุบัน"</string>
<string name="guest_exit_dialog_button" msgid="1736401897067442044">"ออก"</string>
- <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"บันทึกกิจกรรมของผู้มาเยือนไหม"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"บันทึกกิจกรรมของผู้ใช้ชั่วคราวไหม"</string>
<string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"คุณสามารถบันทึกกิจกรรมจากเซสชันปัจจุบันหรือจะลบแอปและข้อมูลทั้งหมดก็ได้"</string>
<string name="guest_exit_clear_data_button" msgid="3425812652180679014">"ลบ"</string>
<string name="guest_exit_save_data_button" msgid="3690974510644963547">"บันทึก"</string>
- <string name="guest_exit_button" msgid="5774985819191803960">"ออกจากโหมดผู้มาเยือน"</string>
- <string name="guest_reset_button" msgid="2515069346223503479">"รีเซ็ตเซสชันผู้มาเยือน"</string>
- <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"ออกจากโหมดผู้มาเยือน"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"ออกจากโหมดผู้ใช้ชั่วคราว"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"รีเซ็ตเซสชันผู้ใช้ชั่วคราว"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"ออกจากโหมดผู้ใช้ชั่วคราว"</string>
<string name="guest_notification_ephemeral" msgid="7263252466950923871">"ระบบจะลบกิจกรรมทั้งหมดเมื่อออก"</string>
<string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"คุณสามารถบันทึกหรือลบกิจกรรมเมื่อออก"</string>
- <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"รีเซ็ตเพื่อลบกิจกรรมของเซสชันตอนนี้เลย หรือจะบันทึกหรือลบกิจกรรมเมื่อออกก็ได้"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"รีเซ็ตเพื่อลบกิจกรรมของเซสชันตอนนี้เลย หรือจะบันทึกหรือลบกิจกรรมเมื่อออกก็ได้"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"ถ่ายรูป"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"เลือกรูปภาพ"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"เลือกรูปภาพ"</string>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index 24c6d69..d558b09 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -612,7 +612,7 @@
<string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Misafir modundan çık"</string>
<string name="guest_notification_ephemeral" msgid="7263252466950923871">"Çıkış yapıldığında tüm etkinlikler silinir"</string>
<string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Etkinliklerinizi çıkarken kaydedebilir veya silebilirsiniz"</string>
- <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Oturum etkinliklerini hemen silmek için sıfırlayın. Etkinlikleri çıkarken kaydetmeyi veya silmeyi de tercih edebilirsiniz"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Oturum etkinliklerini silmek için sıfırlayabilir ya da çıkarken kaydedebilir veya silebilirsiniz"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Fotoğraf çek"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Resim seç"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Fotoğraf seç"</string>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index cab4add..08dcead 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -612,7 +612,7 @@
<string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Вийти з режиму гостя"</string>
<string name="guest_notification_ephemeral" msgid="7263252466950923871">"Під час виходу буде видалено всі дії"</string>
<string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Під час виходу можна зберегти або видалити ваші дії"</string>
- <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Скиньте, щоб зараз видалити дії під час сеансу. Ви також можете зберегти чи видалити дії під час виходу."</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Можна скинути історію сеансу просто зараз або видалити чи зберегти її під час виходу."</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Зробити фотографію"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Вибрати зображення"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Вибрати фотографію"</string>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index 77530b6..807c7d7 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -599,7 +599,7 @@
<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>
- <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"یہ ایک نیا مہمان سیشن شروع کرے گا اور موجودہ سیشن سے تمام ایپس اور ڈیٹا کو حذف کر دے گا"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"اس سے ایک نیا مہمان سیشن شروع ہو گا اور موجودہ سیشن سے تمام ایپس اور ڈیٹا حذف ہو جائے گا"</string>
<string name="guest_exit_dialog_title" msgid="1846494656849381804">"مہمان وضع سے باہر نکلیں؟"</string>
<string name="guest_exit_dialog_message" msgid="1743218864242719783">"یہ موجودہ مہمان سیشن سے ایپس اور ڈیٹا کو حذف کر دے گا"</string>
<string name="guest_exit_dialog_button" msgid="1736401897067442044">"باہر نکلیں"</string>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index c003838..92f987d 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -604,7 +604,7 @@
<string name="guest_exit_dialog_message" msgid="1743218864242719783">"Bunda joriy mehmon seansidagi ilova va ularning maʼlumotlari tozalanadi"</string>
<string name="guest_exit_dialog_button" msgid="1736401897067442044">"Chiqish"</string>
<string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Mehmon faoliyati saqlansinmi?"</string>
- <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Joriy seansdagi faoliyatni saqlash yoki barcha ilova va maʼlumotlarni tozalash mumkin"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Joriy seansdagi faoliyatni saqlash yoki barcha ilova va maʼlumotlarni oʻchirib tashlashingiz mumkin"</string>
<string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Oʻchirish"</string>
<string name="guest_exit_save_data_button" msgid="3690974510644963547">"Saqlash"</string>
<string name="guest_exit_button" msgid="5774985819191803960">"Mehmon rejimidan chiqish"</string>
diff --git a/packages/SettingsLib/res/values-vi/arrays.xml b/packages/SettingsLib/res/values-vi/arrays.xml
index ea5230c..4cf8ff4 100644
--- a/packages/SettingsLib/res/values-vi/arrays.xml
+++ b/packages/SettingsLib/res/values-vi/arrays.xml
@@ -178,13 +178,13 @@
<item msgid="2983219471251787208">"8 MB/vùng đệm nhật ký"</item>
</string-array>
<string-array name="select_logpersist_titles">
- <item msgid="704720725704372366">"Tắt"</item>
+ <item msgid="704720725704372366">"Đang tắt"</item>
<item msgid="6014837961827347618">"Tất cả"</item>
<item msgid="7387060437894578132">"Tất cả trừ đài"</item>
<item msgid="7300881231043255746">"chỉ kernel"</item>
</string-array>
<string-array name="select_logpersist_summaries">
- <item msgid="97587758561106269">"Tắt"</item>
+ <item msgid="97587758561106269">"Đang tắt"</item>
<item msgid="7126170197336963369">"Tất cả lần tải nhật ký"</item>
<item msgid="7167543126036181392">"Tất cả trừ lần tải nhật ký qua đài"</item>
<item msgid="5135340178556563979">"chỉ vùng đệm nhật ký kernel"</item>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index a6f738f..4ea7044 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -668,7 +668,7 @@
<string name="allow_turn_screen_on" msgid="6194845766392742639">"允许开启屏幕"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"允许应用开启屏幕。如获授权,该应用便可在您未明确表达意愿的情况下随时开启屏幕。"</string>
<string name="bt_le_audio_scan_qr_code" msgid="3521809854780392679">"扫描二维码"</string>
- <string name="bt_le_audio_scan_qr_code_scanner" msgid="4679500020630341107">"将扫描器对准下方二维码,即可开始收听"</string>
+ <string name="bt_le_audio_scan_qr_code_scanner" msgid="4679500020630341107">"将取景框对准二维码,即可开始收听"</string>
<string name="bt_le_audio_qr_code_is_not_valid_format" msgid="6092191081849434734">"二维码的格式无效"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"要停止广播“<xliff:g id="APP_NAME">%1$s</xliff:g>”的内容吗?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"如果广播“<xliff:g id="SWITCHAPP">%1$s</xliff:g>”的内容或更改输出来源,当前的广播就会停止"</string>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index f334cc8..9e25102 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -599,7 +599,7 @@
<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>
- <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"此操作會開始新的訪客工作階段,並刪除目前工作階段中的所有應用程式和活動"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"此操作會開始新的訪客工作階段,並刪除目前工作階段的所有應用程式和資料"</string>
<string name="guest_exit_dialog_title" msgid="1846494656849381804">"要結束訪客模式嗎?"</string>
<string name="guest_exit_dialog_message" msgid="1743218864242719783">"此操作會刪除目前訪客工作階段中的所有應用程式和資料"</string>
<string name="guest_exit_dialog_button" msgid="1736401897067442044">"結束"</string>
@@ -612,7 +612,7 @@
<string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"結束訪客模式"</string>
<string name="guest_notification_ephemeral" msgid="7263252466950923871">"結束時將會刪除所有活動"</string>
<string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"您可以在結束時儲存或刪除活動"</string>
- <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"重設即可立即刪除工作階段活動,或在結束時儲存或刪除工作階段"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"重設可立即刪除工作階段活動,或者您可以在結束時儲存或刪除活動"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"拍照"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"選擇圖片"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"揀相"</string>
diff --git a/packages/SettingsLib/res/values/dimens.xml b/packages/SettingsLib/res/values/dimens.xml
index cbc79d2..226b119 100644
--- a/packages/SettingsLib/res/values/dimens.xml
+++ b/packages/SettingsLib/res/values/dimens.xml
@@ -115,12 +115,6 @@
<!-- Minimum density scale. This is available on all devices. -->
<fraction name="display_density_min_scale">85%</fraction>
- <!-- QR code picture size -->
- <dimen name="qrcode_preview_size">360dp</dimen>
- <dimen name="qrcode_preview_margin">40dp</dimen>
- <dimen name="qrcode_preview_radius">30dp</dimen>
- <dimen name="qrcode_icon_size">27dp</dimen>
-
<!-- Broadcast dialog -->
<dimen name="broadcast_dialog_title_img_margin_top">18dp</dimen>
<dimen name="broadcast_dialog_title_text_size">24sp</dimen>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 8ef712a..7c99ce5 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -1627,13 +1627,6 @@
<!-- Description for a setting which controls whether an app can turn the screen on [CHAR LIMIT=NONE] -->
<string name="allow_turn_screen_on_description">Allow an app to turn the screen on. If granted, the app may turn on the screen at any time without your explicit intent.</string>
- <!-- [CHAR LIMIT=NONE] Le audio QR code scanner title -->
- <string name="bt_le_audio_scan_qr_code">Scan QR code</string>
- <!-- [CHAR LIMIT=NONE] Le audio QR code scanner sub-title -->
- <string name="bt_le_audio_scan_qr_code_scanner">To start listening, center the QR code below</string>
- <!-- [CHAR LIMIT=NONE] Hint for QR code process failure -->
- <string name="bt_le_audio_qr_code_is_not_valid_format">QR code isn\u0027t a valid format</string>
-
<!-- [CHAR LIMIT=NONE] Le audio broadcast dialog, title -->
<string name="bt_le_audio_broadcast_dialog_title">Stop broadcasting <xliff:g id="app_name" example="App Name 1">%1$s</xliff:g>?</string>
<!-- [CHAR LIMIT=NONE] Le audio broadcast dialog, sub-title -->
diff --git a/packages/SettingsLib/res/values/styles.xml b/packages/SettingsLib/res/values/styles.xml
index 3234515..5237b4f 100644
--- a/packages/SettingsLib/res/values/styles.xml
+++ b/packages/SettingsLib/res/values/styles.xml
@@ -33,13 +33,6 @@
<item name="android:textColor">?android:attr/colorError</item>
</style>
- <style name="QrCodeScanner">
- <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
- <item name="android:textSize">16sp</item>
- <item name="android:textColor">?android:attr/textColorPrimary</item>
- <item name="android:textDirection">locale</item>
- </style>
-
<style name="BroadcastDialogTitleStyle">
<item name="android:textAppearance">@style/TextAppearanceBroadcastDialogTitle</item>
<item name="android:layout_marginStart">@dimen/broadcast_dialog_title_text_margin</item>
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java b/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java
index cc4fef8..7f65837 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java
@@ -268,9 +268,9 @@
/**
* Preload the top N icons of app entry list.
*
- * @param context caller's context
+ * @param context caller's context
* @param appEntries AppEntry list of ApplicationsState
- * @param number the number of Top N icons of the appEntries
+ * @param number the number of Top N icons of the appEntries
*/
public static void preloadTopIcons(Context context,
ArrayList<ApplicationsState.AppEntry> appEntries, int number) {
@@ -286,6 +286,19 @@
}
}
+ /**
+ * Returns a boolean indicating whether this app is installed or not.
+ *
+ * @param appEntry AppEntry of ApplicationsState.
+ * @return true if the app is in installed state.
+ */
+ public static boolean isAppInstalled(ApplicationsState.AppEntry appEntry) {
+ if (appEntry == null || appEntry.info == null) {
+ return false;
+ }
+ return (appEntry.info.flags & ApplicationInfo.FLAG_INSTALLED) != 0;
+ }
+
private static void setAppEntryMounted(ApplicationsState.AppEntry appEntry, boolean mounted) {
if (appEntry.mounted != mounted) {
synchronized (appEntry) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
index c9af4d5..fea7475 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
@@ -30,6 +30,9 @@
import java.io.IOException;
import java.util.List;
+import java.util.Locale;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
public class BluetoothUtils {
private static final String TAG = "BluetoothUtils";
@@ -39,6 +42,8 @@
public static final int META_INT_ERROR = -1;
public static final String BT_ADVANCED_HEADER_ENABLED = "bt_advanced_header_enabled";
+ private static final int METADATA_FAST_PAIR_CUSTOMIZED_FIELDS = 25;
+ private static final String KEY_HEARABLE_CONTROL_SLICE = "HEARABLE_CONTROL_SLICE_WITH_WIDTH";
private static ErrorListener sErrorListener;
@@ -384,8 +389,43 @@
return Uri.parse(data);
}
+ /**
+ * Get URI Bluetooth metadata for extra control
+ *
+ * @param bluetoothDevice the BluetoothDevice to get metadata
+ * @return the URI metadata
+ */
+ public static String getControlUriMetaData(BluetoothDevice bluetoothDevice) {
+ String data = getStringMetaData(bluetoothDevice, METADATA_FAST_PAIR_CUSTOMIZED_FIELDS);
+ return extraTagValue(KEY_HEARABLE_CONTROL_SLICE, data);
+ }
+
@SuppressLint("NewApi") // Hidden API made public
private static boolean doesClassMatch(BluetoothClass btClass, int classId) {
return btClass.doesClassMatch(classId);
}
+
+ private static String extraTagValue(String tag, String metaData) {
+ if (TextUtils.isEmpty(metaData)) {
+ return null;
+ }
+ Pattern pattern = Pattern.compile(generateExpressionWithTag(tag, "(.*?)"));
+ Matcher matcher = pattern.matcher(metaData);
+ if (matcher.find()) {
+ return matcher.group(1);
+ }
+ return null;
+ }
+
+ private static String getTagStart(String tag) {
+ return String.format(Locale.ENGLISH, "<%s>", tag);
+ }
+
+ private static String getTagEnd(String tag) {
+ return String.format(Locale.ENGLISH, "</%s>", tag);
+ }
+
+ private static String generateExpressionWithTag(String tag, String value) {
+ return getTagStart(tag) + value + getTagEnd(tag);
+ }
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index 6919cf2..a9da2e0 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -77,6 +77,8 @@
private final LocalBluetoothProfileManager mProfileManager;
private final Object mProfileLock = new Object();
BluetoothDevice mDevice;
+ private int mDeviceSide;
+ private int mDeviceMode;
private long mHiSyncId;
private int mGroupId;
// Need this since there is no method for getting RSSI
@@ -335,6 +337,22 @@
connectDevice();
}
+ public int getDeviceSide() {
+ return mDeviceSide;
+ }
+
+ public void setDeviceSide(int side) {
+ mDeviceSide = side;
+ }
+
+ public int getDeviceMode() {
+ return mDeviceMode;
+ }
+
+ public void setDeviceMode(int mode) {
+ mDeviceMode = mode;
+ }
+
public long getHiSyncId() {
return mHiSyncId;
}
@@ -1000,7 +1018,6 @@
== BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET)) {
EventLog.writeEvent(0x534e4554, "138529441", -1, "");
}
- mDevice.setPhonebookAccessPermission(BluetoothDevice.ACCESS_REJECTED);
}
}
}
@@ -1111,7 +1128,8 @@
stringRes = R.string.bluetooth_battery_level;
}
- // Set active string in following device connected situation.
+ // Set active string in following device connected situation, also show battery
+ // information if they have.
// 1. Hearing Aid device active.
// 2. Headset device active with in-calling state.
// 3. A2DP device active without in-calling state.
@@ -1130,6 +1148,24 @@
stringRes = R.string.bluetooth_active_no_battery_level;
}
}
+
+ // Try to show left/right information if can not get it from battery for hearing
+ // aids specifically.
+ if (mIsActiveDeviceHearingAid
+ && stringRes == R.string.bluetooth_active_no_battery_level) {
+ final CachedBluetoothDevice subDevice = getSubDevice();
+ if (subDevice != null && subDevice.isConnected()) {
+ stringRes = R.string.bluetooth_hearing_aid_left_and_right_active;
+ } else {
+ if (mDeviceSide == HearingAidProfile.DeviceSide.SIDE_LEFT) {
+ stringRes = R.string.bluetooth_hearing_aid_left_active;
+ } else if (mDeviceSide == HearingAidProfile.DeviceSide.SIDE_RIGHT) {
+ stringRes = R.string.bluetooth_hearing_aid_right_active;
+ } else {
+ stringRes = R.string.bluetooth_active_no_battery_level;
+ }
+ }
+ }
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
index 6f2d4de..a491455 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
@@ -29,13 +29,48 @@
import android.content.Context;
import android.util.Log;
+import androidx.annotation.IntDef;
+import androidx.annotation.NonNull;
+
import com.android.settingslib.R;
import com.android.settingslib.Utils;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
public class HearingAidProfile implements LocalBluetoothProfile {
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({
+ DeviceSide.SIDE_INVALID,
+ DeviceSide.SIDE_LEFT,
+ DeviceSide.SIDE_RIGHT
+ })
+
+ /** Side definition for hearing aids. See {@link BluetoothHearingAid}. */
+ public @interface DeviceSide {
+ int SIDE_INVALID = -1;
+ int SIDE_LEFT = 0;
+ int SIDE_RIGHT = 1;
+ }
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({
+ DeviceMode.MODE_INVALID,
+ DeviceMode.MODE_MONAURAL,
+ DeviceMode.MODE_BINAURAL
+ })
+
+ /** Mode definition for hearing aids. See {@link BluetoothHearingAid}. */
+ public @interface DeviceMode {
+ int MODE_INVALID = -1;
+ int MODE_MONAURAL = 0;
+ int MODE_BINAURAL = 1;
+ }
+
private static final String TAG = "HearingAidProfile";
private static boolean V = true;
@@ -212,6 +247,11 @@
return isEnabled;
}
+ /**
+ * Tells remote device to set an absolute volume.
+ *
+ * @param volume Absolute volume to be set on remote
+ */
public void setVolume(int volume) {
if (mService == null) {
return;
@@ -219,6 +259,12 @@
mService.setVolume(volume);
}
+ /**
+ * Gets the HiSyncId (unique hearing aid device identifier) of the device.
+ *
+ * @param device Bluetooth device
+ * @return the HiSyncId of the device
+ */
public long getHiSyncId(BluetoothDevice device) {
if (mService == null || device == null) {
return BluetoothHearingAid.HI_SYNC_ID_INVALID;
@@ -226,6 +272,59 @@
return mService.getHiSyncId(device);
}
+ /**
+ * Gets the side of the device.
+ *
+ * @param device Bluetooth device.
+ * @return side of the device. See {@link DeviceSide}.
+ */
+ @DeviceSide
+ public int getDeviceSide(@NonNull BluetoothDevice device) {
+ final int defaultValue = DeviceSide.SIDE_INVALID;
+ if (mService == null) {
+ Log.w(TAG, "Proxy not attached to HearingAidService");
+ return defaultValue;
+ }
+
+ try {
+ Method method = mService.getClass().getDeclaredMethod("getDeviceSideInternal",
+ BluetoothDevice.class);
+ method.setAccessible(true);
+ return (int) method.invoke(mService, device);
+ } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
+ Log.e(TAG, "fail to get getDeviceSideInternal\n" + e.toString() + "\n"
+ + Log.getStackTraceString(new Throwable()));
+ return defaultValue;
+ }
+ }
+
+ /**
+ * Gets the mode of the device.
+ *
+ * @param device Bluetooth device
+ * @return mode of the device. See {@link DeviceMode}.
+ */
+ @DeviceMode
+ public int getDeviceMode(@NonNull BluetoothDevice device) {
+ final int defaultValue = DeviceMode.MODE_INVALID;
+ if (mService == null) {
+ Log.w(TAG, "Proxy not attached to HearingAidService");
+ return defaultValue;
+ }
+
+ try {
+ Method method = mService.getClass().getDeclaredMethod("getDeviceModeInternal",
+ BluetoothDevice.class);
+ method.setAccessible(true);
+ return (int) method.invoke(mService, device);
+ } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
+ Log.e(TAG, "fail to get getDeviceModeInternal\n" + e.toString() + "\n"
+ + Log.getStackTraceString(new Throwable()));
+
+ return defaultValue;
+ }
+ }
+
public String toString() {
return NAME;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
index 0619986..58944f6 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
@@ -340,6 +340,11 @@
if (getHearingAidProfile() != null &&
mProfile instanceof HearingAidProfile &&
(newState == BluetoothProfile.STATE_CONNECTED)) {
+ final int side = getHearingAidProfile().getDeviceSide(cachedDevice.getDevice());
+ final int mode = getHearingAidProfile().getDeviceMode(cachedDevice.getDevice());
+ cachedDevice.setDeviceSide(side);
+ cachedDevice.setDeviceMode(mode);
+
// Check if the HiSyncID has being initialized
if (cachedDevice.getHiSyncId() == BluetoothHearingAid.HI_SYNC_ID_INVALID) {
long newHiSyncId = getHearingAidProfile().getHiSyncId(cachedDevice.getDevice());
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java
index dd7db21..afafd9f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java
@@ -59,7 +59,7 @@
@Override
public Drawable getIcon() {
- return BluetoothUtils.getBtDrawableWithDescription(mContext, mCachedDevice).first;
+ return BluetoothUtils.getBtClassDrawableWithDescription(mContext, mCachedDevice).first;
}
@Override
diff --git a/packages/SettingsLib/src/com/android/settingslib/qrcode/QrCodeScanModeActivity.java b/packages/SettingsLib/src/com/android/settingslib/qrcode/QrCodeScanModeActivity.java
deleted file mode 100644
index 15a910e..0000000
--- a/packages/SettingsLib/src/com/android/settingslib/qrcode/QrCodeScanModeActivity.java
+++ /dev/null
@@ -1,109 +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.settingslib.qrcode;
-
-import static com.android.settingslib.bluetooth.BluetoothBroadcastUtils.EXTRA_BLUETOOTH_DEVICE_SINK;
-import static com.android.settingslib.bluetooth.BluetoothBroadcastUtils.EXTRA_BLUETOOTH_SINK_IS_GROUP;
-
-import android.bluetooth.BluetoothDevice;
-import android.content.Intent;
-import android.os.Bundle;
-import android.util.Log;
-
-import androidx.fragment.app.FragmentTransaction;
-
-import com.android.settingslib.R;
-import com.android.settingslib.bluetooth.BluetoothBroadcastUtils;
-import com.android.settingslib.bluetooth.BluetoothUtils;
-
-public class QrCodeScanModeActivity extends QrCodeScanModeBaseActivity {
- private static final boolean DEBUG = BluetoothUtils.D;
- private static final String TAG = "QrCodeScanModeActivity";
-
- private boolean mIsGroupOp;
- private BluetoothDevice mSink;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- }
-
- @Override
- protected void handleIntent(Intent intent) {
- String action = intent != null ? intent.getAction() : null;
- if (DEBUG) {
- Log.d(TAG, "handleIntent(), action = " + action);
- }
-
- if (action == null) {
- finish();
- return;
- }
-
- switch (action) {
- case BluetoothBroadcastUtils.ACTION_BLUETOOTH_LE_AUDIO_QR_CODE_SCANNER:
- showQrCodeScannerFragment(intent);
- break;
- default:
- if (DEBUG) {
- Log.e(TAG, "Launch with an invalid action");
- }
- finish();
- }
- }
-
- protected void showQrCodeScannerFragment(Intent intent) {
- if (DEBUG) {
- Log.d(TAG, "showQrCodeScannerFragment");
- }
-
- if (intent != null) {
- mSink = intent.getParcelableExtra(EXTRA_BLUETOOTH_DEVICE_SINK);
- mIsGroupOp = intent.getBooleanExtra(EXTRA_BLUETOOTH_SINK_IS_GROUP, false);
- if (DEBUG) {
- Log.d(TAG, "get extra from intent");
- }
- } else {
- if (DEBUG) {
- Log.d(TAG, "intent is null, can not get bluetooth information from intent.");
- }
- }
-
- QrCodeScanModeFragment fragment =
- (QrCodeScanModeFragment) mFragmentManager.findFragmentByTag(
- BluetoothBroadcastUtils.TAG_FRAGMENT_QR_CODE_SCANNER);
-
- if (fragment == null) {
- fragment = new QrCodeScanModeFragment(mIsGroupOp, mSink);
- } else {
- if (fragment.isVisible()) {
- return;
- }
-
- // When the fragment in back stack but not on top of the stack, we can simply pop
- // stack because current fragment transactions are arranged in an order
- mFragmentManager.popBackStackImmediate();
- return;
- }
- final FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();
-
- fragmentTransaction.replace(R.id.fragment_container, fragment,
- BluetoothBroadcastUtils.TAG_FRAGMENT_QR_CODE_SCANNER);
- fragmentTransaction.commit();
- }
-}
-
diff --git a/packages/SettingsLib/src/com/android/settingslib/qrcode/QrCodeScanModeBaseActivity.java b/packages/SettingsLib/src/com/android/settingslib/qrcode/QrCodeScanModeBaseActivity.java
deleted file mode 100644
index 361fd5b..0000000
--- a/packages/SettingsLib/src/com/android/settingslib/qrcode/QrCodeScanModeBaseActivity.java
+++ /dev/null
@@ -1,46 +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.settingslib.qrcode;
-
-import android.content.Intent;
-import android.os.Bundle;
-
-import androidx.fragment.app.FragmentManager;
-
-import com.android.settingslib.R;
-import com.android.settingslib.core.lifecycle.ObservableActivity;
-
-public abstract class QrCodeScanModeBaseActivity extends ObservableActivity {
-
- protected FragmentManager mFragmentManager;
-
- protected abstract void handleIntent(Intent intent);
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- setTheme(R.style.SudThemeGlifV3_DayNight);
-
- setContentView(R.layout.qrcode_scan_mode_activity);
- mFragmentManager = getSupportFragmentManager();
-
- if (savedInstanceState == null) {
- handleIntent(getIntent());
- }
- }
-}
diff --git a/packages/SettingsLib/src/com/android/settingslib/qrcode/QrCodeScanModeController.java b/packages/SettingsLib/src/com/android/settingslib/qrcode/QrCodeScanModeController.java
deleted file mode 100644
index 153d2d2..0000000
--- a/packages/SettingsLib/src/com/android/settingslib/qrcode/QrCodeScanModeController.java
+++ /dev/null
@@ -1,82 +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.settingslib.qrcode;
-
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothLeBroadcastMetadata;
-import android.content.Context;
-import android.util.Log;
-
-import com.android.settingslib.bluetooth.BluetoothUtils;
-import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
-import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;
-import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastMetadata;
-import com.android.settingslib.bluetooth.LocalBluetoothManager;
-import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
-
-public class QrCodeScanModeController {
-
- private static final boolean DEBUG = BluetoothUtils.D;
- private static final String TAG = "QrCodeScanModeController";
-
- private LocalBluetoothLeBroadcastMetadata mLocalBroadcastMetadata;
- private LocalBluetoothLeBroadcastAssistant mLocalBroadcastAssistant;
- private LocalBluetoothManager mLocalBluetoothManager;
- private LocalBluetoothProfileManager mProfileManager;
-
- private LocalBluetoothManager.BluetoothManagerCallback
- mOnInitCallback = new LocalBluetoothManager.BluetoothManagerCallback() {
- @Override
- public void onBluetoothManagerInitialized(Context appContext,
- LocalBluetoothManager bluetoothManager) {
- BluetoothUtils.setErrorListener(mErrorListener);
- }
- };
-
- private BluetoothUtils.ErrorListener
- mErrorListener = new BluetoothUtils.ErrorListener() {
- @Override
- public void onShowError(Context context, String name, int messageResId) {
- if (DEBUG) {
- Log.d(TAG, "Get error when initializing BluetoothManager. ");
- }
- }
- };
-
- public QrCodeScanModeController(Context context) {
- if (DEBUG) {
- Log.d(TAG, "QrCodeScanModeController constructor.");
- }
- mLocalBluetoothManager = LocalBluetoothManager.getInstance(context, mOnInitCallback);
- mProfileManager = mLocalBluetoothManager.getProfileManager();
- mLocalBroadcastMetadata = new LocalBluetoothLeBroadcastMetadata();
- CachedBluetoothDeviceManager cachedDeviceManager = new CachedBluetoothDeviceManager(context,
- mLocalBluetoothManager);
- mLocalBroadcastAssistant = new LocalBluetoothLeBroadcastAssistant(context,
- cachedDeviceManager, mProfileManager);
- }
-
- private BluetoothLeBroadcastMetadata convertToBroadcastMetadata(String qrCodeString) {
- return mLocalBroadcastMetadata.convertToBroadcastMetadata(qrCodeString);
- }
-
- public void addSource(BluetoothDevice sink, String sourceMetadata,
- boolean isGroupOp) {
- mLocalBroadcastAssistant.addSource(sink,
- convertToBroadcastMetadata(sourceMetadata), isGroupOp);
- }
-}
diff --git a/packages/SettingsLib/src/com/android/settingslib/qrcode/QrCodeScanModeFragment.java b/packages/SettingsLib/src/com/android/settingslib/qrcode/QrCodeScanModeFragment.java
deleted file mode 100644
index 069b950..0000000
--- a/packages/SettingsLib/src/com/android/settingslib/qrcode/QrCodeScanModeFragment.java
+++ /dev/null
@@ -1,235 +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.settingslib.qrcode;
-
-import android.bluetooth.BluetoothDevice;
-import android.content.Context;
-import android.graphics.Matrix;
-import android.graphics.Outline;
-import android.graphics.Rect;
-import android.graphics.SurfaceTexture;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.util.Log;
-import android.util.Size;
-import android.view.LayoutInflater;
-import android.view.TextureView;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewOutlineProvider;
-import android.view.accessibility.AccessibilityEvent;
-import android.widget.TextView;
-
-import com.android.settingslib.R;
-import com.android.settingslib.bluetooth.BluetoothBroadcastUtils;
-import com.android.settingslib.bluetooth.BluetoothUtils;
-import com.android.settingslib.core.lifecycle.ObservableFragment;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.StringRes;
-
-public class QrCodeScanModeFragment extends ObservableFragment implements
- TextureView.SurfaceTextureListener,
- QrCamera.ScannerCallback {
- private static final boolean DEBUG = BluetoothUtils.D;
- private static final String TAG = "QrCodeScanModeFragment";
-
- /** Message sent to hide error message */
- private static final int MESSAGE_HIDE_ERROR_MESSAGE = 1;
- /** Message sent to show error message */
- private static final int MESSAGE_SHOW_ERROR_MESSAGE = 2;
- /** Message sent to broadcast QR code */
- private static final int MESSAGE_SCAN_BROADCAST_SUCCESS = 3;
-
- private static final long SHOW_ERROR_MESSAGE_INTERVAL = 10000;
- private static final long SHOW_SUCCESS_SQUARE_INTERVAL = 1000;
-
- private boolean mIsGroupOp;
- private int mCornerRadius;
- private BluetoothDevice mSink;
- private String mBroadcastMetadata;
- private Context mContext;
- private QrCamera mCamera;
- private QrCodeScanModeController mController;
- private TextureView mTextureView;
- private TextView mSummary;
- private TextView mErrorMessage;
-
- public QrCodeScanModeFragment(boolean isGroupOp, BluetoothDevice sink) {
- mIsGroupOp = isGroupOp;
- mSink = sink;
- }
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- mContext = getContext();
- mController = new QrCodeScanModeController(mContext);
- }
-
- @Override
- public final View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- return inflater.inflate(R.layout.qrcode_scanner_fragment, container,
- /* attachToRoot */ false);
- }
-
- @Override
- public void onViewCreated(View view, Bundle savedInstanceState) {
- mTextureView = view.findViewById(R.id.preview_view);
- mCornerRadius = mContext.getResources().getDimensionPixelSize(
- R.dimen.qrcode_preview_radius);
- mTextureView.setSurfaceTextureListener(this);
- mTextureView.setOutlineProvider(new ViewOutlineProvider() {
- @Override
- public void getOutline(View view, Outline outline) {
- outline.setRoundRect(0,0, view.getWidth(), view.getHeight(), mCornerRadius);
- }
- });
- mTextureView.setClipToOutline(true);
- mErrorMessage = view.findViewById(R.id.error_message);
- }
-
- private void initCamera(SurfaceTexture surface) {
- // Check if the camera has already created.
- if (mCamera == null) {
- mCamera = new QrCamera(mContext, this);
- mCamera.start(surface);
- }
- }
-
- private void destroyCamera() {
- if (mCamera != null) {
- mCamera.stop();
- mCamera = null;
- }
- }
-
- @Override
- public void onSurfaceTextureAvailable(@NonNull SurfaceTexture surface, int width, int height) {
- initCamera(surface);
- }
-
- @Override
- public void onSurfaceTextureSizeChanged(@NonNull SurfaceTexture surface, int width,
- int height) {
- }
-
- @Override
- public boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture surface) {
- destroyCamera();
- return true;
- }
-
- @Override
- public void onSurfaceTextureUpdated(@NonNull SurfaceTexture surface) {
- }
-
- @Override
- public void handleSuccessfulResult(String qrCode) {
- if (DEBUG) {
- Log.d(TAG, "handleSuccessfulResult(), get the qr code string.");
- }
- mBroadcastMetadata = qrCode;
- handleBtLeAudioScanner();
- }
-
- @Override
- public void handleCameraFailure() {
- destroyCamera();
- }
-
- @Override
- public Size getViewSize() {
- return new Size(mTextureView.getWidth(), mTextureView.getHeight());
- }
-
- @Override
- public Rect getFramePosition(Size previewSize, int cameraOrientation) {
- return new Rect(0, 0, previewSize.getHeight(), previewSize.getHeight());
- }
-
- @Override
- public void setTransform(Matrix transform) {
- mTextureView.setTransform(transform);
- }
-
- @Override
- public boolean isValid(String qrCode) {
- if (qrCode.startsWith(BluetoothBroadcastUtils.SCHEME_BT_BROADCAST_METADATA)) {
- return true;
- } else {
- showErrorMessage(R.string.bt_le_audio_qr_code_is_not_valid_format);
- return false;
- }
- }
-
- protected boolean isDecodeTaskAlive() {
- return mCamera != null && mCamera.isDecodeTaskAlive();
- }
-
- private final Handler mHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MESSAGE_HIDE_ERROR_MESSAGE:
- mErrorMessage.setVisibility(View.INVISIBLE);
- break;
-
- case MESSAGE_SHOW_ERROR_MESSAGE:
- final String errorMessage = (String) msg.obj;
-
- mErrorMessage.setVisibility(View.VISIBLE);
- mErrorMessage.setText(errorMessage);
- mErrorMessage.sendAccessibilityEvent(
- AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
-
- // Cancel any pending messages to hide error view and requeue the message so
- // user has time to see error
- removeMessages(MESSAGE_HIDE_ERROR_MESSAGE);
- sendEmptyMessageDelayed(MESSAGE_HIDE_ERROR_MESSAGE,
- SHOW_ERROR_MESSAGE_INTERVAL);
- break;
-
- case MESSAGE_SCAN_BROADCAST_SUCCESS:
- mController.addSource(mSink, mBroadcastMetadata, mIsGroupOp);
- updateSummary();
- mSummary.sendAccessibilityEvent(
- AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
- break;
- default:
- }
- }
- };
-
- private void showErrorMessage(@StringRes int messageResId) {
- final Message message = mHandler.obtainMessage(MESSAGE_SHOW_ERROR_MESSAGE,
- getString(messageResId));
- message.sendToTarget();
- }
-
- private void handleBtLeAudioScanner() {
- Message message = mHandler.obtainMessage(MESSAGE_SCAN_BROADCAST_SUCCESS);
- mHandler.sendMessageDelayed(message, SHOW_SUCCESS_SQUARE_INTERVAL);
- }
-
- private void updateSummary() {
- mSummary.setText(getString(R.string.bt_le_audio_scan_qr_code_scanner,
- null /* broadcast_name*/));;
- }
-}
diff --git a/packages/SettingsLib/src/com/android/settingslib/users/AvatarPickerActivity.java b/packages/SettingsLib/src/com/android/settingslib/users/AvatarPickerActivity.java
index 8a1e91b..3e7481a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/users/AvatarPickerActivity.java
+++ b/packages/SettingsLib/src/com/android/settingslib/users/AvatarPickerActivity.java
@@ -147,6 +147,7 @@
mWaitingForActivityResult = savedInstanceState.getBoolean(KEY_AWAITING_RESULT, false);
mAdapter.mSelectedPosition =
savedInstanceState.getInt(KEY_SELECTED_POSITION, AvatarAdapter.NONE);
+ mDoneButton.setEnabled(mAdapter.mSelectedPosition != AvatarAdapter.NONE);
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/users/EditUserInfoController.java b/packages/SettingsLib/src/com/android/settingslib/users/EditUserInfoController.java
index 80ee86f..3b542cc 100644
--- a/packages/SettingsLib/src/com/android/settingslib/users/EditUserInfoController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/users/EditUserInfoController.java
@@ -54,6 +54,7 @@
private Dialog mEditUserInfoDialog;
private Bitmap mSavedPhoto;
+ private Drawable mSavedDrawable;
private EditUserPhotoController mEditUserPhotoController;
private boolean mWaitingForActivityResult = false;
private final String mFileAuthority;
@@ -68,6 +69,7 @@
}
mEditUserInfoDialog = null;
mSavedPhoto = null;
+ mSavedDrawable = null;
}
/**
@@ -170,7 +172,8 @@
private Drawable getUserIcon(Activity activity, Drawable defaultUserIcon) {
if (mSavedPhoto != null) {
- return CircleFramedDrawable.getInstance(activity, mSavedPhoto);
+ mSavedDrawable = CircleFramedDrawable.getInstance(activity, mSavedPhoto);
+ return mSavedDrawable;
}
return defaultUserIcon;
}
@@ -229,6 +232,6 @@
EditUserPhotoController createEditUserPhotoController(Activity activity,
ActivityStarter activityStarter, ImageView userPhotoView) {
return new EditUserPhotoController(activity, activityStarter, userPhotoView,
- mSavedPhoto, mFileAuthority);
+ mSavedPhoto, mSavedDrawable, mFileAuthority);
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/users/EditUserPhotoController.java b/packages/SettingsLib/src/com/android/settingslib/users/EditUserPhotoController.java
index 5862f60..38cf383 100644
--- a/packages/SettingsLib/src/com/android/settingslib/users/EditUserPhotoController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/users/EditUserPhotoController.java
@@ -62,7 +62,7 @@
private Drawable mNewUserPhotoDrawable;
public EditUserPhotoController(Activity activity, ActivityStarter activityStarter,
- ImageView view, Bitmap bitmap, String fileAuthority) {
+ ImageView view, Bitmap savedBitmap, Drawable savedDrawable, String fileAuthority) {
mActivity = activity;
mActivityStarter = activityStarter;
mFileAuthority = fileAuthority;
@@ -71,7 +71,9 @@
mImagesDir.mkdir();
mImageView = view;
mImageView.setOnClickListener(v -> showAvatarPicker());
- mNewUserPhotoBitmap = bitmap;
+
+ mNewUserPhotoBitmap = savedBitmap;
+ mNewUserPhotoDrawable = savedDrawable;
}
/**
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/AppUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/AppUtilsTest.java
index 8e448aa..994c1ee 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/AppUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/AppUtilsTest.java
@@ -129,6 +129,28 @@
assertThat(mAppIconCacheManager.get(APP_PACKAGE_NAME, APP_UID)).isNotNull();
}
+ @Test
+ public void isAppInstalled_noAppEntry_shouldReturnFalse() {
+ assertThat(AppUtils.isAppInstalled(null)).isFalse();
+ }
+
+ @Test
+ public void isAppInstalled_hasAppEntryWithInstalledFlag_shouldReturnTrue() {
+ final ApplicationsState.AppEntry appEntry = mock(ApplicationsState.AppEntry.class);
+ appEntry.info = new ApplicationInfo();
+ appEntry.info.flags = ApplicationInfo.FLAG_INSTALLED;
+
+ assertThat(AppUtils.isAppInstalled(appEntry)).isTrue();
+ }
+
+ @Test
+ public void isAppInstalled_hasAppEntryWithoutInstalledFlag_shouldReturnFalse() {
+ final ApplicationsState.AppEntry appEntry = mock(ApplicationsState.AppEntry.class);
+ appEntry.info = new ApplicationInfo();
+
+ assertThat(AppUtils.isAppInstalled(appEntry)).isFalse();
+ }
+
private ApplicationsState.AppEntry createAppEntry(ApplicationInfo appInfo, int id) {
ApplicationsState.AppEntry appEntry = new ApplicationsState.AppEntry(mContext, appInfo, id);
appEntry.label = "label";
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java
index 2e85514..1c0ea1a 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java
@@ -51,6 +51,11 @@
private static final String STRING_METADATA = "string_metadata";
private static final String BOOL_METADATA = "true";
private static final String INT_METADATA = "25";
+ private static final int METADATA_FAST_PAIR_CUSTOMIZED_FIELDS = 25;
+ private static final String KEY_HEARABLE_CONTROL_SLICE = "HEARABLE_CONTROL_SLICE_WITH_WIDTH";
+ private static final String CONTROL_METADATA =
+ "<HEARABLE_CONTROL_SLICE_WITH_WIDTH>" + STRING_METADATA
+ + "</HEARABLE_CONTROL_SLICE_WITH_WIDTH>";
@Before
public void setUp() {
@@ -152,6 +157,15 @@
}
@Test
+ public void getControlUriMetaData_hasMetaData_returnsCorrectMetaData() {
+ when(mBluetoothDevice.getMetadata(METADATA_FAST_PAIR_CUSTOMIZED_FIELDS)).thenReturn(
+ CONTROL_METADATA.getBytes());
+
+ assertThat(BluetoothUtils.getControlUriMetaData(mBluetoothDevice)).isEqualTo(
+ STRING_METADATA);
+ }
+
+ @Test
public void isAdvancedDetailsHeader_untetheredHeadset_returnTrue() {
when(mBluetoothDevice.getMetadata(
BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET)).thenReturn(
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
index 55d125e..be2a55e 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
@@ -78,6 +78,7 @@
@Mock
private BluetoothDevice mSubDevice;
private CachedBluetoothDevice mCachedDevice;
+ private CachedBluetoothDevice mSubCachedDevice;
private AudioManager mAudioManager;
private Context mContext;
private int mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN;
@@ -95,7 +96,9 @@
when(mPanProfile.isProfileReady()).thenReturn(true);
when(mHearingAidProfile.isProfileReady()).thenReturn(true);
mCachedDevice = spy(new CachedBluetoothDevice(mContext, mProfileManager, mDevice));
+ mSubCachedDevice = spy(new CachedBluetoothDevice(mContext, mProfileManager, mSubDevice));
doAnswer((invocation) -> mBatteryLevel).when(mCachedDevice).getBatteryLevel();
+ doAnswer((invocation) -> mBatteryLevel).when(mSubCachedDevice).getBatteryLevel();
}
@Test
@@ -351,8 +354,9 @@
assertThat(mCachedDevice.getConnectionSummary()).isNull();
// Set device as Active for Hearing Aid and test connection state summary
+ mCachedDevice.setDeviceSide(HearingAidProfile.DeviceSide.SIDE_LEFT);
mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEARING_AID);
- assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Active");
+ assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Active, left only");
// Set Hearing Aid profile to be disconnected and test connection state summary
mCachedDevice.onActiveDeviceChanged(false, BluetoothProfile.HEARING_AID);
@@ -390,17 +394,36 @@
}
@Test
- public void getConnectionSummary_testHearingAidInCall_returnActive() {
+ public void getConnectionSummary_testHearingAidRightEarInCall_returnActiveRightEar() {
// Arrange:
- // 1. Profile: {HEARING_AID, Connected, Active}
+ // 1. Profile: {HEARING_AID, Connected, Active, Right ear}
// 2. Audio Manager: In Call
updateProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED);
+ mCachedDevice.setDeviceSide(HearingAidProfile.DeviceSide.SIDE_RIGHT);
mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEARING_AID);
mAudioManager.setMode(AudioManager.MODE_IN_CALL);
// Act & Assert:
// Get "Active" result without Battery Level.
- assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Active");
+ assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Active, right only");
+ }
+
+ @Test
+ public void getConnectionSummary_testHearingAidBothEarInCall_returnActiveBothEar() {
+ // Arrange:
+ // 1. Profile: {HEARING_AID, Connected, Active, Both ear}
+ // 2. Audio Manager: In Call
+ mCachedDevice.setDeviceSide(HearingAidProfile.DeviceSide.SIDE_RIGHT);
+ updateProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED);
+ mSubCachedDevice.setDeviceSide(HearingAidProfile.DeviceSide.SIDE_LEFT);
+ updateSubDeviceProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED);
+ mCachedDevice.setSubDevice(mSubCachedDevice);
+ mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEARING_AID);
+ mAudioManager.setMode(AudioManager.MODE_IN_CALL);
+
+ // Act & Assert:
+ // Get "Active" result without Battery Level.
+ assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Active, left and right");
}
@Test
@@ -925,39 +948,41 @@
mCachedDevice.onProfileStateChanged(profile, status);
}
+ private void updateSubDeviceProfileStatus(LocalBluetoothProfile profile, int status) {
+ doReturn(status).when(profile).getConnectionStatus(mSubDevice);
+ mSubCachedDevice.onProfileStateChanged(profile, status);
+ }
+
@Test
public void getSubDevice_setSubDevice() {
- CachedBluetoothDevice subCachedDevice = new CachedBluetoothDevice(mContext, mProfileManager,
- mSubDevice);
- mCachedDevice.setSubDevice(subCachedDevice);
+ mCachedDevice.setSubDevice(mSubCachedDevice);
- assertThat(mCachedDevice.getSubDevice()).isEqualTo(subCachedDevice);
+ assertThat(mCachedDevice.getSubDevice()).isEqualTo(mSubCachedDevice);
}
@Test
public void switchSubDeviceContent() {
- CachedBluetoothDevice subCachedDevice = new CachedBluetoothDevice(mContext, mProfileManager,
- mSubDevice);
+
mCachedDevice.mRssi = RSSI_1;
mCachedDevice.mJustDiscovered = JUSTDISCOVERED_1;
- subCachedDevice.mRssi = RSSI_2;
- subCachedDevice.mJustDiscovered = JUSTDISCOVERED_2;
- mCachedDevice.setSubDevice(subCachedDevice);
+ mSubCachedDevice.mRssi = RSSI_2;
+ mSubCachedDevice.mJustDiscovered = JUSTDISCOVERED_2;
+ mCachedDevice.setSubDevice(mSubCachedDevice);
assertThat(mCachedDevice.mRssi).isEqualTo(RSSI_1);
assertThat(mCachedDevice.mJustDiscovered).isEqualTo(JUSTDISCOVERED_1);
assertThat(mCachedDevice.mDevice).isEqualTo(mDevice);
- assertThat(subCachedDevice.mRssi).isEqualTo(RSSI_2);
- assertThat(subCachedDevice.mJustDiscovered).isEqualTo(JUSTDISCOVERED_2);
- assertThat(subCachedDevice.mDevice).isEqualTo(mSubDevice);
+ assertThat(mSubCachedDevice.mRssi).isEqualTo(RSSI_2);
+ assertThat(mSubCachedDevice.mJustDiscovered).isEqualTo(JUSTDISCOVERED_2);
+ assertThat(mSubCachedDevice.mDevice).isEqualTo(mSubDevice);
mCachedDevice.switchSubDeviceContent();
assertThat(mCachedDevice.mRssi).isEqualTo(RSSI_2);
assertThat(mCachedDevice.mJustDiscovered).isEqualTo(JUSTDISCOVERED_2);
assertThat(mCachedDevice.mDevice).isEqualTo(mSubDevice);
- assertThat(subCachedDevice.mRssi).isEqualTo(RSSI_1);
- assertThat(subCachedDevice.mJustDiscovered).isEqualTo(JUSTDISCOVERED_1);
- assertThat(subCachedDevice.mDevice).isEqualTo(mDevice);
+ assertThat(mSubCachedDevice.mRssi).isEqualTo(RSSI_1);
+ assertThat(mSubCachedDevice.mJustDiscovered).isEqualTo(JUSTDISCOVERED_1);
+ assertThat(mSubCachedDevice.mDevice).isEqualTo(mDevice);
}
@Test
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java
index 428a655..b9e565e 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java
@@ -93,6 +93,7 @@
Settings.Global.Wearable.AMBIENT_TOUCH_TO_WAKE,
Settings.Global.Wearable.TOUCH_AND_HOLD_WATCH_FACE,
Settings.Global.Wearable.BATTERY_SAVER_MODE,
- Settings.Global.Wearable.WEAR_ACTIVITY_AUTO_RESUME_TIMEOUT_MS
+ Settings.Global.Wearable.WEAR_ACTIVITY_AUTO_RESUME_TIMEOUT_MS,
+ Settings.Global.Wearable.WEAR_ACTIVITY_AUTO_RESUME_TIMEOUT_SET_BY_USER
};
}
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
index 98e4778..0584406 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
@@ -307,6 +307,9 @@
VALIDATORS.put(
Global.Wearable.WEAR_ACTIVITY_AUTO_RESUME_TIMEOUT_MS,
NON_NEGATIVE_INTEGER_VALIDATOR);
+ VALIDATORS.put(
+ Global.Wearable.WEAR_ACTIVITY_AUTO_RESUME_TIMEOUT_SET_BY_USER,
+ BOOLEAN_VALIDATOR);
VALIDATORS.put(Global.Wearable.BURN_IN_PROTECTION_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Global.Wearable.COMBINED_LOCATION_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Global.Wearable.WRIST_ORIENTATION_MODE,
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index 0c6d40aa..5088533 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -1074,13 +1074,63 @@
if (DEBUG) Log.d(TAG, "Successfully unMarshaled SoftApConfiguration ");
// Depending on device hardware, we may need to notify the user of a setting change
SoftApConfiguration storedConfig = mWifiManager.getSoftApConfiguration();
- if (!storedConfig.equals(configInCloud)) {
+
+ if (isNeedToNotifyUserConfigurationHasChanged(configInCloud, storedConfig)) {
Log.d(TAG, "restored ap configuration requires a conversion, notify the user");
WifiSoftApConfigChangedNotifier.notifyUserOfConfigConversion(this);
}
}
}
+ private boolean isNeedToNotifyUserConfigurationHasChanged(SoftApConfiguration configInCloud,
+ SoftApConfiguration storedConfig) {
+ // Check if the cloud configuration was modified when restored to the device.
+ // All elements of the configuration are compared except:
+ // 1. Persistent randomized MAC address (which is per device)
+ // 2. The flag indicating whether the configuration is "user modified"
+ return !(Objects.equals(configInCloud.getWifiSsid(), storedConfig.getWifiSsid())
+ && Objects.equals(configInCloud.getBssid(), storedConfig.getBssid())
+ && Objects.equals(configInCloud.getPassphrase(), storedConfig.getPassphrase())
+ && configInCloud.isHiddenSsid() == storedConfig.isHiddenSsid()
+ && configInCloud.getChannels().toString().equals(
+ storedConfig.getChannels().toString())
+ && configInCloud.getSecurityType() == storedConfig.getSecurityType()
+ && configInCloud.getMaxNumberOfClients() == storedConfig.getMaxNumberOfClients()
+ && configInCloud.isAutoShutdownEnabled() == storedConfig.isAutoShutdownEnabled()
+ && configInCloud.getShutdownTimeoutMillis()
+ == storedConfig.getShutdownTimeoutMillis()
+ && configInCloud.isClientControlByUserEnabled()
+ == storedConfig.isClientControlByUserEnabled()
+ && Objects.equals(configInCloud.getBlockedClientList(),
+ storedConfig.getBlockedClientList())
+ && Objects.equals(configInCloud.getAllowedClientList(),
+ storedConfig.getAllowedClientList())
+ && configInCloud.getMacRandomizationSetting()
+ == storedConfig.getMacRandomizationSetting()
+ && configInCloud.isBridgedModeOpportunisticShutdownEnabled()
+ == storedConfig.isBridgedModeOpportunisticShutdownEnabled()
+ && configInCloud.isIeee80211axEnabled() == storedConfig.isIeee80211axEnabled()
+ && configInCloud.isIeee80211beEnabled() == storedConfig.isIeee80211beEnabled()
+ && configInCloud.getBridgedModeOpportunisticShutdownTimeoutMillis()
+ == storedConfig.getBridgedModeOpportunisticShutdownTimeoutMillis()
+ && Objects.equals(configInCloud.getVendorElements(),
+ storedConfig.getVendorElements())
+ && (configInCloud.getPersistentRandomizedMacAddress() != null
+ ? Objects.equals(configInCloud.getPersistentRandomizedMacAddress(),
+ storedConfig.getPersistentRandomizedMacAddress()) : true)
+ && Arrays.equals(configInCloud.getAllowedAcsChannels(
+ SoftApConfiguration.BAND_2GHZ),
+ storedConfig.getAllowedAcsChannels(SoftApConfiguration.BAND_2GHZ))
+ && Arrays.equals(configInCloud.getAllowedAcsChannels(
+ SoftApConfiguration.BAND_5GHZ),
+ storedConfig.getAllowedAcsChannels(SoftApConfiguration.BAND_5GHZ))
+ && Arrays.equals(configInCloud.getAllowedAcsChannels(
+ SoftApConfiguration.BAND_6GHZ),
+ storedConfig.getAllowedAcsChannels(SoftApConfiguration.BAND_6GHZ))
+ && configInCloud.getMaxChannelBandwidth() == storedConfig.getMaxChannelBandwidth()
+ );
+ }
+
private byte[] getNetworkPolicies() {
NetworkPolicyManager networkPolicyManager =
(NetworkPolicyManager) getSystemService(NETWORK_POLICY_SERVICE);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index ccfeae4..8683eac 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -771,6 +771,12 @@
Settings.Global.ANGLE_EGL_FEATURES,
GlobalSettingsProto.Gpu.ANGLE_EGL_FEATURES);
dumpSetting(s, p,
+ Settings.Global.ANGLE_DEFERLIST,
+ GlobalSettingsProto.Gpu.ANGLE_DEFERLIST);
+ dumpSetting(s, p,
+ Settings.Global.ANGLE_DEFERLIST_MODE,
+ GlobalSettingsProto.Gpu.ANGLE_DEFERLIST_MODE);
+ dumpSetting(s, p,
Settings.Global.SHOW_ANGLE_IN_USE_DIALOG_BOX,
GlobalSettingsProto.Gpu.SHOW_ANGLE_IN_USE_DIALOG);
dumpSetting(s, p,
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index f5466e7..031292e 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -511,6 +511,8 @@
Settings.Global.ANGLE_GL_DRIVER_SELECTION_PKGS,
Settings.Global.ANGLE_GL_DRIVER_SELECTION_VALUES,
Settings.Global.ANGLE_EGL_FEATURES,
+ Settings.Global.ANGLE_DEFERLIST,
+ Settings.Global.ANGLE_DEFERLIST_MODE,
Settings.Global.UPDATABLE_DRIVER_ALL_APPS,
Settings.Global.UPDATABLE_DRIVER_PRODUCTION_OPT_IN_APPS,
Settings.Global.UPDATABLE_DRIVER_PRERELEASE_OPT_IN_APPS,
@@ -650,7 +652,6 @@
Settings.Global.Wearable.CLOCKWORK_SYSUI_PACKAGE,
Settings.Global.Wearable.CLOCKWORK_SYSUI_MAIN_ACTIVITY,
Settings.Global.Wearable.CLOCKWORK_LONG_PRESS_TO_ASSISTANT_ENABLED,
- Settings.Global.Wearable.WEAR_ACTIVITY_AUTO_RESUME_TIMEOUT_SET_BY_USER,
Settings.Global.Wearable.WET_MODE_ON,
Settings.Global.Wearable.COOLDOWN_MODE_ON,
Settings.Global.Wearable.CHARGING_SOUNDS_ENABLED,
diff --git a/packages/Shell/res/values-hy/strings.xml b/packages/Shell/res/values-hy/strings.xml
index 33f76f0..ebe4cd9 100644
--- a/packages/Shell/res/values-hy/strings.xml
+++ b/packages/Shell/res/values-hy/strings.xml
@@ -23,11 +23,11 @@
<string name="bugreport_updating_title" msgid="4423539949559634214">"Տվյալների ավելացում վրիպակի զեկույցում"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Խնդրում ենք սպասել…"</string>
<string name="bugreport_finished_text" product="watch" msgid="1223616207145252689">"Վրիպակների մասին հաշվետվությունը շուտով կստանաք հեռախոսին"</string>
- <string name="bugreport_finished_text" product="tv" msgid="5758325479058638893">"Ընտրեք՝ վրիպակի զեկույցն ուղարկելու համար"</string>
- <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Հպեք՝ վրիպակի զեկույցը տրամադրելու համար"</string>
- <string name="bugreport_finished_pending_screenshot_text" product="tv" msgid="2343263822812016950">"Ընտրեք՝ վրիպակի զեկույցն առանց սքրինշոթի ուղարկելու համար կամ սպասեք սքրինշոթի ստեղծմանը"</string>
- <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Հպեք՝ վրիպակի զեկույցն առանց սքրինշոթի ուղարկելու համար կամ սպասեք սքրինշոթի ստեղծմանը"</string>
- <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Հպեք՝ վրիպակի զեկույցն առանց սքրինշոթի ուղարկելու համար կամ սպասեք սքրինշոթի ստեղծմանը"</string>
+ <string name="bugreport_finished_text" product="tv" msgid="5758325479058638893">"Ընտրեք՝ վրիպակի մասին հաղորդումն ուղարկելու համար"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Հպեք՝ վրիպակի մասին հաղորդմամբ կիսվելու համար"</string>
+ <string name="bugreport_finished_pending_screenshot_text" product="tv" msgid="2343263822812016950">"Ընտրեք՝ վրիպակի մասին հաղորդումն առանց սքրինշոթի ուղարկելու համար կամ սպասեք սքրինշոթի ստեղծմանը"</string>
+ <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Հպեք՝ վրիպակի մասին հաղորդումն առանց սքրինշոթի ուղարկելու համար կամ սպասեք սքրինշոթի ստեղծմանը"</string>
+ <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Հպեք՝ վրիպակի մասին հաղորդումն առանց սքրինշոթի ուղարկելու համար կամ սպասեք սքրինշոթի ստեղծմանը"</string>
<string name="bugreport_confirm" msgid="5917407234515812495">"Վրիպակի զեկույցները պարունակում են տվյալներ համակարգի տարբեր մատյաններից և կարող են ներառել տեղեկություններ, որոնք դուք գաղտնի եք համարում (օրինակ՝ հավելվածի օգտագործման կամ տեղադրության մասին): Վրիպակի զեկույցները տրամադրեք միայն վստահելի մարդկանց և հավելվածներին:"</string>
<string name="bugreport_confirm_dont_repeat" msgid="6179945398364357318">"Այլևս ցույց չտալ"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Վրիպակների հաշվետվություններ"</string>
@@ -43,5 +43,5 @@
<string name="bugreport_info_title" msgid="2306030793918239804">"Վրիպակի զեկույցի վերնագիրը"</string>
<string name="bugreport_info_description" msgid="5072835127481627722">"Վրիպակի զեկույցի ամփոփագիրը"</string>
<string name="save" msgid="4781509040564835759">"Պահել"</string>
- <string name="bugreport_intent_chooser_title" msgid="7605709494790894076">"Տրամադրե՞լ վրիպակի զեկույցը"</string>
+ <string name="bugreport_intent_chooser_title" msgid="7605709494790894076">"Կիսվե՞լ վրիպակի մասին հաղորդմամբ"</string>
</resources>
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 290ce34..5dd1b09 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -323,6 +323,8 @@
<!-- To read safety center status -->
<uses-permission android:name="android.permission.READ_SAFETY_CENTER_STATUS" />
+ <uses-permission android:name="android.permission.SET_UNRESTRICTED_KEEP_CLEAR_AREAS" />
+
<protected-broadcast android:name="com.android.settingslib.action.REGISTER_SLICE_RECEIVER" />
<protected-broadcast android:name="com.android.settingslib.action.UNREGISTER_SLICE_RECEIVER" />
<protected-broadcast android:name="com.android.settings.flashlight.action.FLASHLIGHT_CHANGED" />
@@ -721,7 +723,7 @@
android:excludeFromRecents="true"
android:stateNotNeeded="true"
android:resumeWhilePausing="true"
- android:theme="@android:style/Theme.Translucent.NoTitleBar.Fullscreen">
+ android:theme="@style/Theme.AppCompat.DayNight.NoActionBar">
<intent-filter>
<action android:name="android.app.action.CONFIRM_DEVICE_CREDENTIAL_WITH_USER" />
<category android:name="android.intent.category.DEFAULT" />
diff --git a/packages/SystemUI/TEST_MAPPING b/packages/SystemUI/TEST_MAPPING
index d146fc9..b01fd6d 100644
--- a/packages/SystemUI/TEST_MAPPING
+++ b/packages/SystemUI/TEST_MAPPING
@@ -124,49 +124,5 @@
}
]
}
- ],
- "hubui-postsubmit": [
- {
- "name": "PlatformScenarioTests",
- "options": [
- {
- "include-filter": "android.platform.test.scenario.hubui"
- },
- {
- "include-annotation": "android.platform.test.scenario.annotation.HubUi"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
- }
- ],
- "hubui-presubmit": [
- {
- "name": "PlatformScenarioTests",
- "options": [
- {
- "include-annotation": "android.platform.test.annotations.Presubmit"
- },
- {
- "include-annotation": "android.platform.test.scenario.annotation.HubUi"
- },
- {
- "include-filter": "android.platform.test.scenario.hubui"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "android.platform.test.annotations.Postsubmit"
- }
- ]
- }
]
}
diff --git a/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt b/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt
index dd45b6f..0c82022 100644
--- a/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt
+++ b/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt
@@ -21,7 +21,6 @@
import android.graphics.Color
import com.android.internal.graphics.ColorUtils
import com.android.internal.graphics.cam.Cam
-import com.android.internal.graphics.cam.CamUtils.lstarFromInt
import kotlin.math.absoluteValue
import kotlin.math.max
import kotlin.math.roundToInt
@@ -50,7 +49,7 @@
val previousHue = hueAndRotations[previousIndex].first
if (ColorScheme.angleIsBetween(sourceHue, thisHue, previousHue)) {
return ColorScheme.wrapDegreesDouble(sourceHue.toDouble() +
- hueAndRotations[previousIndex].first)
+ hueAndRotations[previousIndex].second)
}
}
@@ -143,12 +142,24 @@
}
}
+internal class ChromaMultiple(val multiple: Double) : Chroma {
+ override fun get(sourceColor: Cam): Double {
+ return sourceColor.chroma * multiple
+ }
+}
+
internal class ChromaConstant(val chroma: Double) : Chroma {
override fun get(sourceColor: Cam): Double {
return chroma
}
}
+internal class ChromaSource : Chroma {
+ override fun get(sourceColor: Cam): Double {
+ return sourceColor.chroma.toDouble()
+ }
+}
+
internal class TonalSpec(val hue: Hue = HueSource(), val chroma: Chroma) {
fun shades(sourceColor: Cam): List<Int> {
val hue = hue.get(sourceColor)
@@ -184,8 +195,8 @@
a1 = TonalSpec(HueSource(), ChromaMinimum(48.0)),
a2 = TonalSpec(HueVibrantSecondary(), ChromaConstant(24.0)),
a3 = TonalSpec(HueVibrantTertiary(), ChromaConstant(32.0)),
- n1 = TonalSpec(HueSource(), ChromaConstant(10.0)),
- n2 = TonalSpec(HueSource(), ChromaConstant(12.0))
+ n1 = TonalSpec(HueSource(), ChromaConstant(12.0)),
+ n2 = TonalSpec(HueSource(), ChromaConstant(14.0))
)),
EXPRESSIVE(CoreSpec(
a1 = TonalSpec(HueAdd(240.0), ChromaConstant(40.0)),
@@ -208,6 +219,13 @@
n1 = TonalSpec(HueSource(), ChromaConstant(10.0)),
n2 = TonalSpec(HueSource(), ChromaConstant(16.0))
)),
+ CONTENT(CoreSpec(
+ a1 = TonalSpec(HueSource(), ChromaSource()),
+ a2 = TonalSpec(HueSource(), ChromaMultiple(0.33)),
+ a3 = TonalSpec(HueSource(), ChromaMultiple(0.66)),
+ n1 = TonalSpec(HueSource(), ChromaMultiple(0.0833)),
+ n2 = TonalSpec(HueSource(), ChromaMultiple(0.1666))
+ )),
}
class ColorScheme(
@@ -231,7 +249,7 @@
darkTheme: Boolean,
style: Style = Style.TONAL_SPOT
):
- this(getSeedColor(wallpaperColors), darkTheme, style)
+ this(getSeedColor(wallpaperColors, style != Style.CONTENT), darkTheme, style)
val allAccentColors: List<Int>
get() {
@@ -260,7 +278,7 @@
val proposedSeedCam = Cam.fromInt(seed)
val seedArgb = if (seed == Color.TRANSPARENT) {
GOOGLE_BLUE
- } else if (proposedSeedCam.chroma < 5) {
+ } else if (style != Style.CONTENT && proposedSeedCam.chroma < 5) {
GOOGLE_BLUE
} else {
seed
@@ -289,22 +307,26 @@
* Identifies a color to create a color scheme from.
*
* @param wallpaperColors Colors extracted from an image via quantization.
+ * @param filter If false, allow colors that have low chroma, creating grayscale themes.
* @return ARGB int representing the color
*/
@JvmStatic
+ @JvmOverloads
@ColorInt
- fun getSeedColor(wallpaperColors: WallpaperColors): Int {
- return getSeedColors(wallpaperColors).first()
+ fun getSeedColor(wallpaperColors: WallpaperColors, filter: Boolean = true): Int {
+ return getSeedColors(wallpaperColors, filter).first()
}
/**
* Filters and ranks colors from WallpaperColors.
*
* @param wallpaperColors Colors extracted from an image via quantization.
+ * @param filter If false, allow colors that have low chroma, creating grayscale themes.
* @return List of ARGB ints, ordered from highest scoring to lowest.
*/
@JvmStatic
- fun getSeedColors(wallpaperColors: WallpaperColors): List<Int> {
+ @JvmOverloads
+ fun getSeedColors(wallpaperColors: WallpaperColors, filter: Boolean = true): List<Int> {
val totalPopulation = wallpaperColors.allColors.values.reduce { a, b -> a + b }
.toDouble()
val totalPopulationMeaningless = (totalPopulation == 0.0)
@@ -317,9 +339,12 @@
val distinctColors = wallpaperColors.mainColors.map {
it.toArgb()
}.distinct().filter {
- Cam.fromInt(it).chroma >= MIN_CHROMA
+ if (!filter) {
+ true
+ } else {
+ Cam.fromInt(it).chroma >= MIN_CHROMA
+ }
}.toList()
-
if (distinctColors.isEmpty()) {
return listOf(GOOGLE_BLUE)
}
@@ -332,7 +357,7 @@
val intToCam = wallpaperColors.allColors.mapValues { Cam.fromInt(it.key) }
// Get an array with 360 slots. A slot contains the percentage of colors with that hue.
- val hueProportions = huePopulations(intToCam, intToProportion)
+ val hueProportions = huePopulations(intToCam, intToProportion, filter)
// Map each color to the percentage of the image with its hue.
val intToHueProportion = wallpaperColors.allColors.mapValues {
val cam = intToCam[it.key]!!
@@ -346,13 +371,12 @@
// Remove any inappropriate seed colors. For example, low chroma colors look grayscale
// raising their chroma will turn them to a much louder color that may not have been
// in the image.
- val filteredIntToCam = intToCam.filter {
+ val filteredIntToCam = if (!filter) intToCam else (intToCam.filter {
val cam = it.value
- val lstar = lstarFromInt(it.key)
val proportion = intToHueProportion[it.key]!!
cam.chroma >= MIN_CHROMA &&
(totalPopulationMeaningless || proportion > 0.01)
- }
+ })
// Sort the colors by score, from high to low.
val intToScoreIntermediate = filteredIntToCam.mapValues {
score(it.value, intToHueProportion[it.key]!!)
@@ -444,7 +468,8 @@
private fun huePopulations(
camByColor: Map<Int, Cam>,
- populationByColor: Map<Int, Double>
+ populationByColor: Map<Int, Double>,
+ filter: Boolean = true
): List<Double> {
val huePopulation = List(size = 360, init = { 0.0 }).toMutableList()
@@ -452,7 +477,7 @@
val population = populationByColor[entry.key]!!
val cam = camByColor[entry.key]!!
val hue = cam.hue.roundToInt() % 360
- if (cam.chroma <= MIN_CHROMA) {
+ if (filter && cam.chroma <= MIN_CHROMA) {
continue
}
huePopulation[hue] = huePopulation[hue] + population
diff --git a/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml
index ca1e6b2..145bd2b 100644
--- a/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml
@@ -21,7 +21,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="keyguard_enter_your_pin" msgid="5429932527814874032">"請輸入 PIN"</string>
- <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"請畫出圖形"</string>
+ <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"請畫出圖案"</string>
<string name="keyguard_enter_your_password" msgid="7225626204122735501">"請輸入密碼"</string>
<string name="keyguard_sim_error_message_short" msgid="633630844240494070">"SIM 卡無效。"</string>
<string name="keyguard_charged" msgid="5478247181205188995">"已完成充電"</string>
@@ -50,7 +50,7 @@
<string name="error_disable_esim_title" msgid="3802652622784813119">"無法停用 eSIM 卡"</string>
<string name="error_disable_esim_msg" msgid="2441188596467999327">"發生錯誤,因此無法停用此 eSIM 卡。"</string>
<string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Enter 鍵 (輸入)"</string>
- <string name="kg_wrong_pattern" msgid="5907301342430102842">"圖形錯誤"</string>
+ <string name="kg_wrong_pattern" msgid="5907301342430102842">"圖案錯誤"</string>
<string name="kg_wrong_password" msgid="4143127991071670512">"密碼錯誤"</string>
<string name="kg_wrong_pin" msgid="4160978845968732624">"PIN 碼錯誤"</string>
<string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{請在 # 秒後再試一次。}other{請在 # 秒後再試一次。}}"</string>
@@ -66,7 +66,7 @@
<string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK 碼應由 8 個或以上數字組成。"</string>
<string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"您已輸入錯誤的 PIN 碼 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。\n\n請在 <xliff:g id="NUMBER_1">%2$d</xliff:g> 秒後再試一次。"</string>
<string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"您已輸入錯誤的密碼 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。\n\n請在 <xliff:g id="NUMBER_1">%2$d</xliff:g> 秒後再試一次。"</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"您已畫錯解鎖圖形 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。\n\n請在 <xliff:g id="NUMBER_1">%2$d</xliff:g> 秒後再試一次。"</string>
+ <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"您已畫錯解鎖圖案 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。\n\n請在 <xliff:g id="NUMBER_1">%2$d</xliff:g> 秒後再試一次。"</string>
<string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"SIM 卡 PIN 碼不正確,您現在必須聯絡流動網絡供應商為您的裝置解鎖。"</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
<item quantity="other">SIM 卡的 PIN 碼不正確,您還有 <xliff:g id="NUMBER_1">%d</xliff:g> 次輸入機會。</item>
@@ -81,10 +81,10 @@
<string name="kg_password_puk_failed" msgid="6778867411556937118">"無法使用 SIM 卡 PUK 碼解鎖!"</string>
<string name="accessibility_ime_switch_button" msgid="9082358310194861329">"轉換輸入方法"</string>
<string name="airplane_mode" msgid="2528005343938497866">"飛行模式"</string>
- <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"裝置重新啟動後,必須畫出上鎖圖形才能使用"</string>
+ <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"裝置重新啟動後,必須畫出上鎖圖案才能使用"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"裝置重新啟動後,必須輸入 PIN 碼才能使用"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"裝置重新啟動後,必須輸入密碼才能使用"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"請務必畫出上鎖圖形,以進一步確保安全"</string>
+ <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"請務必畫出上鎖圖案,以進一步確保安全"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"請務必輸入 PIN 碼,以進一步確保安全"</string>
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"請務必輸入密碼,以進一步確保安全"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"裝置已由管理員鎖定"</string>
diff --git a/packages/SystemUI/res-product/values-af/strings.xml b/packages/SystemUI/res-product/values-af/strings.xml
index 1d335c3..09c9127 100644
--- a/packages/SystemUI/res-product/values-af/strings.xml
+++ b/packages/SystemUI/res-product/values-af/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Ontsluit jou foon vir meer opsies"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Ontsluit jou tablet vir meer opsies"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Ontsluit jou toestel vir meer opsies"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"Speel tans op hierdie foon"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"Speel tans op hierdie tablet"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-am/strings.xml b/packages/SystemUI/res-product/values-am/strings.xml
index c11e856..c08e194 100644
--- a/packages/SystemUI/res-product/values-am/strings.xml
+++ b/packages/SystemUI/res-product/values-am/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"ለተጨማሪ አማራጮች የእርስዎን ስልክ ይክፈቱ"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"ለተጨማሪ አማራጮች የእርስዎን ጡባዊ ይክፈቱ"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"ለተጨማሪ አማራጮች የእርስዎን መሣሪያ ይክፈቱ"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"በዚህ ስልክ ላይ በመጫወት ላይ"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"በዚህ ጡባዊ ላይ በመጫወት ላይ"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-ar/strings.xml b/packages/SystemUI/res-product/values-ar/strings.xml
index a13136f..8922c27 100644
--- a/packages/SystemUI/res-product/values-ar/strings.xml
+++ b/packages/SystemUI/res-product/values-ar/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"يمكنك فتح قفل هاتفك للوصول إلى مزيد من الخيارات."</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"يمكنك فتح قفل جهازك اللوحي للوصول إلى مزيد من الخيارات."</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"يمكنك فتح قفل جهازك للوصول إلى مزيد من الخيارات."</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"جارٍ تشغيل الوسائط على هذا الهاتف."</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"جارٍ تشغيل الوسائط على هذا الجهاز اللوحي."</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-as/strings.xml b/packages/SystemUI/res-product/values-as/strings.xml
index aa9cb2d..c8aedb3 100644
--- a/packages/SystemUI/res-product/values-as/strings.xml
+++ b/packages/SystemUI/res-product/values-as/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"অধিক বিকল্পৰ বাবে আপোনাৰ ফ’নটো আনলক কৰক"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"অধিক বিকল্পৰ বাবে আপোনাৰ টেবলেটটো আনলক কৰক"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"অধিক বিকল্পৰ বাবে আপোনাৰ ডিভাইচটো আনলক কৰক"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"এই ফ’নটোত প্লে’ কৰি থকা হৈছে"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"এই টেবলেটটোত প্লে’ কৰি থকা হৈছে"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-az/strings.xml b/packages/SystemUI/res-product/values-az/strings.xml
index c0668db..fd514b3 100644
--- a/packages/SystemUI/res-product/values-az/strings.xml
+++ b/packages/SystemUI/res-product/values-az/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Daha çox seçim üçün telefonu kiliddən çıxarın"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Daha çox seçim üçün planşeti kiliddən çıxarın"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Daha çox seçim üçün cihazı kiliddən çıxarın"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"Bu telefonda oxudulur"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"Bu planşetdə oxudulur"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-b+sr+Latn/strings.xml b/packages/SystemUI/res-product/values-b+sr+Latn/strings.xml
index 7a27dd0..287b3f6 100644
--- a/packages/SystemUI/res-product/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res-product/values-b+sr+Latn/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Otključajte telefon za još opcija"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Otključajte tablet za još opcija"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Otključajte uređaj za još opcija"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"Pušta se na ovom telefonu"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"Pušta se na ovom tabletu"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-be/strings.xml b/packages/SystemUI/res-product/values-be/strings.xml
index 4fd7cc0..cf42bed 100644
--- a/packages/SystemUI/res-product/values-be/strings.xml
+++ b/packages/SystemUI/res-product/values-be/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Каб адкрыць іншыя параметры, разблакіруйце тэлефон"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Каб адкрыць іншыя параметры, разблакіруйце планшэт"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Каб адкрыць іншыя параметры, разблакіруйце прыладу"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"Прайграецца на гэтым тэлефоне"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"Прайграецца на гэтым планшэце"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-bg/strings.xml b/packages/SystemUI/res-product/values-bg/strings.xml
index cfdab24..182ffa9 100644
--- a/packages/SystemUI/res-product/values-bg/strings.xml
+++ b/packages/SystemUI/res-product/values-bg/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Отключете телефона си за още опции"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Отключете таблета си за още опции"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Отключете устройството си за още опции"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"Възпроизвежда се на този телефон"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"Възпроизвежда се на този таблет"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-bn/strings.xml b/packages/SystemUI/res-product/values-bn/strings.xml
index 214dd45..d54de52 100644
--- a/packages/SystemUI/res-product/values-bn/strings.xml
+++ b/packages/SystemUI/res-product/values-bn/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"আরও বিকল্প দেখতে আপনার ফোন আনলক করুন"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"আরও বিকল্প দেখতে আপনার ট্যাবলেট আনলক করুন"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"আরও বিকল্প দেখতে আপনার ডিভাইস আনলক করুন"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"এই ফোনে চালানো হচ্ছে"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"এই ট্যাবলেটে চালানো হচ্ছে"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-bs/strings.xml b/packages/SystemUI/res-product/values-bs/strings.xml
index ed5caae..9567125 100644
--- a/packages/SystemUI/res-product/values-bs/strings.xml
+++ b/packages/SystemUI/res-product/values-bs/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Otključajte telefon za više opcija"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Otključajte tablet za više opcija"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Otključajte uređaj za više opcija"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"Reproducira se na ovom telefonu"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"Reproducira se na ovom tabletu"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-ca/strings.xml b/packages/SystemUI/res-product/values-ca/strings.xml
index 4441792..d318b4e 100644
--- a/packages/SystemUI/res-product/values-ca/strings.xml
+++ b/packages/SystemUI/res-product/values-ca/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Desbloqueja el teu telèfon per veure més opcions"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Desbloqueja la teva tauleta per veure més opcions"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Desbloqueja el teu dispositiu per veure més opcions"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"S\'està reproduint en aquest telèfon"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"S\'està reproduint en aquesta tauleta"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-cs/strings.xml b/packages/SystemUI/res-product/values-cs/strings.xml
index aa6ba72..e1ee268 100644
--- a/packages/SystemUI/res-product/values-cs/strings.xml
+++ b/packages/SystemUI/res-product/values-cs/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Chcete-li zobrazit další možnosti, odemkněte telefon"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Chcete-li zobrazit další možnosti, odemkněte tablet"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Chcete-li zobrazit další možnosti, odemkněte zařízení"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"Přehrávání na tomto telefonu"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"Přehrávání na tomto tabletu"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-da/strings.xml b/packages/SystemUI/res-product/values-da/strings.xml
index 5b2112e..55bda69 100644
--- a/packages/SystemUI/res-product/values-da/strings.xml
+++ b/packages/SystemUI/res-product/values-da/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Lås din telefon op for at se flere valgmuligheder"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Lås din tablet op for at se flere valgmuligheder"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Lås din enhed op for at se flere valgmuligheder"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"Afspilles på denne telefon"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"Afspilles på denne tablet"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-de/strings.xml b/packages/SystemUI/res-product/values-de/strings.xml
index a84413d..b8d1a7c 100644
--- a/packages/SystemUI/res-product/values-de/strings.xml
+++ b/packages/SystemUI/res-product/values-de/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Entsperre dein Smartphone für weitere Optionen"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Entsperre dein Tablet für weitere Optionen"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Entsperre dein Gerät für weitere Optionen"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"Wird auf diesem Smartphone abgespielt"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"Wird auf diesem Tablet abgespielt"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-el/strings.xml b/packages/SystemUI/res-product/values-el/strings.xml
index 8dd9ec2..3d38be4 100644
--- a/packages/SystemUI/res-product/values-el/strings.xml
+++ b/packages/SystemUI/res-product/values-el/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Ξεκλειδώστε το τηλέφωνό σας για περισσότερες επιλογές"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Ξεκλειδώστε το tablet για περισσότερες επιλογές"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Ξεκλειδώστε τη συσκευή σας για περισσότερες επιλογές"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"Αναπαραγωγή σε αυτό το τηλέφωνο"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"Αναπαραγωγή σε αυτό το tablet"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-en-rAU/strings.xml b/packages/SystemUI/res-product/values-en-rAU/strings.xml
index 3de7b65..04e63f5 100644
--- a/packages/SystemUI/res-product/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res-product/values-en-rAU/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Unlock your phone for more options"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Unlock your tablet for more options"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Unlock your device for more options"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"Playing on this phone"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"Playing on this tablet"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-en-rCA/strings.xml b/packages/SystemUI/res-product/values-en-rCA/strings.xml
index 3de7b65..04e63f5 100644
--- a/packages/SystemUI/res-product/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res-product/values-en-rCA/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Unlock your phone for more options"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Unlock your tablet for more options"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Unlock your device for more options"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"Playing on this phone"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"Playing on this tablet"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-en-rGB/strings.xml b/packages/SystemUI/res-product/values-en-rGB/strings.xml
index 3de7b65..04e63f5 100644
--- a/packages/SystemUI/res-product/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res-product/values-en-rGB/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Unlock your phone for more options"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Unlock your tablet for more options"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Unlock your device for more options"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"Playing on this phone"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"Playing on this tablet"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-en-rIN/strings.xml b/packages/SystemUI/res-product/values-en-rIN/strings.xml
index 3de7b65..04e63f5 100644
--- a/packages/SystemUI/res-product/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res-product/values-en-rIN/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Unlock your phone for more options"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Unlock your tablet for more options"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Unlock your device for more options"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"Playing on this phone"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"Playing on this tablet"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-en-rXC/strings.xml b/packages/SystemUI/res-product/values-en-rXC/strings.xml
index 022c5b3..aa895e1 100644
--- a/packages/SystemUI/res-product/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res-product/values-en-rXC/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Unlock your phone for more options"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Unlock your tablet for more options"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Unlock your device for more options"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"Playing on this phone"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"Playing on this tablet"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-es-rUS/strings.xml b/packages/SystemUI/res-product/values-es-rUS/strings.xml
index b333479..7e0eec6 100644
--- a/packages/SystemUI/res-product/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res-product/values-es-rUS/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Desbloquea el teléfono para ver más opciones"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Desbloquea la tablet para ver más opciones"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Desbloquea el dispositivo para ver más opciones"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"Reproduciendo en este teléfono"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"Reproduciendo en esta tablet"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-es/strings.xml b/packages/SystemUI/res-product/values-es/strings.xml
index 03ff2ff..970c615 100644
--- a/packages/SystemUI/res-product/values-es/strings.xml
+++ b/packages/SystemUI/res-product/values-es/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Desbloquea el teléfono para ver más opciones"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Desbloquea el tablet para ver más opciones"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Desbloquea el dispositivo para ver más opciones"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"Reproduciendo en este teléfono"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"Reproduciendo en este tablet"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-et/strings.xml b/packages/SystemUI/res-product/values-et/strings.xml
index 01060cb..ae463f2 100644
--- a/packages/SystemUI/res-product/values-et/strings.xml
+++ b/packages/SystemUI/res-product/values-et/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Lisavalikute nägemiseks avage oma telefon"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Lisavalikute nägemiseks avage oma tahvelarvuti"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Lisavalikute nägemiseks avage oma seade"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"Esitatakse selles telefonis"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"Esitatakse selles tahvelarvutis"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-eu/strings.xml b/packages/SystemUI/res-product/values-eu/strings.xml
index e6cf28d..7cf68f6 100644
--- a/packages/SystemUI/res-product/values-eu/strings.xml
+++ b/packages/SystemUI/res-product/values-eu/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Desblokeatu telefonoa aukera gehiago ikusteko"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Desblokeatu tableta aukera gehiago ikusteko"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Desblokeatu gailua aukera gehiago ikusteko"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"Telefono honetan erreproduzitzen"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"Tableta honetan erreproduzitzen"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-fa/strings.xml b/packages/SystemUI/res-product/values-fa/strings.xml
index cd98ef6..5ff3011 100644
--- a/packages/SystemUI/res-product/values-fa/strings.xml
+++ b/packages/SystemUI/res-product/values-fa/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"برای گزینههای بیشتر، قفل تلفن را باز کنید"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"برای گزینههای بیشتر، قفل رایانه لوحی را باز کنید"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"برای گزینههای بیشتر، قفل دستگاه را باز کنید"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"درحال پخش در این تلفن"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"درحال پخش در این رایانه لوحی"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-fi/strings.xml b/packages/SystemUI/res-product/values-fi/strings.xml
index 4001b30..55a65ea 100644
--- a/packages/SystemUI/res-product/values-fi/strings.xml
+++ b/packages/SystemUI/res-product/values-fi/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Avaa puhelimen lukitus, niin näet enemmän vaihtoehtoja"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Avaa tabletin lukitus, niin näet enemmän vaihtoehtoja"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Avaa laitteen lukitus, niin näet enemmän vaihtoehtoja"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"Toistetaan tällä puhelimella"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"Toistetaan tällä tabletilla"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-fr-rCA/strings.xml b/packages/SystemUI/res-product/values-fr-rCA/strings.xml
index 0849256..1ffa042 100644
--- a/packages/SystemUI/res-product/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res-product/values-fr-rCA/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Déverrouillez votre téléphone pour afficher davantage d\'options"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Déverrouillez votre tablette pour afficher davantage d\'options"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Déverrouillez votre appareil pour afficher davantage d\'options"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"Lecture sur ce téléphone"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"Lecture sur cette tablette"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-fr/strings.xml b/packages/SystemUI/res-product/values-fr/strings.xml
index 1bbb759..a07c8d8 100644
--- a/packages/SystemUI/res-product/values-fr/strings.xml
+++ b/packages/SystemUI/res-product/values-fr/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Déverrouillez votre téléphone pour obtenir plus d\'options"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Déverrouillez votre tablette pour obtenir plus d\'options"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Déverrouillez votre appareil pour obtenir plus d\'options"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"Lecture sur ce téléphone…"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"Lecture sur cette tablette…"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-gl/strings.xml b/packages/SystemUI/res-product/values-gl/strings.xml
index 6f034fb..25fbb25 100644
--- a/packages/SystemUI/res-product/values-gl/strings.xml
+++ b/packages/SystemUI/res-product/values-gl/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Desbloquea o teléfono para ver máis opcións"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Desbloquea a tableta para ver máis opcións"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Desbloquea o dispositivo para ver máis opcións"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"Reproducindo contido neste teléfono"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"Reproducindo contido nesta tableta"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-gu/strings.xml b/packages/SystemUI/res-product/values-gu/strings.xml
index 9839b42..b889dcc 100644
--- a/packages/SystemUI/res-product/values-gu/strings.xml
+++ b/packages/SystemUI/res-product/values-gu/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"વધુ વિકલ્પો માટે તમારા ફોનને અનલૉક કરો"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"વધુ વિકલ્પો માટે તમારા ટૅબ્લેટને અનલૉક કરો"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"વધુ વિકલ્પો માટે તમારા ડિવાઇસને અનલૉક કરો"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"આ ફોન પર ચલાવવામાં આવી રહ્યું છે"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"આ ટૅબ્લેટ પર ચલાવવામાં આવી રહ્યું છે"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-hi/strings.xml b/packages/SystemUI/res-product/values-hi/strings.xml
index 83c67e2..f148fc5 100644
--- a/packages/SystemUI/res-product/values-hi/strings.xml
+++ b/packages/SystemUI/res-product/values-hi/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"ज़्यादा विकल्प देखने के लिए, अपना फ़ोन अनलॉक करें"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"ज़्यादा विकल्प देखने के लिए, अपना टैबलेट अनलॉक करें"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"ज़्यादा विकल्प देखने के लिए, अपना डिवाइस अनलॉक करें"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"मीडिया इस फ़ोन पर चल रहा है"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"मीडिया इस टैबलेट पर चल रहा है"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-hr/strings.xml b/packages/SystemUI/res-product/values-hr/strings.xml
index 13f0023..73ffd62 100644
--- a/packages/SystemUI/res-product/values-hr/strings.xml
+++ b/packages/SystemUI/res-product/values-hr/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Za više opcija otključajte telefon"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Za više opcija otključajte tablet"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Za više opcija otključajte uređaj"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"Reproducira se na ovom telefonu"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"Reproducira se na ovom tabletu"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-hu/strings.xml b/packages/SystemUI/res-product/values-hu/strings.xml
index 743e2082..19d79d3 100644
--- a/packages/SystemUI/res-product/values-hu/strings.xml
+++ b/packages/SystemUI/res-product/values-hu/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"További lehetőségekért oldja fel a telefont"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"További lehetőségekért oldja fel a táblagépet"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"További lehetőségekért oldja fel az eszközt"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"Lejátszás ezen a telefonon"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"Lejátszás ezen a táblagépen"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-hy/strings.xml b/packages/SystemUI/res-product/values-hy/strings.xml
index f245562..17f42a0 100644
--- a/packages/SystemUI/res-product/values-hy/strings.xml
+++ b/packages/SystemUI/res-product/values-hy/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Ապակողպեք ձեր հեռախոսը՝ լրացուցիչ կարգավորումները տեսնելու համար"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Ապակողպեք ձեր պլանշետը՝ լրացուցիչ կարգավորումները տեսնելու համար"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Ապակողպեք ձեր սարքը՝ լրացուցիչ կարգավորումները տեսնելու համար"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"Նվագարկվում է այս հեռախոսում"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"Նվագարկվում է այս պլանշետում"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-in/strings.xml b/packages/SystemUI/res-product/values-in/strings.xml
index 1451e2c..15d8f39 100644
--- a/packages/SystemUI/res-product/values-in/strings.xml
+++ b/packages/SystemUI/res-product/values-in/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Buka kunci ponsel untuk melihat opsi lainnya"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Buka kunci tablet untuk melihat opsi lainnya"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Buka kunci perangkat untuk melihat opsi lainnya"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"Diputar di ponsel ini"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"Diputar di tablet ini"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-is/strings.xml b/packages/SystemUI/res-product/values-is/strings.xml
index 32f6e21..b24871c 100644
--- a/packages/SystemUI/res-product/values-is/strings.xml
+++ b/packages/SystemUI/res-product/values-is/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Taktu símann úr lás til að fá fleiri valkosti"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Taktu spjaldtölvuna úr lás til að fá fleiri valkosti"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Taktu tækið úr lás til að fá fleiri valkosti"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"Í spilun í þessum síma"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"Í spilun í þessari spjaldtölvu"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-it/strings.xml b/packages/SystemUI/res-product/values-it/strings.xml
index 3403f31..8e9875d 100644
--- a/packages/SystemUI/res-product/values-it/strings.xml
+++ b/packages/SystemUI/res-product/values-it/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Sblocca il telefono per visualizzare altre opzioni"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Sblocca il tablet per visualizzare altre opzioni"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Sblocca il dispositivo per visualizzare altre opzioni"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"In riproduzione su questo telefono"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"In riproduzione su questo tablet"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-iw/strings.xml b/packages/SystemUI/res-product/values-iw/strings.xml
index a5c7aaa..b3aa028 100644
--- a/packages/SystemUI/res-product/values-iw/strings.xml
+++ b/packages/SystemUI/res-product/values-iw/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"לאפשרויות נוספות, יש לבטל את נעילת הטלפון"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"לאפשרויות נוספות, יש לבטל את נעילת הטאבלט"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"לאפשרויות נוספות, יש לבטל את נעילת המכשיר"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"פועלת בטלפון הזה"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"פועלת בטאבלט הזה"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-ja/strings.xml b/packages/SystemUI/res-product/values-ja/strings.xml
index 0e7497a..c51a04c 100644
--- a/packages/SystemUI/res-product/values-ja/strings.xml
+++ b/packages/SystemUI/res-product/values-ja/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"スマートフォンのロックを解除してその他のオプションを表示する"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"タブレットのロックを解除してその他のオプションを表示する"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"デバイスのロックを解除してその他のオプションを表示する"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"このスマートフォンで再生しています"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"このタブレットで再生しています"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-ka/strings.xml b/packages/SystemUI/res-product/values-ka/strings.xml
index 3d04a3c..1b496cc 100644
--- a/packages/SystemUI/res-product/values-ka/strings.xml
+++ b/packages/SystemUI/res-product/values-ka/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"მეტი ვარიანტის სანახავად განბლოკეთ თქვენი ტელეფონი"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"მეტი ვარიანტის სანახავად განბლოკეთ თქვენი ტაბლეტი"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"მეტი ვარიანტის სანახავად განბლოკეთ თქვენი მოწყობილობა"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"უკრავს ტელეფონზე"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"უკრავს ამ ტაბლეტზე"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-kk/strings.xml b/packages/SystemUI/res-product/values-kk/strings.xml
index 2629667..8cfda7e 100644
--- a/packages/SystemUI/res-product/values-kk/strings.xml
+++ b/packages/SystemUI/res-product/values-kk/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Басқа опцияларды көру үшін телефон құлпын ашыңыз."</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Басқа опцияларды көру үшін планшет құлпын ашыңыз."</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Басқа опцияларды көру үшін құрылғы құлпын ашыңыз."</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"Осы телефонда ойнатылуда."</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"Осы планшетте ойнатылуда."</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-km/strings.xml b/packages/SystemUI/res-product/values-km/strings.xml
index 0a840ed..035432d 100644
--- a/packages/SystemUI/res-product/values-km/strings.xml
+++ b/packages/SystemUI/res-product/values-km/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"ដោះសោទូរសព្ទរបស់អ្នកសម្រាប់ជម្រើសច្រើនទៀត"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"ដោះសោថេប្លេតរបស់អ្នកសម្រាប់ជម្រើសច្រើនទៀត"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"ដោះសោឧបករណ៍របស់អ្នកសម្រាប់ជម្រើសច្រើនទៀត"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"កំពុងចាក់នៅលើទូរសព្ទនេះ"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"កំពុងចាក់នៅលើថេប្លេតនេះ"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-kn/strings.xml b/packages/SystemUI/res-product/values-kn/strings.xml
index 1b0f8bd..d795cef 100644
--- a/packages/SystemUI/res-product/values-kn/strings.xml
+++ b/packages/SystemUI/res-product/values-kn/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"ಹೆಚ್ಚಿನ ಆಯ್ಕೆಗಳಿಗಾಗಿ ನಿಮ್ಮ ಫೋನ್ ಅನ್ನು ಅನ್ಲಾಕ್ ಮಾಡಿ"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"ಹೆಚ್ಚಿನ ಆಯ್ಕೆಗಳಿಗಾಗಿ ನಿಮ್ಮ ಟ್ಯಾಬ್ಲೆಟ್ ಅನ್ನು ಅನ್ಲಾಕ್ ಮಾಡಿ"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"ಹೆಚ್ಚಿನ ಆಯ್ಕೆಗಳಿಗಾಗಿ ನಿಮ್ಮ ಸಾಧನವನ್ನು ಅನ್ಲಾಕ್ ಮಾಡಿ"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"ಈ ಫೋನ್ನಲ್ಲಿ ಪ್ಲೇ ಆಗುತ್ತಿದೆ"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"ಈ ಟ್ಯಾಬ್ಲೆಟ್ನಲ್ಲಿ ಪ್ಲೇ ಮಾಡಲಾಗುತ್ತಿದೆ"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-ko/strings.xml b/packages/SystemUI/res-product/values-ko/strings.xml
index 3629f2f..651662f 100644
--- a/packages/SystemUI/res-product/values-ko/strings.xml
+++ b/packages/SystemUI/res-product/values-ko/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"더 많은 옵션을 확인하려면 휴대전화를 잠금 해제하세요."</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"더 많은 옵션을 확인하려면 태블릿을 잠금 해제하세요."</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"더 많은 옵션을 확인하려면 기기를 잠금 해제하세요."</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"이 휴대전화에서 재생 중"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"이 태블릿에서 재생 중"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-ky/strings.xml b/packages/SystemUI/res-product/values-ky/strings.xml
index 00265a1..7c54729 100644
--- a/packages/SystemUI/res-product/values-ky/strings.xml
+++ b/packages/SystemUI/res-product/values-ky/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Дагы башка параметрлерди көрүү үчүн телефонуңуздун кулпусун ачыңыз"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Дагы башка параметрлерди көрүү үчүн планшетиңиздин кулпусун ачыңыз"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Дагы башка параметрлерди көрүү үчүн түзмөгүңүздүн кулпусун ачыңыз"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"Ушул телефондо ойнотулууда"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"Ушул планшетте ойнотулууда"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-lo/strings.xml b/packages/SystemUI/res-product/values-lo/strings.xml
index 2b262e7..b6479d6 100644
--- a/packages/SystemUI/res-product/values-lo/strings.xml
+++ b/packages/SystemUI/res-product/values-lo/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"ປົດລັອກໂທລະສັບຂອງທ່ານເພື່ອໃຊ້ຕົວເລືອກເພີ່ມເຕີມ"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"ປົດລັອກແທັບເລັດຂອງທ່ານເພື່ອໃຊ້ຕົວເລືອກເພີ່ມເຕີມ"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"ປົດລັອກອຸປະກອນຂອງທ່ານເພື່ອໃຊ້ຕົວເລືອກເພີ່ມເຕີມ"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"ກຳລັງຫຼິ້ນຢູ່ໂທລະສັບນີ້"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"ກຳລັງຫຼິ້ນຢູ່ແທັບເລັດນີ້"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-lt/strings.xml b/packages/SystemUI/res-product/values-lt/strings.xml
index 8ac5895..560e36e 100644
--- a/packages/SystemUI/res-product/values-lt/strings.xml
+++ b/packages/SystemUI/res-product/values-lt/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Atrakinkite telefoną, kad galėtumėte naudoti daugiau parinkčių"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Atrakinkite planšetinį kompiuterį, kad galėtumėte naudoti daugiau parinkčių"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Atrakinkite įrenginį, kad galėtumėte naudoti daugiau parinkčių"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"Leidžiama šiame telefone"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"Leidžiama šiame planšetiniame kompiuteryje"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-lv/strings.xml b/packages/SystemUI/res-product/values-lv/strings.xml
index 174f5d2..3c64f62 100644
--- a/packages/SystemUI/res-product/values-lv/strings.xml
+++ b/packages/SystemUI/res-product/values-lv/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Atbloķējiet tālruni, lai skatītu citas opcijas."</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Atbloķējiet planšetdatoru, lai skatītu citas opcijas."</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Atbloķējiet ierīci, lai skatītu citas opcijas."</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"Notiek atskaņošana šajā tālrunī"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"Notiek atskaņošana šajā planšetdatorā"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-mk/strings.xml b/packages/SystemUI/res-product/values-mk/strings.xml
index 86ff8d1..d5895bf 100644
--- a/packages/SystemUI/res-product/values-mk/strings.xml
+++ b/packages/SystemUI/res-product/values-mk/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Отклучето го вашиот телефон за повеќе опции"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Отклучето го вашиот таблет за повеќе опции"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Отклучето го вашиот уред за повеќе опции"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"Пуштено на овој телефон"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"Пуштено на овој таблет"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-ml/strings.xml b/packages/SystemUI/res-product/values-ml/strings.xml
index fc322d6..59f3eb5 100644
--- a/packages/SystemUI/res-product/values-ml/strings.xml
+++ b/packages/SystemUI/res-product/values-ml/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"കൂടുതൽ ഓപ്ഷനുകൾക്ക് നിങ്ങളുടെ ഫോൺ അൺലോക്ക് ചെയ്യുക"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"കൂടുതൽ ഓപ്ഷനുകൾക്ക് നിങ്ങളുടെ ടാബ്ലെറ്റ് അൺലോക്ക് ചെയ്യുക"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"കൂടുതൽ ഓപ്ഷനുകൾക്ക് നിങ്ങളുടെ ഉപകരണം അൺലോക്ക് ചെയ്യുക"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"ഈ ഫോണിൽ പ്ലേ ചെയ്യുന്നു"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"ഈ ടാബ്ലെറ്റിൽ പ്ലേ ചെയ്യുന്നു"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-mn/strings.xml b/packages/SystemUI/res-product/values-mn/strings.xml
index 0b47eb0..41eb52d 100644
--- a/packages/SystemUI/res-product/values-mn/strings.xml
+++ b/packages/SystemUI/res-product/values-mn/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Бусад сонголтыг харахын тулд утасныхаа түгжээг тайлна уу"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Бусад сонголтыг харахын тулд таблетынхаа түгжээг тайлна уу"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Бусад сонголтыг харахын тулд төхөөрөмжийнхөө түгжээг тайлна уу"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"Энэ утсан дээр тоглуулж байна"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"Энэ таблет дээр тоглуулж байна"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-mr/strings.xml b/packages/SystemUI/res-product/values-mr/strings.xml
index c9cd4ba..ec277cc 100644
--- a/packages/SystemUI/res-product/values-mr/strings.xml
+++ b/packages/SystemUI/res-product/values-mr/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"आणखी पर्यायांसाठी तुमचा फोन अनलॉक करा"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"आणखी पर्यायांसाठी तुमचा टॅबलेट अनलॉक करा"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"आणखी पर्यायांसाठी तुमचे डिव्हाइस अनलॉक करा"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"या फोनवर प्ले होत आहे"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"या टॅबलेटवर प्ले होत आहे"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-ms/strings.xml b/packages/SystemUI/res-product/values-ms/strings.xml
index ded2b3d..7b247a0 100644
--- a/packages/SystemUI/res-product/values-ms/strings.xml
+++ b/packages/SystemUI/res-product/values-ms/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Buka kunci telefon anda untuk mendapatkan lagi pilihan"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Buka kunci tablet anda untuk mendapatkan lagi pilihan"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Buka kunci peranti anda untuk mendapatkan lagi pilihan"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"Dimainkan pada telefon ini"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"Dimainkan pada tablet ini"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-my/strings.xml b/packages/SystemUI/res-product/values-my/strings.xml
index 43c2aca..d15df82 100644
--- a/packages/SystemUI/res-product/values-my/strings.xml
+++ b/packages/SystemUI/res-product/values-my/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"နောက်ထပ် ထိန်းချုပ်မှုများအတွက် သင့်ဖုန်းကို လော့ခ်ဖွင့်ပါ"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"နောက်ထပ် ထိန်းချုပ်မှုများအတွက် သင့်တက်ဘလက်ကို လော့ခ်ဖွင့်ပါ"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"နောက်ထပ် ထိန်းချုပ်မှုများအတွက် သင့်စက်ကို လော့ခ်ဖွင့်ပါ"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"ဤဖုန်းတွင် ဖွင့်နေသည်"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"ဤတက်ဘလက်တွင် ဖွင့်နေသည်"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-nb/strings.xml b/packages/SystemUI/res-product/values-nb/strings.xml
index c7d5bb1..816e9c1 100644
--- a/packages/SystemUI/res-product/values-nb/strings.xml
+++ b/packages/SystemUI/res-product/values-nb/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Lås opp telefonen din for å få flere alternativer"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Lås opp nettbrettet ditt for å få flere alternativer"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Lås opp enheten din for å få flere alternativer"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"Spilles av på denne telefonen"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"Spilles av på dette nettbrettet"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-ne/strings.xml b/packages/SystemUI/res-product/values-ne/strings.xml
index 3150244..eef80b2 100644
--- a/packages/SystemUI/res-product/values-ne/strings.xml
+++ b/packages/SystemUI/res-product/values-ne/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"थप विकल्पहरू हेर्न आफ्नो फोन अनलक गर्नुहोस्"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"थप विकल्पहरू हेर्न आफ्नो ट्याब्लेट अनलक गर्नुहोस्"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"थप विकल्पहरू हेर्न आफ्नो डिभाइस अनलक गर्नुहोस्"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"यो फोनमा प्ले गरिँदै छ"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"यो ट्याब्लेटमा प्ले गरिँदै छ"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-nl/strings.xml b/packages/SystemUI/res-product/values-nl/strings.xml
index 015ff3e..95e32ef 100644
--- a/packages/SystemUI/res-product/values-nl/strings.xml
+++ b/packages/SystemUI/res-product/values-nl/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Ontgrendel je telefoon voor meer opties"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Ontgrendel je tablet voor meer opties"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Ontgrendel je apparaat voor meer opties"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"Afspelen op deze telefoon"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"Afspelen op deze tablet"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-or/strings.xml b/packages/SystemUI/res-product/values-or/strings.xml
index f0525c9..e0d9366 100644
--- a/packages/SystemUI/res-product/values-or/strings.xml
+++ b/packages/SystemUI/res-product/values-or/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"ଅଧିକ ବିକଳ୍ପ ପାଇଁ ଆପଣଙ୍କ ଫୋନ୍ ଅନଲକ୍ କରନ୍ତୁ"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"ଅଧିକ ବିକଳ୍ପ ପାଇଁ ଆପଣଙ୍କ ଟାବଲେଟ୍ ଅନଲକ୍ କରନ୍ତୁ"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"ଅଧିକ ବିକଳ୍ପ ପାଇଁ ଆପଣଙ୍କ ଡିଭାଇସ୍ ଅନଲକ୍ କରନ୍ତୁ"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"ଏହି ଫୋନରେ ପ୍ଲେ ହେଉଛି"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"ଏହି ଟାବଲେଟରେ ପ୍ଲେ ହେଉଛି"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-pa/strings.xml b/packages/SystemUI/res-product/values-pa/strings.xml
index fa6cc3b..d65998b 100644
--- a/packages/SystemUI/res-product/values-pa/strings.xml
+++ b/packages/SystemUI/res-product/values-pa/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"ਹੋਰ ਵਿਕਲਪਾਂ ਲਈ ਆਪਣਾ ਫ਼ੋਨ ਅਣਲਾਕ ਕਰੋ"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"ਹੋਰ ਵਿਕਲਪਾਂ ਲਈ ਆਪਣਾ ਟੈਬਲੈੱਟ ਅਣਲਾਕ ਕਰੋ"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"ਹੋਰ ਵਿਕਲਪਾਂ ਲਈ ਆਪਣਾ ਡੀਵਾਈਸ ਅਣਲਾਕ ਕਰੋ"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"ਇਸ ਫ਼ੋਨ \'ਤੇ ਚਲਾਇਆ ਜਾ ਰਿਹਾ ਹੈ"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"ਇਸ ਟੈਬਲੈੱਟ \'ਤੇ ਚਲਾਇਆ ਜਾ ਰਿਹਾ ਹੈ"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-pl/strings.xml b/packages/SystemUI/res-product/values-pl/strings.xml
index 5ac3d84..f6360eb 100644
--- a/packages/SystemUI/res-product/values-pl/strings.xml
+++ b/packages/SystemUI/res-product/values-pl/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Odblokuj telefon, by wyświetlić więcej opcji"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Odblokuj tablet, by wyświetlić więcej opcji"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Odblokuj urządzenie, by wyświetlić więcej opcji"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"Odtwarzam na tym telefonie"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"Odtwarzam na tym tablecie"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-pt-rBR/strings.xml b/packages/SystemUI/res-product/values-pt-rBR/strings.xml
index 499850a..b287fd9 100644
--- a/packages/SystemUI/res-product/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res-product/values-pt-rBR/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Desbloqueie seu smartphone para ver mais opções"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Desbloqueie seu tablet para ver mais opções"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Desbloqueie seu dispositivo para ver mais opções"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"Mídia aberta neste smartphone"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"Mídia aberta neste tablet"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-pt-rPT/strings.xml b/packages/SystemUI/res-product/values-pt-rPT/strings.xml
index 22166bd..678bd26 100644
--- a/packages/SystemUI/res-product/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res-product/values-pt-rPT/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Desbloqueie o telemóvel para obter mais opções."</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Desbloqueie o tablet para obter mais opções."</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Desbloqueie o dispositivo para obter mais opções."</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"A reproduzir neste telemóvel"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"A reproduzir neste tablet"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-pt/strings.xml b/packages/SystemUI/res-product/values-pt/strings.xml
index 499850a..b287fd9 100644
--- a/packages/SystemUI/res-product/values-pt/strings.xml
+++ b/packages/SystemUI/res-product/values-pt/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Desbloqueie seu smartphone para ver mais opções"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Desbloqueie seu tablet para ver mais opções"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Desbloqueie seu dispositivo para ver mais opções"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"Mídia aberta neste smartphone"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"Mídia aberta neste tablet"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-ro/strings.xml b/packages/SystemUI/res-product/values-ro/strings.xml
index 4740501..54dc73a 100644
--- a/packages/SystemUI/res-product/values-ro/strings.xml
+++ b/packages/SystemUI/res-product/values-ro/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Deblocați telefonul pentru mai multe opțiuni"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Deblocați tableta pentru mai multe opțiuni"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Deblocați dispozitivul pentru mai multe opțiuni"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"Se redă pe acest telefon"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"Se redă pe această tabletă"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-ru/strings.xml b/packages/SystemUI/res-product/values-ru/strings.xml
index e622dbc..0d0dd1c 100644
--- a/packages/SystemUI/res-product/values-ru/strings.xml
+++ b/packages/SystemUI/res-product/values-ru/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Чтобы посмотреть дополнительные параметры, разблокируйте телефон."</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Чтобы посмотреть дополнительные параметры, разблокируйте планшет."</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Чтобы посмотреть дополнительные параметры, разблокируйте устройство."</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"Воспроизводится на этом телефоне."</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"Воспроизводится на этом планшете."</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-si/strings.xml b/packages/SystemUI/res-product/values-si/strings.xml
index efb2cde..0d7b67d 100644
--- a/packages/SystemUI/res-product/values-si/strings.xml
+++ b/packages/SystemUI/res-product/values-si/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"තව විකල්ප සඳහා ඔබේ දුරකථනය අගුලු හරින්න"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"තව විකල්ප සඳහා ඔබේ ටැබ්ලට් පරිගණකය අගුලු හරින්න"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"තව විකල්ප සඳහා ඔබේ උපාංගය අගුලු හරින්න"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"මෙම දුරකථනයෙහි වාදනය වේ"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"මෙම ටැබ්ලටයේ වාදනය වේ"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-sk/strings.xml b/packages/SystemUI/res-product/values-sk/strings.xml
index a7b6f0a..3caddbe 100644
--- a/packages/SystemUI/res-product/values-sk/strings.xml
+++ b/packages/SystemUI/res-product/values-sk/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Ak chcete zobraziť ďalšie možnosti, odomknite telefón"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Ak chcete zobraziť ďalšie možnosti, odomknite tablet"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Ak chcete zobraziť ďalšie možnosti, odomknite zariadenie"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"Prehráva sa v tomto telefóne"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"Prehráva sa v tomto tablete"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-sl/strings.xml b/packages/SystemUI/res-product/values-sl/strings.xml
index db55db8..96ac31b 100644
--- a/packages/SystemUI/res-product/values-sl/strings.xml
+++ b/packages/SystemUI/res-product/values-sl/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Za več možnosti odklenite telefon"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Za več možnosti odklenite tablični računalnik"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Za več možnosti odklenite napravo"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"Predvajanje v tem telefonu"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"Predvajanje v tem tabličnem računalniku"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-sq/strings.xml b/packages/SystemUI/res-product/values-sq/strings.xml
index cc444c2..f552b29 100644
--- a/packages/SystemUI/res-product/values-sq/strings.xml
+++ b/packages/SystemUI/res-product/values-sq/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Shkyçe telefonin për më shumë opsione"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Shkyçe tabletin për më shumë opsione"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Shkyçe pajisjen për më shumë opsione"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"Po luhet në këtë telefon"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"Po luhet në këtë tablet"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-sr/strings.xml b/packages/SystemUI/res-product/values-sr/strings.xml
index f22d640..f1e6eec 100644
--- a/packages/SystemUI/res-product/values-sr/strings.xml
+++ b/packages/SystemUI/res-product/values-sr/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Откључајте телефон за још опција"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Откључајте таблет за још опција"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Откључајте уређај за још опција"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"Пушта се на овом телефону"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"Пушта се на овом таблету"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-sv/strings.xml b/packages/SystemUI/res-product/values-sv/strings.xml
index f6059e0..397580f6 100644
--- a/packages/SystemUI/res-product/values-sv/strings.xml
+++ b/packages/SystemUI/res-product/values-sv/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Lås upp telefonen för fler alternativ"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Lås upp surfplattan för fler alternativ"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Lås upp enheten för fler alternativ"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"Spelas upp på denna telefon"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"Spelas upp på denna surfplatta"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-sw/strings.xml b/packages/SystemUI/res-product/values-sw/strings.xml
index 171fd97..863838f 100644
--- a/packages/SystemUI/res-product/values-sw/strings.xml
+++ b/packages/SystemUI/res-product/values-sw/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Fungua simu yako ili upate chaguo zaidi"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Fungua kompyuta yako kibao ili upate chaguo zaidi"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Fungua kifaa chako ili upate chaguo zaidi"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"Inacheza kwenye simu hii"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"Inacheza kwenye kompyuta hii kibao"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-ta/strings.xml b/packages/SystemUI/res-product/values-ta/strings.xml
index b537549..0582460 100644
--- a/packages/SystemUI/res-product/values-ta/strings.xml
+++ b/packages/SystemUI/res-product/values-ta/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"மேலும் விருப்பங்களுக்கு மொபைலை அன்லாக் செய்யவும்"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"மேலும் விருப்பங்களுக்கு டேப்லெட்டை அன்லாக் செய்யவும்"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"மேலும் விருப்பங்களுக்குச் சாதனத்தை அன்லாக் செய்யவும்"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"இந்த மொபைலில் பிளே ஆகிறது"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"இந்த டேப்லெட்டில் பிளே ஆகிறது"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-te/strings.xml b/packages/SystemUI/res-product/values-te/strings.xml
index 511e095..088cf88 100644
--- a/packages/SystemUI/res-product/values-te/strings.xml
+++ b/packages/SystemUI/res-product/values-te/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"మరిన్ని ఆప్షన్ల కోసం మీ ఫోన్ను అన్లాక్ చేయండి"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"మరిన్ని ఆప్షన్ల కోసం మీ టాబ్లెట్ను అన్లాక్ చేయండి"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"మరిన్ని ఆప్షన్ల కోసం మీ పరికరాన్ని అన్లాక్ చేయండి"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"ఈ ఫోన్లో ప్లే అవుతోంది"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"ఈ టాబ్లెట్లో ప్లే అవుతోంది"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-th/strings.xml b/packages/SystemUI/res-product/values-th/strings.xml
index bf2261d..f367f9a 100644
--- a/packages/SystemUI/res-product/values-th/strings.xml
+++ b/packages/SystemUI/res-product/values-th/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"ปลดล็อกโทรศัพท์เพื่อดูตัวเลือกเพิ่มเติม"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"ปลดล็อกแท็บเล็ตเพื่อดูตัวเลือกเพิ่มเติม"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"ปลดล็อกอุปกรณ์เพื่อดูตัวเลือกเพิ่มเติม"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"กำลังเล่นในโทรศัพท์เครื่องนี้"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"กำลังเล่นในแท็บเล็ตเครื่องนี้"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-tl/strings.xml b/packages/SystemUI/res-product/values-tl/strings.xml
index a70a3a5..cfc6df4 100644
--- a/packages/SystemUI/res-product/values-tl/strings.xml
+++ b/packages/SystemUI/res-product/values-tl/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"I-unlock ang iyong telepono para sa higit pang opsyon"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"I-unlock ang iyong tablet para sa higit pang opsyon"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"I-unlock ang iyong device para sa higit pang opsyon"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"Nagpe-play sa teleponong ito"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"Nagpe-play sa tablet na ito"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-tr/strings.xml b/packages/SystemUI/res-product/values-tr/strings.xml
index 5eb7e91..fedd3c8 100644
--- a/packages/SystemUI/res-product/values-tr/strings.xml
+++ b/packages/SystemUI/res-product/values-tr/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Diğer seçenekler için telefonunuzun kilidini açın"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Diğer seçenekler için tabletinizin kilidini açın"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Diğer seçenekler için cihazınızın kilidini açın"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"Bu telefonda oynatılıyor"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"Bu tablette oynatılıyor"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-uk/strings.xml b/packages/SystemUI/res-product/values-uk/strings.xml
index 098f8e7..4f5fc9c 100644
--- a/packages/SystemUI/res-product/values-uk/strings.xml
+++ b/packages/SystemUI/res-product/values-uk/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Розблокуйте телефон, щоб переглянути інші параметри"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Розблокуйте планшет, щоб переглянути інші параметри"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Розблокуйте пристрій, щоб переглянути інші параметри"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"Відтворюється на цьому телефоні"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"Відтворюється на цьому планшеті"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-ur/strings.xml b/packages/SystemUI/res-product/values-ur/strings.xml
index 298a729..ee55538 100644
--- a/packages/SystemUI/res-product/values-ur/strings.xml
+++ b/packages/SystemUI/res-product/values-ur/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"مزید اختیارات کے لیے اپنا فون غیر مقفل کریں"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"مزید اختیارات کے لیے اپنا ٹیبلیٹ غیر مقفل کریں"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"مزید اختیارات کے لیے اپنا آلہ غیر مقفل کریں"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"اس فون پر چل رہا ہے"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"اس ٹیبلیٹ پر چل رہا ہے"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-uz/strings.xml b/packages/SystemUI/res-product/values-uz/strings.xml
index d9c0acd..bf8d94a 100644
--- a/packages/SystemUI/res-product/values-uz/strings.xml
+++ b/packages/SystemUI/res-product/values-uz/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Boshqa parametrlar uchun telefoningiz qulfini oching"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Boshqa parametrlar uchun planshetingiz qulfini oching"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Boshqa parametrlar uchun qurilmangiz qulfini oching"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"Bu telefonda ijro etilmoqda"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"Bu planshetda ijro etilmoqda"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-vi/strings.xml b/packages/SystemUI/res-product/values-vi/strings.xml
index d6fdf9f..e4ecfc1 100644
--- a/packages/SystemUI/res-product/values-vi/strings.xml
+++ b/packages/SystemUI/res-product/values-vi/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Mở khóa điện thoại của bạn để xem thêm tùy chọn"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Mở khóa máy tính bảng của bạn để xem thêm tùy chọn"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Mở khóa thiết bị của bạn để xem thêm tùy chọn"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"Đang phát trên điện thoại này"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"Đang phát trên máy tính bảng này"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-zh-rCN/strings.xml b/packages/SystemUI/res-product/values-zh-rCN/strings.xml
index 19196eb..2813efd 100644
--- a/packages/SystemUI/res-product/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res-product/values-zh-rCN/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"解锁手机即可查看更多选项"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"解锁平板电脑即可查看更多选项"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"解锁设备即可查看更多选项"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"正在此手机上播放"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"正在此平板电脑上播放"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-zh-rHK/strings.xml b/packages/SystemUI/res-product/values-zh-rHK/strings.xml
index 53f92c3..ba07d92 100644
--- a/packages/SystemUI/res-product/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res-product/values-zh-rHK/strings.xml
@@ -38,9 +38,11 @@
<string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="3280816298678433681">"您嘗試解鎖手機已失敗 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。如果之後再嘗試 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次仍未成功,系統將移除此工作設定檔,而所有設定檔資料亦會一併刪除。"</string>
<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4417100487251371559">"您嘗試解鎖平板電腦已失敗 <xliff:g id="NUMBER">%d</xliff:g> 次。系統將移除此工作設定檔,而所有設定檔資料亦會一併刪除。"</string>
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"您嘗試解鎖手機已失敗 <xliff:g id="NUMBER">%d</xliff:g> 次。系統將移除此工作設定檔,而所有設定檔資料亦會一併刪除。"</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"您已畫錯解鎖圖形 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。如果之後再嘗試 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次仍未成功,系統會要求您透過電郵帳戶解鎖平板電腦。\n\n請在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後再試一次。"</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"您已畫錯解鎖圖形 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。如果之後再嘗試 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次仍未成功,系統會要求您透過電郵帳戶解鎖手機。\n\n請在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後再試一次。"</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"您已畫錯解鎖圖案 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。如果之後再嘗試 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次仍未成功,系統會要求您透過電郵帳戶解鎖平板電腦。\n\n請在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後再試一次。"</string>
+ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"您已畫錯解鎖圖案 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。如果之後再嘗試 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次仍未成功,系統會要求您透過電郵帳戶解鎖手機。\n\n請在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後再試一次。"</string>
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"解鎖手機以存取更多選項"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"解鎖平板電腦以存取更多選項"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"解鎖裝置以存取更多選項"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"正在此手機上播放"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"正在此平板電腦上播放"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-zh-rTW/strings.xml b/packages/SystemUI/res-product/values-zh-rTW/strings.xml
index e484b66..736824c 100644
--- a/packages/SystemUI/res-product/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res-product/values-zh-rTW/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"解鎖手機可查看更多選項"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"解鎖平板電腦可查看更多選項"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"解鎖裝置可查看更多選項"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"正在這支手機上播放"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"正在這台平板電腦上播放"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-zu/strings.xml b/packages/SystemUI/res-product/values-zu/strings.xml
index 8b79a22..dae4b22 100644
--- a/packages/SystemUI/res-product/values-zu/strings.xml
+++ b/packages/SystemUI/res-product/values-zu/strings.xml
@@ -43,4 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Vula ifoni yakho ukuthola okunye okungakhethwa"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Vula ithebulethi yakho ukuthola okunye okungakhethwa"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Vula idivayisi yakho ukuthola okunye okungakhethwa"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"Okudlala kule foni"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"Okudlala kule thebhulethi"</string>
</resources>
diff --git a/packages/SettingsLib/res/layout/qrcode_scan_mode_activity.xml b/packages/SystemUI/res/drawable/broadcast_dialog_btn_bg.xml
similarity index 62%
rename from packages/SettingsLib/res/layout/qrcode_scan_mode_activity.xml
rename to packages/SystemUI/res/drawable/broadcast_dialog_btn_bg.xml
index f0a182b..5fd7ee29 100644
--- a/packages/SettingsLib/res/layout/qrcode_scan_mode_activity.xml
+++ b/packages/SystemUI/res/drawable/broadcast_dialog_btn_bg.xml
@@ -15,16 +15,9 @@
limitations under the License.
-->
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/root"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
-
- <LinearLayout
- android:id="@+id/fragment_container"
- android:layout_width="match_parent"
- android:layout_height="match_parent"/>
-
-</LinearLayout>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ android:shape="rectangle">
+ <solid android:color="?androidprv:attr/colorAccentPrimary" />
+ <corners android:radius="@dimen/broadcast_dialog_btn_radius" />
+</shape>
diff --git a/packages/SystemUI/res/drawable/ic_chevron_icon.xml b/packages/SystemUI/res/drawable/ic_chevron_icon.xml
index acbbbcb..d60cc8c 100644
--- a/packages/SystemUI/res/drawable/ic_chevron_icon.xml
+++ b/packages/SystemUI/res/drawable/ic_chevron_icon.xml
@@ -15,14 +15,6 @@
~ limitations under the License.
-->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="18dp"
- android:height="31dp"
- android:viewportWidth="18"
- android:viewportHeight="31">
- <path
- android:pathData="M0.0061,27.8986L2.6906,30.5831L17.9219,15.3518L2.6906,0.1206L0.0061,2.8051L12.5338,15.3518"
- android:strokeAlpha="0.7"
- android:fillColor="#FFFFFF"
- android:fillAlpha="0.7"/>
-</vector>
+<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="M9.4,18 L8,16.6 12.6,12 8,7.4 9.4,6 15.4,12Z"/>
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_qs_screen_saver.xml b/packages/SystemUI/res/drawable/ic_qs_screen_saver.xml
new file mode 100644
index 0000000..263a3d1
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_screen_saver.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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?android:attr/colorControlNormal">
+ <path android:fillColor="@android:color/white"
+ android:pathData="M5,15H19L14.5,9L11,13.5L8.5,10.5ZM6,21Q5.575,21 5.287,20.712Q5,20.425 5,20V19H3Q2.175,19 1.588,18.413Q1,17.825 1,17V6Q1,5.175 1.588,4.588Q2.175,4 3,4H21Q21.825,4 22.413,4.588Q23,5.175 23,6V17Q23,17.825 22.413,18.413Q21.825,19 21,19H19V20Q19,20.425 18.712,20.712Q18.425,21 18,21ZM3,17H21Q21,17 21,17Q21,17 21,17V6Q21,6 21,6Q21,6 21,6H3Q3,6 3,6Q3,6 3,6V17Q3,17 3,17Q3,17 3,17ZM3,17Q3,17 3,17Q3,17 3,17V6Q3,6 3,6Q3,6 3,6Q3,6 3,6Q3,6 3,6V17Q3,17 3,17Q3,17 3,17Z"/>
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/keyguard_bottom_affordance_bg.xml b/packages/SystemUI/res/drawable/keyguard_bottom_affordance_bg.xml
index 3a08a71..41123c8 100644
--- a/packages/SystemUI/res/drawable/keyguard_bottom_affordance_bg.xml
+++ b/packages/SystemUI/res/drawable/keyguard_bottom_affordance_bg.xml
@@ -16,19 +16,13 @@
* limitations under the License.
*/
-->
-<ripple
+<shape
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
- android:color="?android:attr/textColorPrimary">
- <item>
- <shape
- android:shape="rectangle">
- <solid android:color="?androidprv:attr/colorSurface"/>
- <size
- android:width="@dimen/keyguard_affordance_width"
- android:height="@dimen/keyguard_affordance_height"/>
- <corners android:radius="@dimen/keyguard_affordance_fixed_radius"/>
- </shape>
- </item>
-</ripple>
-
+ android:shape="rectangle">
+ <solid android:color="?androidprv:attr/colorSurface"/>
+ <size
+ android:width="@dimen/keyguard_affordance_width"
+ android:height="@dimen/keyguard_affordance_height"/>
+ <corners android:radius="@dimen/keyguard_affordance_fixed_radius"/>
+</shape>
diff --git a/packages/SystemUI/res/drawable/overlay_cancel.xml b/packages/SystemUI/res/drawable/overlay_cancel.xml
index f9786e2..3fa12dd 100644
--- a/packages/SystemUI/res/drawable/overlay_cancel.xml
+++ b/packages/SystemUI/res/drawable/overlay_cancel.xml
@@ -24,6 +24,6 @@
android:fillColor="?androidprv:attr/colorAccentTertiary"
android:pathData="M16,16m-16,0a16,16 0,1 1,32 0a16,16 0,1 1,-32 0"/>
<path
- android:fillColor="?android:attr/textColorPrimary"
+ android:fillColor="?attr/overlayButtonTextColor"
android:pathData="M23,10.41L21.59,9 16,14.59 10.41,9 9,10.41 14.59,16 9,21.59 10.41,23 16,17.41 21.59,23 23,21.59 17.41,16z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/settings_input_antenna.xml b/packages/SystemUI/res/drawable/settings_input_antenna.xml
new file mode 100644
index 0000000..f2adcaf
--- /dev/null
+++ b/packages/SystemUI/res/drawable/settings_input_antenna.xml
@@ -0,0 +1,23 @@
+<?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.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp"
+ android:height="24dp" android:viewportWidth="24" android:viewportHeight="24"
+ android:tint="?android:attr/textColorSecondary">
+ <path android:fillColor="#FF000000"
+ android:pathData="M9,22.4 L7.6,21 11,17.6V14.3Q10.325,14 9.913,13.375Q9.5,12.75 9.5,12Q9.5,10.95 10.225,10.225Q10.95,9.5 12,9.5Q13.05,9.5 13.775,10.225Q14.5,10.95 14.5,12Q14.5,12.75 14.088,13.375Q13.675,14 13,14.3V17.6L16.4,21L15,22.4L12,19.4ZM5,12Q5,9.05 7.05,7.025Q9.1,5 12,5Q14.9,5 16.95,7.025Q19,9.05 19,12H17Q17,9.925 15.538,8.462Q14.075,7 12,7Q9.925,7 8.463,8.462Q7,9.925 7,12ZM1,12Q1,9.7 1.863,7.7Q2.725,5.7 4.225,4.212Q5.725,2.725 7.725,1.862Q9.725,1 12,1Q14.275,1 16.275,1.862Q18.275,2.725 19.775,4.212Q21.275,5.7 22.138,7.7Q23,9.7 23,12H21Q21,10.125 20.288,8.487Q19.575,6.85 18.35,5.625Q17.125,4.4 15.488,3.7Q13.85,3 12,3Q10.15,3 8.512,3.7Q6.875,4.4 5.65,5.625Q4.425,6.85 3.712,8.487Q3,10.125 3,12Z"/>
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/auth_biometric_background.xml b/packages/SystemUI/res/layout/auth_biometric_background.xml
new file mode 100644
index 0000000..7ce81ad
--- /dev/null
+++ b/packages/SystemUI/res/layout/auth_biometric_background.xml
@@ -0,0 +1,30 @@
+<?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="match_parent"
+ android:gravity="center"
+ android:orientation="vertical">
+
+ <ImageView
+ android:id="@+id/icon"
+ android:layout_width="80dp"
+ android:layout_height="80dp"
+ android:layout_marginBottom="160dp"/>
+
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/broadcast_dialog.xml b/packages/SystemUI/res/layout/broadcast_dialog.xml
new file mode 100644
index 0000000..5ba2afe
--- /dev/null
+++ b/packages/SystemUI/res/layout/broadcast_dialog.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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/dialog_bg"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="@dimen/broadcast_dialog_margin"
+ android:orientation="vertical">
+
+ <ImageView
+ android:id="@+id/dialog_icon"
+ android:layout_width="@dimen/broadcast_dialog_icon_size"
+ android:layout_height="@dimen/broadcast_dialog_icon_size"
+ android:layout_marginTop="@dimen/broadcast_dialog_icon_margin_top"
+ android:layout_marginBottom="@dimen/broadcast_dialog_title_img_margin_top"
+ android:layout_gravity="center"
+ android:src="@drawable/settings_input_antenna"/>
+
+ <TextView
+ style="@style/BroadcastDialogTitleStyle"
+ android:id="@+id/dialog_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:layout_gravity="center"/>
+
+ <TextView
+ style="@style/BroadcastDialogBodyStyle"
+ android:id="@+id/dialog_subtitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:layout_gravity="center"/>
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginHorizontal="@dimen/broadcast_dialog_margin"
+ android:layout_marginBottom="@dimen/broadcast_dialog_margin"
+ android:orientation="vertical">
+
+ <Button
+ android:layout_marginBottom="@dimen/broadcast_dialog_btn_margin_bottom"
+ android:id="@+id/switch_broadcast"
+ style="@style/BroadcastDialogButtonStyle"/>
+
+ <Button
+ android:layout_marginBottom="@dimen/broadcast_dialog_btn_margin_bottom"
+ android:id="@+id/change_output"
+ android:text="@string/bt_le_audio_broadcast_dialog_different_output"
+ style="@style/BroadcastDialogButtonStyle"/>
+
+ <Button
+ android:id="@+id/cancel"
+ android:text="@android:string/cancel"
+ style="@style/BroadcastDialogButtonStyle"/>
+ </LinearLayout>
+
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/clipboard_edit_text_activity.xml b/packages/SystemUI/res/layout/clipboard_edit_text_activity.xml
index 1122ca6..1c09e81f 100644
--- a/packages/SystemUI/res/layout/clipboard_edit_text_activity.xml
+++ b/packages/SystemUI/res/layout/clipboard_edit_text_activity.xml
@@ -12,6 +12,7 @@
android:layout_height="48dp"
android:layout_marginTop="8dp"
android:layout_marginStart="12dp"
+ android:paddingHorizontal="16dp"
android:background="@drawable/overlay_button_background"
android:text="@string/clipboard_edit_text_done"
app:layout_constraintStart_toStartOf="parent"
diff --git a/packages/SystemUI/res/layout/clipboard_overlay.xml b/packages/SystemUI/res/layout/clipboard_overlay.xml
index 085a581..1712b48 100644
--- a/packages/SystemUI/res/layout/clipboard_overlay.xml
+++ b/packages/SystemUI/res/layout/clipboard_overlay.xml
@@ -67,9 +67,9 @@
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="@dimen/overlay_offset_x"
- android:layout_marginBottom="8dp"
+ android:layout_marginBottom="12dp"
app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintBottom_toBottomOf="@id/actions_container_background"
+ app:layout_constraintBottom_toBottomOf="parent"
android:elevation="7dp"
app:layout_constraintEnd_toEndOf="@id/clipboard_preview_end"
app:layout_constraintTop_toTopOf="@id/clipboard_preview_top"
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 54b2340..4af9b20 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Probeer weer skermkiekie neem"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"Kan nie skermkiekie stoor nie"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Die program of jou organisasie laat nie toe dat skermkiekies geneem word nie"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Die neem van skermskote word deur jou IT-admin geblokkeer"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Wysig"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Wysig skermkiekie"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"Deel skermskoot"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Outo-draai"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Outodraai skerm"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Ligging"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Sluimerskerm"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Kameratoegang"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Mikrofoontoegang"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Beskikbaar"</string>
@@ -318,6 +320,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Ontsluit met gesig. Druk om oop te maak."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Gesig is herken. Druk om oop te maak."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Gesig is herken. Druk die ontsluitikoon om oop te maak."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"Swiep op om weer te probeer"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Ontsluit om NFC te gebruik"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Hierdie toestel behoort aan jou organisasie"</string>
@@ -426,7 +432,7 @@
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Dit hou dit in sig totdat jy dit ontspeld. Raak en hou Oorsig om dit te ontspeld."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Dit hou dit in sig totdat jy dit ontspeld. Raak en hou Tuis om dit te ontspeld."</string>
<string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Persoonlike data (soos kontakte en e-posinhoud) kan toeganklik wees."</string>
- <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Kan vasgespelde program ander programme oopmaak."</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Vasgespelde program kan ander programme oopmaak."</string>
<string name="screen_pinning_toast" msgid="8177286912533744328">"Raak en hou die terug- en oorsigknoppie om hierdie program te ontspeld"</string>
<string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Raak en hou die terug- en tuisknoppie om hierdie program te ontspeld"</string>
<string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"Swiep op en hou om hierdie program te ontspeld"</string>
@@ -467,7 +473,7 @@
<string name="wallet_title" msgid="5369767670735827105">"Beursie"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"Stel op om vinniger, veiliger aankope met jou foon te doen"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"Wys alles"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"Voeg \'n kaart by"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"Tik om oop te maak"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"Dateer tans op"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Ontsluit om te gebruik"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Kon nie jou kaarte kry nie; probeer later weer"</string>
@@ -693,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Opletberigte"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Battery"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Skermkiekies"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Algemene boodskappe"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"Berging"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Wenke"</string>
<string name="instant_apps" msgid="8337185853050247304">"Kitsprogramme"</string>
@@ -727,6 +736,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"Skakel aan wanneer battery waarskynlik sal leegloop"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"Nee, dankie"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Stort SysUI-hoop"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"In gebruik"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Programme gebruik tans jou <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" en "</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Beweeg nader om op <xliff:g id="DEVICENAME">%1$s</xliff:g> te speel"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Beweeg nader aan <xliff:g id="DEVICENAME">%1$s</xliff:g> om hier te speel"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Speel tans op <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Speel tans op hierdie foon"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Iets is fout. Probeer weer."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Onaktief, gaan program na"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Nie gekry nie"</string>
@@ -853,6 +862,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"Stoor"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"Begin tans …"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"Kan nie uitsaai nie"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Kan nie stoor nie. Probeer weer."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Kan nie stoor nie."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Bounommer"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Bounommer is na knipbord gekopieer."</string>
<string name="basic_status" msgid="2315371112182658176">"Maak gesprek oop"</string>
@@ -915,7 +926,7 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-fi sal vir nou nie outomaties koppel nie"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Sien alles"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Ontkoppel Ethernet om netwerke te wissel"</string>
- <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Om toestelervaring te verbeter, kan programme en dienste steeds enige tyd na wi‑fi-netwerke soek, selfs wanneer wi‑fi af is. Jy kan dit in Wi-fi-opsporing-instellings verander. "<annotation id="link">"Verander"</annotation></string>
+ <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Om toestelervaring te verbeter, kan programme en dienste steeds enige tyd na wi‑fi-netwerke soek, selfs wanneer wi‑fi af is. Jy kan dit in Wi-fi-opsporinginstellings verander. "<annotation id="link">"Verander"</annotation></string>
<string name="turn_off_airplane_mode" msgid="8425587763226548579">"Skakel vliegtuigmodus af"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> wil die volgende teël by Kitsinstellings voeg"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Voeg teël by"</string>
@@ -937,6 +948,13 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Wysig gekopieerde teks"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Wysig gekopieerde prent"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Stuur na toestel in die omtrek"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"Tik om te bekyk"</string>
+ <!-- no translation found for clipboard_text_copied (5100836834278976679) -->
+ <skip />
+ <!-- no translation found for clipboard_image_copied (3793365360174328722) -->
+ <skip />
+ <!-- no translation found for clipboard_content_copied (144452398567828145) -->
+ <skip />
<string name="add" msgid="81036585205287996">"Voeg by"</string>
<string name="manage_users" msgid="1823875311934643849">"Bestuur gebruikers"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"Sleep na verdeelde skerm word nie vir hierdie kennisgewing gesteun nie."</string>
@@ -945,4 +963,12 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Wekker gestel"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera en mikrofoon is af"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# kennisgewing}other{# kennisgewings}}"</string>
+ <!-- no translation found for broadcasting_description_is_broadcasting (765627502786404290) -->
+ <skip />
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Hou op om <xliff:g id="APP_NAME">%1$s</xliff:g> uit te saai?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"As jy <xliff:g id="SWITCHAPP">%1$s</xliff:g> uitsaai of die uitvoer verander, sal jou huidige uitsending stop"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Saai <xliff:g id="SWITCHAPP">%1$s</xliff:g> uit"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Verander uitvoer"</string>
+ <!-- no translation found for bt_le_audio_broadcast_dialog_unknown_name (3791472237793443044) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-af/tiles_states_strings.xml b/packages/SystemUI/res/values-af/tiles_states_strings.xml
index 93d26e8..e60f233 100644
--- a/packages/SystemUI/res/values-af/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-af/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Af"</item>
<item msgid="460891964396502657">"Aan"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Onbeskikbaar"</item>
+ <item msgid="8014986104355098744">"Af"</item>
+ <item msgid="5966994759929723339">"Aan"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 495048b..08f55ee 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"ቅጽበታዊ ገጽ ዕይታን እንደገና ማንሳት ይሞክሩ"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"ቅጽበታዊ ገጽ እይታን ማስቀመጥ አልተቻለም"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"ቅጽበታዊ ገጽ እይታዎችን ማንሳት በመተግበሪያው ወይም በእርስዎ ድርጅት አይፈቀድም"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"ቅጽበታዊ ገጽ እይታዎችን ማንሳት በእርስዎ አይቲ አስተዳዳሪ ታግዷል"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"አርትዕ ያድርጉ"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"ቅጽበታዊ ገጽ ዕይታን አርትዕ ያድርጉ"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"ቅጽበታዊ ገጽ እይታን ያጋሩ"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"በራስ ሰር አሽከርክር"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"ማያ ገጽን በራስ-አሽከርክር"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"አካባቢ"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"የማያ ገጽ ማቆያ"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"የካሜራ መዳረሻ"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"የማይክሮፎን መዳረሻ"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"ይገኛል"</string>
@@ -318,6 +320,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"በመልክ ተከፍቷል። ለመክፈት ይጫኑ።"</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"መልክ ተለይቶ ታውቋል። ለመክፈት ይጫኑ።"</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"መልክ ተለይቶ ታውቋል። ለመክፈት የመክፈቻ አዶውን ይጫኑ።"</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"እንደገና ለመሞከር ወደ ላይ ይጥረጉ"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFCን ለመጠቀም ይክፈቱ"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"ይህ መሣሪያ የድርጅትዎ ነው"</string>
@@ -467,7 +473,7 @@
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"በስልክዎ በመጠቀም ፈጣን እና የበለጠ ደህንነቱ በተጠበቀ መንገድ ግዢዎችን ለመፈጸም ዝግጁ ይሁኑ"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"ሁሉንም አሳይ"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"ካርድ አክል"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"ለመክፈት መታ ያድርጉ"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"በማዘመን ላይ"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ለማየት ይክፈቱ"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"የእርስዎን ካርዶች ማግኘት ላይ ችግር ነበር፣ እባክዎ ቆይተው እንደገና ይሞክሩ"</string>
@@ -693,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"ማንቂያዎች"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"ባትሪ"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"ቅጽበታዊ ገጽ እይታዎች"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"አጠቃላይ መልዕክቶች"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"ማከማቻ"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"ፍንጮች"</string>
<string name="instant_apps" msgid="8337185853050247304">"የቅጽበት መተግበሪያዎች"</string>
@@ -727,6 +736,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"ባትሪው የማለቅ ዕድሉ ከፍ ያለ ከሆነ ያብሩት"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"አይ፣ አመሰግናለሁ"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"SysUI Heap አራግፍ"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"በጥቅም ላይ"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"መተግበሪያዎች የእርስዎን <xliff:g id="TYPES_LIST">%s</xliff:g> እየተጠቀሙ ነው።"</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">"፣ "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" እና "</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"በ<xliff:g id="DEVICENAME">%1$s</xliff:g> ላይ ለማጫወት ጠጋ ያድርጉ"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"እዚህ ለመጫወት ወደ <xliff:g id="DEVICENAME">%1$s</xliff:g> ቀረብ ይበሉ"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"በ<xliff:g id="DEVICENAME">%1$s</xliff:g> ላይ በማጫወት ላይ"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"በዚህ ስልክ በመጫወት ላይ"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"የሆነ ችግር ተፈጥሯል። እንደገና ይሞክሩ።"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"ንቁ ያልኾነ፣ መተግበሪያን ይፈትሹ"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"አልተገኘም"</string>
@@ -853,6 +862,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"አስቀምጥ"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"በመጀመር ላይ…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"መሰራጨት አይችልም"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"ማስቀመጥ አልተቻለም። እንደገና ይሞክሩ።"</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"ማስቀመጥ አልተቻለም።"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"የግንብ ቁጥር"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"የገንባ ቁጥር ወደ ቅንጥብ ሰሌዳ ተቀድቷል።"</string>
<string name="basic_status" msgid="2315371112182658176">"ውይይት ይክፈቱ"</string>
@@ -937,6 +948,13 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"የተቀዳ ጽሁፍ አርትዕ ያድርጉ"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"የተቀዳ ምስል አርትዕ ያድርጉ"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"በአቅራቢያ ወዳለ መሳሪያ ይላኩ"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"ለመመልከት መታ ያድርጉ"</string>
+ <!-- no translation found for clipboard_text_copied (5100836834278976679) -->
+ <skip />
+ <!-- no translation found for clipboard_image_copied (3793365360174328722) -->
+ <skip />
+ <!-- no translation found for clipboard_content_copied (144452398567828145) -->
+ <skip />
<string name="add" msgid="81036585205287996">"አክል"</string>
<string name="manage_users" msgid="1823875311934643849">"ተጠቃሚዎችን ያስተዳድሩ"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"ይህ ማሳወቂያ ወደ Splitscreen መጎተትን አይደግፍም።"</string>
@@ -945,4 +963,12 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"ማንቂያ ተቀናብሯል"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"ካሜራ እና ማይክሮፎን ጠፍተዋል"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# ማሳወቂያ}one{# ማሳወቂያዎች}other{# ማሳወቂያዎች}}"</string>
+ <!-- no translation found for broadcasting_description_is_broadcasting (765627502786404290) -->
+ <skip />
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g>ን ማሰራጨት ይቁም?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"<xliff:g id="SWITCHAPP">%1$s</xliff:g>ን ካሰራጩ ወይም ውፅዓትን ከቀየሩ የአሁኑ ስርጭትዎ ይቆማል"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> ያሰራጩ"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"ውፅዓትን ይቀይሩ"</string>
+ <!-- no translation found for bt_le_audio_broadcast_dialog_unknown_name (3791472237793443044) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-am/tiles_states_strings.xml b/packages/SystemUI/res/values-am/tiles_states_strings.xml
index 12be1ae..bbf2d23 100644
--- a/packages/SystemUI/res/values-am/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-am/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"አጥፋ"</item>
<item msgid="460891964396502657">"አብራ"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"አይገኝም"</item>
+ <item msgid="8014986104355098744">"ጠፍቷል"</item>
+ <item msgid="5966994759929723339">"በርቷል"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 9c68cf7..5d13572 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"جرّب أخذ لقطة الشاشة مرة أخرى"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"يتعذّر حفظ لقطة الشاشة."</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"يحظر التطبيق أو تحظر مؤسستك التقاط لقطات شاشة"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"حَظَر مشرف تكنولوجيا المعلومات عملية أخذ لقطات للشاشة."</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"تعديل"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"تعديل لقطة الشاشة"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"مشاركة لقطة الشاشة"</string>
@@ -229,6 +230,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"التدوير التلقائي"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"التدوير التلقائي للشاشة"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"الموقع الجغرافي"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"شاشة الاستراحة"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"الوصول إلى الكاميرا"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"الوصول إلى الميكروفون"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"متاح"</string>
@@ -326,6 +328,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"تم فتح قفل جهازك عند تقريبه من وجهك. اضغط لفتح الجهاز."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"تم التعرّف على الوجه. اضغط لفتح الجهاز."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"تم التعرّف على الوجه. اضغط على رمز فتح القفل لفتح الجهاز."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"مرِّر سريعًا للأعلى لإعادة المحاولة."</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"افتح قفل الشاشة لاستخدام تقنية NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"هذا الجهاز يخص مؤسستك."</string>
@@ -479,7 +485,7 @@
<string name="wallet_title" msgid="5369767670735827105">"المحفظة"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"يمكنك إعداد طريقة دفع لإجراء عمليات شراء بسرعة وأمان أكبر باستخدام هاتفك."</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"عرض الكل"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"إضافة بطاقة"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"انقر لفتح قفل الجهاز."</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"جارٍ تحديث تطبيق المحفظة"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"فتح القفل للاستخدام"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"حدثت مشكلة أثناء الحصول على البطاقات، يُرجى إعادة المحاولة لاحقًا."</string>
@@ -512,7 +518,7 @@
<string name="notification_alert_title" msgid="3656229781017543655">"تلقائية"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"تلقائي"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"بدون صوت أو اهتزاز"</string>
- <string name="notification_conversation_summary_low" msgid="1734433426085468009">"بدون صوت أو اهتزاز وتظهر في موضع أسفل في قسم المحادثات."</string>
+ <string name="notification_conversation_summary_low" msgid="1734433426085468009">"بدون صوت أو اهتزاز وتظهر في أسفل قسم المحادثات"</string>
<string name="notification_channel_summary_default" msgid="3282930979307248890">"يمكن إصدار رنين أو اهتزاز بناءً على إعدادات الهاتف."</string>
<string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"يمكن إصدار رنين أو اهتزاز بناءً على إعدادات الهاتف. تظهر المحادثات من <xliff:g id="APP_NAME">%1$s</xliff:g> كفقاعات تلقائيًا."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"السماح للنظام بتحديد ما إذا يجب اهتزاز الجهاز أو إصدار رنين عند تلقّي هذا الإشعار"</string>
@@ -713,7 +719,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"التنبيهات"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"البطارية"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"لقطات الشاشة"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"رسائل عامة"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"مساحة التخزين"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"تلميحات"</string>
<string name="instant_apps" msgid="8337185853050247304">"التطبيقات الفورية"</string>
@@ -725,7 +734,7 @@
<string name="mobile_data" msgid="4564407557775397216">"بيانات الجوّال"</string>
<string name="mobile_data_text_format" msgid="6806501540022589786">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>، <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
- <string name="wifi_is_off" msgid="5389597396308001471">"شبكة Wi-Fi متوقفة."</string>
+ <string name="wifi_is_off" msgid="5389597396308001471">"ميزة Wi-Fi غير مفعّلة"</string>
<string name="bt_is_off" msgid="7436344904889461591">"تم إيقاف البلوتوث."</string>
<string name="dnd_is_off" msgid="3185706903793094463">"تم إيقاف وضع \"عدم الإزعاج\""</string>
<string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"تم تفعيل وضع \"عدم الإزعاج\" بواسطة قاعدة تلقائية (<xliff:g id="ID_1">%s</xliff:g>)."</string>
@@ -747,6 +756,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"فعِّل الميزة إذا كان من المرجح نفاد شحن البطارية."</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"لا، شكرًا"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"تفريغ ذاكرة SysUI"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"قيد الاستخدام"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"تستخدم التطبيقات <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">"، "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" و "</string>
@@ -848,7 +858,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"عليك الاقتراب لتشغيل الوسائط على <xliff:g id="DEVICENAME">%1$s</xliff:g>."</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"يُرجى الاقتراب من <xliff:g id="DEVICENAME">%1$s</xliff:g> لتشغيل الوسائط هنا."</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"جارٍ تشغيل الوسائط على <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"جارٍ تشغيل الوسائط على هذا الهاتف"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"حدث خطأ. يُرجى إعادة المحاولة."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"غير نشط، تحقّق من التطبيق."</string>
<string name="controls_error_removed" msgid="6675638069846014366">"لم يتم العثور عليه."</string>
@@ -877,6 +886,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"حفظ"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"جارٍ البدء…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"يتعذّر البث"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"لا يمكن إجراء الحفظ. يُرجى إعادة المحاولة."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"لا يمكن إجراء الحفظ."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"رقم الإصدار"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"تم نسخ رقم الإصدار إلى الحافظة."</string>
<string name="basic_status" msgid="2315371112182658176">"محادثة مفتوحة"</string>
@@ -965,6 +976,13 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"تعديل النص المنسوخ"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"تعديل الصورة المنسوخة"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"الإرسال إلى جهاز مجاور"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"انقر لعرض المحتوى."</string>
+ <!-- no translation found for clipboard_text_copied (5100836834278976679) -->
+ <skip />
+ <!-- no translation found for clipboard_image_copied (3793365360174328722) -->
+ <skip />
+ <!-- no translation found for clipboard_content_copied (144452398567828145) -->
+ <skip />
<string name="add" msgid="81036585205287996">"إضافة"</string>
<string name="manage_users" msgid="1823875311934643849">"إدارة المستخدمين"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"لا يتيح هذا الإشعار السحب لتقسيم الشاشة."</string>
@@ -973,4 +991,12 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"تم ضبط المنبه."</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"الكاميرا والميكروفون غير مفعّلين."</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{إشعار واحد}zero{# إشعار}two{إشعاران}few{# إشعارات}many{# إشعارًا}other{# إشعار}}"</string>
+ <!-- no translation found for broadcasting_description_is_broadcasting (765627502786404290) -->
+ <skip />
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"هل تريد إيقاف بث تطبيق <xliff:g id="APP_NAME">%1$s</xliff:g>؟"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"إذا أجريت بث تطبيق <xliff:g id="SWITCHAPP">%1$s</xliff:g> أو غيَّرت جهاز الإخراج، سيتوقَف البث الحالي."</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"بث تطبيق <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"تغيير جهاز الإخراج"</string>
+ <!-- no translation found for bt_le_audio_broadcast_dialog_unknown_name (3791472237793443044) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ar/tiles_states_strings.xml b/packages/SystemUI/res/values-ar/tiles_states_strings.xml
index b4fb760..44b58f9 100644
--- a/packages/SystemUI/res/values-ar/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ar/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"غير مفعّل"</item>
<item msgid="460891964396502657">"مفعّل"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"غير متوفّرة"</item>
+ <item msgid="8014986104355098744">"غير مفعّلة"</item>
+ <item msgid="5966994759929723339">"مفعَّلة"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index 1be16bd..5484f6e 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"স্ক্ৰীণশ্বট আকৌ ল\'বলৈ চেষ্টা কৰক"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"স্ক্ৰীনশ্বট ছেভ কৰিব নোৱাৰি"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"এপটোৱে বা আপোনাৰ প্ৰতিষ্ঠানে স্ক্ৰীণশ্বট ল\'বলৈ অনুমতি নিদিয়ে"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"স্ক্ৰীনশ্বট লোৱাটো আপোনাৰ আইটি প্ৰশাসকে অৱৰোধ কৰিছে"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"সম্পাদনা কৰক"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"স্ক্ৰীনশ্বট সম্পাদনা কৰক"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"স্ক্ৰীনশ্বট শ্বেয়াৰ কৰক"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"স্বয়ং-ঘূৰ্ণন"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"স্বয়ং-ঘূৰ্ণন স্ক্ৰীন"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"অৱস্থান"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"স্ক্ৰীন ছেভাৰ"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"কেমেৰাৰ এক্সেছ"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"মাইকৰ এক্সেছ"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"উপলব্ধ"</string>
@@ -318,6 +320,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"মুখাৱয়বৰ জৰিয়তে আনলক কৰা হৈছে। খুলিবলৈ টিপক।"</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"মুখাৱয়ব চিনাক্ত কৰা হৈছে। খুলিবলৈ টিপক।"</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"মুখাৱয়ব চিনাক্ত কৰা হৈছে। খুলিবলৈ আনলক কৰক চিহ্নটোত টিপক।"</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"পুনৰ চেষ্টা কৰিবলৈ ওপৰলৈ ছোৱাইপ কৰক"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC ব্যৱহাৰ কৰিবলৈ আনলক কৰক"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"এই ডিভাইচটো আপোনাৰ প্ৰতিষ্ঠানৰ"</string>
@@ -467,7 +473,7 @@
<string name="wallet_title" msgid="5369767670735827105">"ৱালেট"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"আপোনাৰ ফ’নটোৰে দ্ৰুত তথা অধিক সুৰক্ষিত ক্ৰয় কৰিবলৈ ছেট আপ পাওক"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"আটাইবোৰ দেখুৱাওক"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"এখন কাৰ্ড যোগ দিয়ক"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"খুলিবলৈ টিপক"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"আপডে’ট কৰি থকা হৈছে"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ব্যৱহাৰ কৰিবলৈ আনলক কৰক"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"আপোনাৰ কাৰ্ড লাভ কৰোঁতে এটা সমস্যা হৈছে, অনুগ্ৰহ কৰি পাছত পুনৰ চেষ্টা কৰক"</string>
@@ -693,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"সতৰ্কবার্তাসমূহ"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"বেটাৰী"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"স্ক্ৰীণশ্বটসমূহ"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"সাধাৰণ বার্তাসমূহ"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"ষ্ট\'ৰেজ"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"ইংগিতবোৰ"</string>
<string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string>
@@ -727,6 +736,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"বেটাৰী শেষ হোৱাৰ সম্ভাৱনা থাকিলে অন কৰক"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"নালাগে, ধন্যবাদ"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"SysUI হীপ ডাম্প কৰক"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"ব্যৱহাৰ হৈ আছে"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"এপ্লিকেশ্বনসমূহে আপোনাৰ <xliff:g id="TYPES_LIST">%s</xliff:g> ব্যৱহাৰ কৰি আছে।"</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" আৰু "</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g>ত প্লে’ কৰিবলৈ ওচৰলৈ যাওক"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"ইয়াত খেলিবলৈ <xliff:g id="DEVICENAME">%1$s</xliff:g>ৰ আৰু ওচৰলৈ যাওক"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g>ত প্লে কৰি থকা হৈছে"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"এই ফ’নটোত প্লে কৰি থকা হৈছে"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"কিবা ভুল হ’ল। পুনৰ চেষ্টা কৰক।"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"সক্ৰিয় নহয়, এপ্টো পৰীক্ষা কৰক"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"বিচাৰি পোৱা নগ’ল"</string>
@@ -853,6 +862,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"ছেভ কৰক"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"আৰম্ভ কৰা হৈছে…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"সম্প্ৰচাৰ কৰিব নোৱাৰি"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"ছেভ কৰিব নোৱাৰি। পুনৰ চেষ্টা কৰক।"</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"ছেভ কৰিব নোৱাৰি।"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"বিল্ডৰ নম্বৰ"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"ক্লিপব’ৰ্ডলৈ বিল্ডৰ নম্বৰ প্ৰতিলিপি কৰা হ’ল।"</string>
<string name="basic_status" msgid="2315371112182658176">"বাৰ্তালাপ খোলক"</string>
@@ -927,7 +938,7 @@
</plurals>
<string name="fgs_dot_content_description" msgid="2865071539464777240">"নতুন তথ্য"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"সক্ৰিয় এপ্"</string>
- <string name="fgs_manager_dialog_message" msgid="6839542063522121108">"আপুনি এই এপ্সমূহ ব্যৱহাৰ কৰি নাথাকিলেও, সেইসমূহ এতিয়াও সক্ৰিয় হৈ আছে আৰু সেইসমূহে বেটাৰিৰ জীৱনকাল প্ৰভাৱিত কৰিব পাৰে"</string>
+ <string name="fgs_manager_dialog_message" msgid="6839542063522121108">"আপুনি এই এপ্সমূহ ব্যৱহাৰ কৰি নাথাকিলেও, সেইসমূহ এতিয়াও সক্ৰিয় হৈ আছে আৰু সেইসমূহে বেটাৰীৰ জীৱনকাল প্ৰভাৱিত কৰিব পাৰে"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"বন্ধ কৰক"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"বন্ধ হ’ল"</string>
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"হ’ল"</string>
@@ -937,6 +948,10 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"প্ৰতিলিপি কৰা পাঠ সম্পাদনা কৰক"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"প্ৰতিলিপি কৰা প্ৰতিচ্ছবি সম্পাদনা কৰক"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"নিকটৱৰ্তী ডিভাইচলৈ পঠাওক"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"চাবলৈ টিপক"</string>
+ <string name="clipboard_text_copied" msgid="5100836834278976679">"পাঠ প্ৰতিলিপি কৰা হ’ল"</string>
+ <string name="clipboard_image_copied" msgid="3793365360174328722">"প্ৰতিচ্ছবি প্ৰতিলিপি কৰা হ’ল"</string>
+ <string name="clipboard_content_copied" msgid="144452398567828145">"সমল প্ৰতিলিপি কৰা হ’ল"</string>
<string name="add" msgid="81036585205287996">"যোগ দিয়ক"</string>
<string name="manage_users" msgid="1823875311934643849">"ব্যৱহাৰকাৰী পৰিচালনা কৰক"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"এই জাননীটোৱে টানি আনি এৰাৰ পৰা বিভাজিত স্ক্ৰীন সমৰ্থন নকৰে।"</string>
@@ -945,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"এলাৰ্ম ছেট কৰা হ’ল"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"কেমেৰা আৰু মাইক অফ হৈ আছে"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# টা জাননী}one{# টা জাননী}other{# টা জাননী}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"সম্প্ৰচাৰণ"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g>ৰ সম্প্ৰচাৰ কৰা বন্ধ কৰিবনে?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"যদি আপুনি <xliff:g id="SWITCHAPP">%1$s</xliff:g>ৰ সম্প্ৰচাৰ কৰে অথবা আউটপুট সলনি কৰে, তেন্তে, আপোনাৰ বৰ্তমানৰ সম্প্ৰচাৰ বন্ধ হৈ যাব"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> সম্প্ৰচাৰ কৰক"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"আউটপুট সলনি কৰক"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"অজ্ঞাত"</string>
</resources>
diff --git a/packages/SystemUI/res/values-as/tiles_states_strings.xml b/packages/SystemUI/res/values-as/tiles_states_strings.xml
index 7767cfc..3145341 100644
--- a/packages/SystemUI/res/values-as/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-as/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"অফ"</item>
<item msgid="460891964396502657">"অন"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"উপলব্ধ নহয়"</item>
+ <item msgid="8014986104355098744">"অফ আছে"</item>
+ <item msgid="5966994759929723339">"অন আছে"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index fced562..4bf0f34 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Skrinşotu yenidən çəkin"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"Skrinşotu yadda saxlamaq mümkün olmadı"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Skrinşot çəkməyə tətbiq və ya təşkilat tərəfindən icazə verilmir"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Skrinşot çəkilməsi İT admininiz tərəfindən bloklanıb"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Redaktə edin"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Skrinşota düzəliş edin"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"Skrinşotu paylaşın"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Avtodönüş"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Ekranın avtomatik dönməsi"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Məkan"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Ekran qoruyucu"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Kameraya giriş"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Mikrofona giriş"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Əlçatan"</string>
@@ -318,6 +320,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Üz ilə kiliddən çıxarılıb. Açmaq üçün basın."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Üz tanınıb. Açmaq üçün basın."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Üz tanınıb. \"Kiliddən çıxar\" ikonasına basıb açın."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"Yenidən cəhd etmək üçün yuxarı sürüşdürün"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC istifadə etmək üçün kiliddən çıxarın"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Bu cihaz təşkilatınıza məxsusdur"</string>
@@ -467,7 +473,7 @@
<string name="wallet_title" msgid="5369767670735827105">"Pulqabı"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"Telefonunuzla daha sürətli və təhlükəsiz satınalmalar etmək üçün ayarlayın"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"Hamısını göstər"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"Kart əlavə edin"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"Açmaq üçün toxunun"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"Güncəllənir"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"İstifadə etmək üçün kiliddən çıxarın"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Kartların əldə edilməsində problem oldu, sonra yenidən cəhd edin"</string>
@@ -693,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Xəbərdarlıqlar"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Batareya"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Skrinşotlar"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Ümumi Mesajlar"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"Yaddaş"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Məsləhətlər"</string>
<string name="instant_apps" msgid="8337185853050247304">"Ani Tətbiqlər"</string>
@@ -727,6 +736,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"Batareya bitmək üzrə olduqda aktiv edin"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"Xeyr, təşəkkür"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"İstifadə olunur"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Tətbiqlər <xliff:g id="TYPES_LIST">%s</xliff:g> istifadə edir."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" və "</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g> cihazında oxutmaq üçün yaxınlaşın"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Burada oxutmaq üçün <xliff:g id="DEVICENAME">%1$s</xliff:g> cihazına yaxınlaşın"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> cihazında oxudulur"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Bu telefonda oxudulur"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Xəta oldu. Yenə cəhd edin."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Aktiv deyil, tətbiqi yoxlayın"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Tapılmadı"</string>
@@ -853,6 +862,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"Saxlayın"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"Başlanır…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"Yayımlamaq mümkün deyil"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Yadda saxlamaq mümkün deyil. Yenə cəhd edin."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Yadda saxlamaq mümkün deyil."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Montaj nömrəsi"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Versiya nömrəsi mübadilə buferinə kopyalandı."</string>
<string name="basic_status" msgid="2315371112182658176">"Açıq söhbət"</string>
@@ -937,6 +948,10 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Kopyalanmış mətni redaktə edin"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Kopyalanmış şəkli redaktə edin"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Yaxınlıqdakı cihaza göndərin"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"Baxmaq üçün toxunun"</string>
+ <string name="clipboard_text_copied" msgid="5100836834278976679">"Mətn kopyalanıb"</string>
+ <string name="clipboard_image_copied" msgid="3793365360174328722">"Şəkil Kopyalanıb"</string>
+ <string name="clipboard_content_copied" msgid="144452398567828145">"Məzmun kopyalanıb"</string>
<string name="add" msgid="81036585205287996">"Əlavə edin"</string>
<string name="manage_users" msgid="1823875311934643849">"İstifadəçiləri idarə edin"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"Bu bildiriş Ayrılmış ekrana sürüşdürməyi dəstəkləmir."</string>
@@ -945,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Siqnal ayarlanıb"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera və mikrofon deaktivdir"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# bildiriş}other{# bildiriş}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Yayım"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> tətbiqinin yayımlanması dayandırılsın?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> tətbiqini yayımlasanız və ya nəticəni dəyişsəniz, cari yayımınız dayandırılacaq"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> tətbiqini yayımlayın"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Nəticəni dəyişdirin"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Naməlum"</string>
</resources>
diff --git a/packages/SystemUI/res/values-az/tiles_states_strings.xml b/packages/SystemUI/res/values-az/tiles_states_strings.xml
index 0311794..fb745b25 100644
--- a/packages/SystemUI/res/values-az/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-az/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Deaktiv"</item>
<item msgid="460891964396502657">"Aktiv"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Əlçatmazdır"</item>
+ <item msgid="8014986104355098744">"Deaktiv"</item>
+ <item msgid="5966994759929723339">"Aktiv"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index c5add48..b3753d2 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Probajte da ponovo napravite snimak ekrana"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"Čuvanje snimka ekrana nije uspelo"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Aplikacija ili organizacija ne dozvoljavaju pravljenje snimaka ekrana"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"IT administrator blokira pravljenje snimaka ekrana"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Izmeni"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Izmenite snimak ekrana"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"Delite snimak ekrana"</string>
@@ -226,6 +227,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automatska rotacija"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Automatsko rotiranje ekrana"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Lokacija"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Čuvar ekrana"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Pristup kameri"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Pristup mikrofonu"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Dostupno"</string>
@@ -320,6 +322,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Otključano je licem. Pritisnite da biste otvorili."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Lice je prepoznato. Pritisnite da biste otvorili."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Lice prepoznato. Pritisnite ikonu otključavanja za otvaranje."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"Prevucite nagore da biste probali ponovo"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Otključajte da biste koristili NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Ovaj uređaj pripada organizaciji"</string>
@@ -470,7 +476,7 @@
<string name="wallet_title" msgid="5369767670735827105">"Novčanik"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"Obavite konfigurisanje da biste mogli brže i sigurnije da kupujete pomoću telefona"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"Prikaži sve"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"Dodajte karticu"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"Dodirnite i otvorite"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"Ažurira se"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Otključaj radi korišćenja"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Došlo je do problema pri preuzimanju kartica. Probajte ponovo kasnije"</string>
@@ -515,7 +521,7 @@
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"Prikazuje se u vrhu obaveštenja o konverzacijama i kao slika profila na zaključanom ekranu, pojavljuje se kao oblačić"</string>
<string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"Prikazuje se u vrhu obaveštenja o konverzacijama i kao slika profila na zaključanom ekranu, prekida režim Ne uznemiravaj"</string>
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Prikazuje se u vrhu obaveštenja o konverzacijama i kao slika profila na zaključanom ekranu, pojavljuje se kao oblačić, prekida režim Ne uznemiravaj"</string>
- <string name="notification_priority_title" msgid="2079708866333537093">"Prioritet"</string>
+ <string name="notification_priority_title" msgid="2079708866333537093">"Prioritetno"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ne podržava funkcije konverzacije"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Ova obaveštenja ne mogu da se menjaju."</string>
<string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Obaveštenja o pozivima ne mogu da se menjaju."</string>
@@ -698,7 +704,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Obaveštenja"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Baterija"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Snimci ekrana"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Opšte poruke"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"Memorijski prostor"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Saveti"</string>
<string name="instant_apps" msgid="8337185853050247304">"Instant aplikacije"</string>
@@ -732,6 +741,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"Uključite ako će baterija verovatno da se isprazni"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"Ne, hvala"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Izdvoji SysUI mem."</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"U upotrebi"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Aplikacije koriste <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" i "</string>
@@ -830,7 +840,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Približite da biste puštali muziku na: <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Približite se uređaju <xliff:g id="DEVICENAME">%1$s</xliff:g> da biste na njemu puštali"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Pušta se na uređaju <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Pušta se na ovom telefonu"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Došlo je do greške. Probajte ponovo."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Neaktivno. Vidite aplikaciju"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Nije pronađeno"</string>
@@ -859,6 +868,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"Sačuvaj"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"Pokreće se…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"Emitovanje nije uspelo"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Čuvanje nije uspelo. Probajte ponovo."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Čuvanje nije uspelo."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Broj verzije"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Broj verzije je kopiran u privremenu memoriju."</string>
<string name="basic_status" msgid="2315371112182658176">"Otvorite konverzaciju"</string>
@@ -944,6 +955,13 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Izmenite kopirani tekst"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Izmenite kopiranu sliku"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Pošalji na uređaj u blizini"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"Dodirnite da biste pregledali"</string>
+ <!-- no translation found for clipboard_text_copied (5100836834278976679) -->
+ <skip />
+ <!-- no translation found for clipboard_image_copied (3793365360174328722) -->
+ <skip />
+ <!-- no translation found for clipboard_content_copied (144452398567828145) -->
+ <skip />
<string name="add" msgid="81036585205287996">"Dodaj"</string>
<string name="manage_users" msgid="1823875311934643849">"Upravljajte korisnicima"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"Ovo obaveštenje ne podržava prevlačenje na podeljeni ekran."</string>
@@ -952,4 +970,12 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm je podešen"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera i mikrofon su isključeni"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# obaveštenje}one{# obaveštenje}few{# obaveštenja}other{# obaveštenja}}"</string>
+ <!-- no translation found for broadcasting_description_is_broadcasting (765627502786404290) -->
+ <skip />
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Želite da zaustavite emitovanje aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Ako emitujete aplikaciju <xliff:g id="SWITCHAPP">%1$s</xliff:g> ili promenite izlaz, aktuelno emitovanje će se zaustaviti"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Emitujte aplikaciju <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Promenite izlaz"</string>
+ <!-- no translation found for bt_le_audio_broadcast_dialog_unknown_name (3791472237793443044) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/tiles_states_strings.xml b/packages/SystemUI/res/values-b+sr+Latn/tiles_states_strings.xml
index a057c48..b69b064 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Isključeno"</item>
<item msgid="460891964396502657">"Uključeno"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Nedostupno"</item>
+ <item msgid="8014986104355098744">"Isključeno"</item>
+ <item msgid="5966994759929723339">"Uključeno"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index b67bf4e..19cd7e8 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Паспрабуйце зрабіць здымак экрана яшчэ раз"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"Не ўдалося захаваць здымак экрана"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Рабіць здымкі экрана не дазваляе праграма ці ваша арганізацыя"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Стварэнне здымкаў экрана заблакіравана IT-адміністратарам"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Змяніць"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Змяніць здымак экрана"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"Абагуліць здымак экрана"</string>
@@ -227,6 +228,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Аўтапаварот"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Аўтаматычны паварот экрана"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Месцазнаходжанне"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Экранная застаўка"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Доступ да камеры"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Доступ да мікрафона"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Доступ дазволены"</string>
@@ -322,6 +324,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Разблакіравана распазнаваннем твару. Націсніце, каб адкрыць."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Твар распазнаны. Націсніце, каб адкрыць."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Твар распазнаны. Для адкрыцця націсніце значок разблакіроўкі."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"Прагартайце ўверх, каб паўтарыць спробу"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Разблакіруйце, каб выкарыстоўваць NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Гэта прылада належыць вашай арганізацыі"</string>
@@ -473,7 +479,7 @@
<string name="wallet_title" msgid="5369767670735827105">"Кашалёк"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"Наладзьце картку, каб рабіць больш хуткія і бяспечныя куплі з дапамогай тэлефона"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"Паказаць усе"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"Дадаць карту"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"Націсніце, каб адкрыць"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"Ідзе абнаўленне"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Разблакіраваць для выкарыстання"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Узнікла праблема з загрузкай вашых карт. Паўтарыце спробу пазней"</string>
@@ -703,7 +709,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Абвесткі"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Акумулятар"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Здымкі экрана"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Агульныя паведамленні"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"Захоўванне"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Падказкі"</string>
<string name="instant_apps" msgid="8337185853050247304">"Імгненныя праграмы"</string>
@@ -737,6 +746,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"Уключыце, калі зарад акумулятара заканчваецца"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"Не, дзякуй"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"Выкарыстоўваецца"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Праграмы выкарыстоўваюць: <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" і "</string>
@@ -836,7 +846,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Каб прайграць мультымедыя на прыладзе \"<xliff:g id="DEVICENAME">%1$s</xliff:g>\", наблізьцеся да яе"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Падыдзіце бліжэй да прылады \"<xliff:g id="DEVICENAME">%1$s</xliff:g>\", каб прайграць на гэтай"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Прайграецца на прыладзе \"<xliff:g id="DEVICENAME">%1$s</xliff:g>\""</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Прайграецца на гэтым тэлефоне"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Нешта пайшло не так. Паўтарыце спробу."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Неактыўна, праверце праграму"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Не знойдзена"</string>
@@ -865,6 +874,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"Захаваць"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"Запускаецца…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"Не ўдалося запусціць трансляцыю"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Не ўдалося захаваць. Паўтарыце спробу."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Не ўдалося захаваць."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Нумар зборкі"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Нумар зборкі скапіраваны ў буфер абмену."</string>
<string name="basic_status" msgid="2315371112182658176">"Адкрытая размова"</string>
@@ -951,6 +962,13 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Змяніць скапіраваны тэкст"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Змяніць скапіраваны відарыс"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Адправіць на прыладу паблізу"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"Націсніце для прагляду"</string>
+ <!-- no translation found for clipboard_text_copied (5100836834278976679) -->
+ <skip />
+ <!-- no translation found for clipboard_image_copied (3793365360174328722) -->
+ <skip />
+ <!-- no translation found for clipboard_content_copied (144452398567828145) -->
+ <skip />
<string name="add" msgid="81036585205287996">"Дадаць"</string>
<string name="manage_users" msgid="1823875311934643849">"Кіраванне карыстальнікамі"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"Гэта апавяшчэнне нельга перацягнуць на падзелены экран."</string>
@@ -959,4 +977,12 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Будзільнік зададзены"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Камера і мікрафон выключаны"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# апавяшчэнне}one{# апавяшчэнне}few{# апавяшчэнні}many{# апавяшчэнняў}other{# апавяшчэння}}"</string>
+ <!-- no translation found for broadcasting_description_is_broadcasting (765627502786404290) -->
+ <skip />
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Спыніць трансляцыю праграмы \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Пры пераключэнні на праграму \"<xliff:g id="SWITCHAPP">%1$s</xliff:g>\" ці змяненні вываду бягучая трансляцыя спыняецца"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Трансляцыя праграмы \"<xliff:g id="SWITCHAPP">%1$s</xliff:g>\""</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Змяненне вываду"</string>
+ <!-- no translation found for bt_le_audio_broadcast_dialog_unknown_name (3791472237793443044) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-be/tiles_states_strings.xml b/packages/SystemUI/res/values-be/tiles_states_strings.xml
index d258811..8fb2da2 100644
--- a/packages/SystemUI/res/values-be/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-be/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Выключана"</item>
<item msgid="460891964396502657">"Уключана"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Недаступна"</item>
+ <item msgid="8014986104355098744">"Выключана"</item>
+ <item msgid="5966994759929723339">"Уключана"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index aada58b..87a2187 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Опитайте да направите екранна снимка отново"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"Екранната снимка не може да се запази"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Правенето на екранни снимки не е разрешено от приложението или организацията ви"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Правенето на екранни снимки е блокирано от системния ви администратор"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Редактиране"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Редактиране на екранната снимка"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"Споделяне на екранната снимка"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Автоматична ориентация"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Автоматично завъртане на екрана"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Местоположение"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Скрийнсейвър"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Достъп до камерата"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Достъп до микрофона"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Налице"</string>
@@ -318,6 +320,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Отключено с лице. Натиснете за отваряне."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Лицето бе разпознато. Натиснете за отваряне."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Лицето бе разпознато. Отворете чрез иконата за отключване."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"Плъзнете бързо нагоре, за да опитате отново"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Отключете, за да използвате NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Това устройство принадлежи на организацията ви"</string>
@@ -467,7 +473,7 @@
<string name="wallet_title" msgid="5369767670735827105">"Портфейл"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"Купувайте по-бързо и по-сигурно с телефона си"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"Показване на всички"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"Добавяне на карта"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"Докоснете за отваряне"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"Актуализира се"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Отключване с цел използване"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"При извличането на картите ви възникна проблем. Моля, опитайте отново по-късно"</string>
@@ -693,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Сигнали"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Батерия"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Екранни снимки"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Общи съобщения"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"Хранилище"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Съвети"</string>
<string name="instant_apps" msgid="8337185853050247304">"Мигновени приложения"</string>
@@ -727,6 +736,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"Включване, когато е вероятно батерията да се изтощи"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"Не, благодаря"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"Използва се"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Някои приложения използват <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" и "</string>
@@ -804,7 +814,7 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Прекарайте пръст, за да видите повече"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Препоръките се зареждат"</string>
<string name="controls_media_title" msgid="1746947284862928133">"Мултимедия"</string>
- <string name="controls_media_close_session" msgid="4780485355795635052">"Да се скрие ли за <xliff:g id="APP_NAME">%1$s</xliff:g> тази контрола за мултимедията?"</string>
+ <string name="controls_media_close_session" msgid="4780485355795635052">"Скриване за <xliff:g id="APP_NAME">%1$s</xliff:g> на контролата за мултимедия?"</string>
<string name="controls_media_active_session" msgid="3146882316024153337">"Текущата сесия за мултимедия не бе скрита."</string>
<string name="controls_media_dismiss_button" msgid="4485675693008031646">"Скриване"</string>
<string name="controls_media_resume" msgid="1933520684481586053">"Възобновяване"</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Преместете се по-близо, за да се възпроизведе на <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Приближете се до <xliff:g id="DEVICENAME">%1$s</xliff:g> за възпроизвеждане на това устройство"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Възпроизвежда се на <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Възпроизвежда се на този телефон"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Нещо се обърка. Опитайте отново."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Неактивно, проверете прилож."</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Не е намерено"</string>
@@ -853,6 +862,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"Запазване"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"Стартира се…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"Предаването не е възможно"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Не може да се запази. Опитайте отново."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Не може да се запази."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Номер на компилацията"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Номерът на компилацията е копиран в буферната памет."</string>
<string name="basic_status" msgid="2315371112182658176">"Отворен разговор"</string>
@@ -937,6 +948,13 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Редактиране на копирания текст"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Редактиране на копираното изображение"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Изпращане до устройство в близост"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"Докоснете за преглед"</string>
+ <!-- no translation found for clipboard_text_copied (5100836834278976679) -->
+ <skip />
+ <!-- no translation found for clipboard_image_copied (3793365360174328722) -->
+ <skip />
+ <!-- no translation found for clipboard_content_copied (144452398567828145) -->
+ <skip />
<string name="add" msgid="81036585205287996">"Добавяне"</string>
<string name="manage_users" msgid="1823875311934643849">"Управление на потребителите"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"Това известие не поддържа плъзгане за разделяне на екрана."</string>
@@ -945,4 +963,12 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Будилникът е зададен"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Камерата и микрофонът са изключени"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# известие}other{# известия}}"</string>
+ <!-- no translation found for broadcasting_description_is_broadcasting (765627502786404290) -->
+ <skip />
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Да се спре ли предаването на <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Ако предавате <xliff:g id="SWITCHAPP">%1$s</xliff:g> или промените изхода, текущото ви предаване ще бъде прекратено"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Предаване на <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Промяна на изхода"</string>
+ <!-- no translation found for bt_le_audio_broadcast_dialog_unknown_name (3791472237793443044) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-bg/tiles_states_strings.xml b/packages/SystemUI/res/values-bg/tiles_states_strings.xml
index da5c325..b85133b 100644
--- a/packages/SystemUI/res/values-bg/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-bg/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Изкл."</item>
<item msgid="460891964396502657">"Вкл."</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Не е налице"</item>
+ <item msgid="8014986104355098744">"Изкл."</item>
+ <item msgid="5966994759929723339">"Вкл."</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 9cf2d07..2120e72 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"আবার স্ক্রিনশট নেওয়ার চেষ্টা করুন"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"স্ক্রিনশট সেভ করা যায়নি"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"এই অ্যাপ বা আপনার প্রতিষ্ঠান স্ক্রিনশট নেওয়ার অনুমতি দেয়নি"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"আপনার আইটি অ্যাডমিন স্ক্রিনশট নেওয়ার সুবিধা ব্লক করেছেন"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"এডিট করুন"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"স্ক্রিনশট এডিট করুন"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"স্ক্রিনশট শেয়ার করুন"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"নিজে থেকে ঘুরবে"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"অটো-রোটেট স্ক্রিন"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"লোকেশন"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"স্ক্রিন সেভার"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"ক্যামেরা অ্যাক্সেস"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"মাইক্রোফোন অ্যাক্সেস"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"উপলভ্য"</string>
@@ -318,6 +320,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"ফেসের সাহায্যে আনলক করা হয়েছে। খোলার জন্য প্রেস করুন।"</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"ফেস শনাক্ত করা হয়েছে। খোলার জন্য প্রেস করুন।"</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"ফেস শনাক্ত করা হয়েছে। খোলার জন্য আনলক আইকন প্রেস করুন।"</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"আবার চেষ্টা করতে উপরের দিকে সোয়াইপ করুন"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC ব্যবহার করতে আনলক করুন"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"এই ডিভাইসটি আপনার প্রতিষ্ঠানের"</string>
@@ -467,7 +473,7 @@
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"ফোন ব্যবহার করে আরও দ্রুত ও আরও নিরাপদে কেনাকাটা করার জন্য সেট-আপ করুন"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"সবকটি দেখুন"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"কার্ড যোগ করুন"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"খোলার জন্য ট্যাপ করুন"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"আপডেট করা হচ্ছে"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ব্যবহার করতে আনলক করুন"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"আপনার কার্ড সংক্রান্ত তথ্য পেতে সমস্যা হয়েছে, পরে আবার চেষ্টা করুন"</string>
@@ -693,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"সতর্কতা"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"ব্যাটারি"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"স্ক্রীনশটস"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"সাধারণ বার্তাগুলি"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"স্টোরেজ"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"হিন্ট"</string>
<string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string>
@@ -727,6 +736,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"ব্যাটারির চার্জ শেষ হয়ে যাওয়ার সম্ভাবনা দেখা দিলে চালু করুন"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"না থাক"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"ব্যবহার হচ্ছে"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"অ্যাপ্লিকেশনগুলি আপনার <xliff:g id="TYPES_LIST">%s</xliff:g> ব্যবহার করছে।"</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" এবং "</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g>-এ চালাতে আরও কাছে আনুন"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"এখান থেকে চালাতে <xliff:g id="DEVICENAME">%1$s</xliff:g>-এর কাছে নিয়ে যান"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g>-এ ভিডিও চালানো হচ্ছে"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"এই ফোনে চালানো হচ্ছে"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"কোনও সমস্যা হয়েছে। আবার চেষ্টা করুন।"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"বন্ধ আছে, অ্যাপ চেক করুন"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"খুঁজে পাওয়া যায়নি"</string>
@@ -853,6 +862,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"সেভ করুন"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"শুরু করা হচ্ছে…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"সম্প্রচার করা যাচ্ছে না"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"সেভ করা যাচ্ছে না। আবার চেষ্টা করুন।"</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"সেভ করা যাচ্ছে না।"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"বিল্ড নম্বর"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"বিল্ড নম্বর ক্লিপবোর্ডে কপি করা হয়েছে।"</string>
<string name="basic_status" msgid="2315371112182658176">"খোলা কথোপকথন"</string>
@@ -937,6 +948,13 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"কপি করা টেক্সট এডিট করুন"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"কপি করা ছবি এডিট করুন"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"আশেপাশের ডিভাইসে পাঠান"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"দেখতে ট্যাপ করুন"</string>
+ <!-- no translation found for clipboard_text_copied (5100836834278976679) -->
+ <skip />
+ <!-- no translation found for clipboard_image_copied (3793365360174328722) -->
+ <skip />
+ <!-- no translation found for clipboard_content_copied (144452398567828145) -->
+ <skip />
<string name="add" msgid="81036585205287996">"যোগ করুন"</string>
<string name="manage_users" msgid="1823875311934643849">"ব্যবহারকারীদের ম্যানেজ করুন"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"স্প্লিটস্ক্রিন মোডে এই বিজ্ঞপ্তি টেনে আনা যাবে না।"</string>
@@ -945,4 +963,12 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"অ্যালার্ম সেট করা হয়েছে"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"ক্যামেরা ও মাইক্রোফোন বন্ধ আছে"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{#টি বিজ্ঞপ্তি}one{#টি বিজ্ঞপ্তি}other{#টি বিজ্ঞপ্তি}}"</string>
+ <!-- no translation found for broadcasting_description_is_broadcasting (765627502786404290) -->
+ <skip />
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> সম্প্রচার বন্ধ করবেন?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"আপনি <xliff:g id="SWITCHAPP">%1$s</xliff:g> সম্প্রচার করলে বা আউটপুট পরিবর্তন করলে, আপনার বর্তমান সম্প্রচার বন্ধ হয়ে যাবে"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> সম্প্রচার করুন"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"আউটপুট পরিবর্তন করুন"</string>
+ <!-- no translation found for bt_le_audio_broadcast_dialog_unknown_name (3791472237793443044) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-bn/tiles_states_strings.xml b/packages/SystemUI/res/values-bn/tiles_states_strings.xml
index 784d974..d70afc0 100644
--- a/packages/SystemUI/res/values-bn/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-bn/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"বন্ধ আছে"</item>
<item msgid="460891964396502657">"চালু আছে"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"অনুপলভ্য"</item>
+ <item msgid="8014986104355098744">"বন্ধ আছে"</item>
+ <item msgid="5966994759929723339">"চালু আছে"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index c83f6c3..0292e52 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Pokušajte ponovo snimiti ekran"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"Nije moguće sačuvati snimak ekrana"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Ova aplikacija ili vaša organizacija ne dozvoljavaju snimanje ekrana"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Snimanje ekrana je blokirao IT administrator"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Uredite"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Uredite snimak ekrana"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"Dijeljenje snimka ekrana"</string>
@@ -226,6 +227,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automatsko rotiranje"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Automatsko rotiranje ekrana"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Lokacija"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Čuvar ekrana"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Pristup kameri"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Pristup mikrofonu"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Dostupno"</string>
@@ -320,6 +322,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Otključano licem. Pritisnite da otvorite."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Lice prepoznato. Pritisnite da otvorite."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Lice prepoznato. Pritisnite ikonu za otklj. da otvorite."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"Prevucite prema gore da pokušate ponovo"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Otključajte da koristite NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Ovaj uređaj pripada vašoj organizaciji"</string>
@@ -470,7 +476,7 @@
<string name="wallet_title" msgid="5369767670735827105">"Novčanik"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"Postavite aplikaciju za brže i sigurnije kupovine putem telefona"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"Prikaži sve"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"Dodajte karticu"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"Dodirnite da otvorite"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"Ažuriranje"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Otključajte da koristite"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Došlo je do problema prilikom preuzimanja vaših kartica. Pokušajte ponovo kasnije"</string>
@@ -698,7 +704,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Obavještenja"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Baterija"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Snimci ekrana"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Opće poruke"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"Pohrana"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Savjeti"</string>
<string name="instant_apps" msgid="8337185853050247304">"Instant aplikacije"</string>
@@ -732,6 +741,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"Uključite ako je vjerovatno da će se baterija istrošiti"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"Ne, hvala"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Izdvoji SysUI mem."</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"U upotrebi"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Aplikacije koriste <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" i "</string>
@@ -810,7 +820,7 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Prevucite da vidite više"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Učitavanje preporuka"</string>
<string name="controls_media_title" msgid="1746947284862928133">"Mediji"</string>
- <string name="controls_media_close_session" msgid="4780485355795635052">"Sakriti kontrolu medijskog sadržaja za aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="controls_media_close_session" msgid="4780485355795635052">"Sakriti kontrolu medija za aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="controls_media_active_session" msgid="3146882316024153337">"Trenutna sesija medija se ne može sakriti."</string>
<string name="controls_media_dismiss_button" msgid="4485675693008031646">"Sakrij"</string>
<string name="controls_media_resume" msgid="1933520684481586053">"Nastavi"</string>
@@ -830,7 +840,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Približite se da reproducirate na uređaju <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Približite se uređaju <xliff:g id="DEVICENAME">%1$s</xliff:g> da na njemu reproducirate"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Reproducira se na uređaju <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Reproducira se na ovom telefonu"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Nešto nije uredu. Pokušajte ponovo."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Neaktivno, vidite aplikaciju"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Nije pronađeno"</string>
@@ -859,6 +868,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"Sačuvaj"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"Pokretanje…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"Nije moguće emitirati"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Nije moguće sačuvati. Pokušajte ponovo."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Nije moguće sačuvati."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Broj verzije"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Broj verzije je kopiran u međumemoriju."</string>
<string name="basic_status" msgid="2315371112182658176">"Otvoreni razgovor"</string>
@@ -944,6 +955,10 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Uredi kopirani tekst"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Uredi kopiranu sliku"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Pošalji na uređaj u blizini"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"Dodirnite da vidite"</string>
+ <string name="clipboard_text_copied" msgid="5100836834278976679">"Tekst je kopiran"</string>
+ <string name="clipboard_image_copied" msgid="3793365360174328722">"Slika je kopirana"</string>
+ <string name="clipboard_content_copied" msgid="144452398567828145">"Sadržaj je kopiran"</string>
<string name="add" msgid="81036585205287996">"Dodaj"</string>
<string name="manage_users" msgid="1823875311934643849">"Upravljajte korisnicima"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"Ovo obavještenje ne podržava prevlačenje na podijeljeni ekran."</string>
@@ -952,4 +967,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm je postavljen"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera i mikrofon su isključeni"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# obavještenje}one{# obavještenje}few{# obavještenja}other{# obavještenja}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Emitiranje"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Zaustaviti emitiranje aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Ako emitirate aplikaciju <xliff:g id="SWITCHAPP">%1$s</xliff:g> ili promijenite izlaz, trenutno emitiranje će se zaustaviti"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Emitiraj aplikaciju <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Promijeni izlaz"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Nepoznato"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bs/tiles_states_strings.xml b/packages/SystemUI/res/values-bs/tiles_states_strings.xml
index a057c48..b69b064 100644
--- a/packages/SystemUI/res/values-bs/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-bs/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Isključeno"</item>
<item msgid="460891964396502657">"Uključeno"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Nedostupno"</item>
+ <item msgid="8014986104355098744">"Isključeno"</item>
+ <item msgid="5966994759929723339">"Uključeno"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 376aa94..283bfad 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Prova de tornar a fer una captura de pantalla"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"No es pot desar la captura de pantalla"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"L\'aplicació o la teva organització no permeten fer captures de pantalla"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"El teu administrador de TI ha bloquejat les captures de pantalla"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Edita"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Edita la captura de pantalla"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"Comparteix la captura de pantalla"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Gira automàticament"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Gira la pantalla automàticament"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Ubicació"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Estalvi de pantalla"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Accés a la càmera"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Accés al micròfon"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Disponible"</string>
@@ -318,6 +320,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"S\'ha desbloquejat amb la cara. Prem per obrir."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"S\'ha reconegut la cara. Prem per obrir."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"S\'ha reconegut la cara. Prem la icona per obrir."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"Llisca cap a dalt per tornar-ho a provar"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Desbloqueja per utilitzar l\'NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Aquest dispositiu pertany a la teva organització"</string>
@@ -467,7 +473,7 @@
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"Configura una manera més ràpida i segura de fer compres amb el telèfon"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"Mostra-ho tot"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"Afegeix una targeta"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"Toca per obrir"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"S\'està actualitzant"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Desbloqueja per utilitzar"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Hi ha hagut un problema en obtenir les teves targetes; torna-ho a provar més tard"</string>
@@ -693,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Alertes"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Bateria"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Captures de pantalla"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Missatges generals"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"Emmagatzematge"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Suggeriments"</string>
<string name="instant_apps" msgid="8337185853050247304">"Aplicacions instantànies"</string>
@@ -727,6 +736,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"Activa\'l quan sigui probable que et quedis sense bateria"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"No, gràcies"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Aboca el monticle de SysUI"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"En ús"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Algunes aplicacions estan fent servir el següent: <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" i "</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Mou més a prop per reproduir a <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Acosta\'t a <xliff:g id="DEVICENAME">%1$s</xliff:g> per reproduir el contingut aquí"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"S\'està reproduint a <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"S\'està reproduint en aquest telèfon"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"S\'ha produït un error. Torna-ho a provar."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inactiu; comprova l\'aplicació"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"No s\'ha trobat"</string>
@@ -853,6 +862,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"Desa"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"S\'està iniciant…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"No es pot emetre"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"No es pot desar. Torna-ho a provar."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"No es pot desar."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Número de compilació"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"El número de compilació s\'ha copiat al porta-retalls."</string>
<string name="basic_status" msgid="2315371112182658176">"Conversa oberta"</string>
@@ -937,6 +948,13 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Edita el text que has copiat"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Edita la imatge que has copiat"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Envia a un dispositiu proper"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"Toca per veure"</string>
+ <!-- no translation found for clipboard_text_copied (5100836834278976679) -->
+ <skip />
+ <!-- no translation found for clipboard_image_copied (3793365360174328722) -->
+ <skip />
+ <!-- no translation found for clipboard_content_copied (144452398567828145) -->
+ <skip />
<string name="add" msgid="81036585205287996">"Afegeix"</string>
<string name="manage_users" msgid="1823875311934643849">"Gestiona els usuaris"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"Aquesta notificació no es pot arrossegar a la pantalla dividida."</string>
@@ -945,4 +963,12 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarma definida"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Càmera i micròfon desactivats"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notificació}other{# notificacions}}"</string>
+ <!-- no translation found for broadcasting_description_is_broadcasting (765627502786404290) -->
+ <skip />
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Vols deixar d\'emetre <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Si emets <xliff:g id="SWITCHAPP">%1$s</xliff:g> o canvies la sortida, l\'emissió actual s\'aturarà"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Emet <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Canvia la sortida"</string>
+ <!-- no translation found for bt_le_audio_broadcast_dialog_unknown_name (3791472237793443044) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ca/tiles_states_strings.xml b/packages/SystemUI/res/values-ca/tiles_states_strings.xml
index 5977679..242cbd3 100644
--- a/packages/SystemUI/res/values-ca/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ca/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Desactivat"</item>
<item msgid="460891964396502657">"Activat"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"No disponible"</item>
+ <item msgid="8014986104355098744">"Desactivat"</item>
+ <item msgid="5966994759929723339">"Activat"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 5850d5d..6edfc46 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Zkuste snímek pořídit znovu"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"Snímek obrazovky se nepodařilo uložit"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Aplikace nebo organizace zakazuje pořizování snímků obrazovky"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Pořizování snímků obrazovky je blokováno administrátorem IT"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Upravit"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Upravit snímek obrazovky"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"Sdílet snímek obrazovky"</string>
@@ -227,6 +228,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automatické otáčení"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Automatické otočení obrazovky"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Poloha"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Spořič obrazovky"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Přístup k fotoaparátu"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Přístup k mikrofonu"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Dostupné"</string>
@@ -283,8 +285,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Do svítání"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Zapnout v <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Do <xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="quick_settings_dark_mode_secondary_label_on_at_bedtime" msgid="2274300599408864897">"Zapnout při večerce"</string>
- <string name="quick_settings_dark_mode_secondary_label_until_bedtime_ends" msgid="1790772410777123685">"Dokud neskončí večerka"</string>
+ <string name="quick_settings_dark_mode_secondary_label_on_at_bedtime" msgid="2274300599408864897">"Zapnout během nočního klidu"</string>
+ <string name="quick_settings_dark_mode_secondary_label_until_bedtime_ends" msgid="1790772410777123685">"Dokud neskončí noční klid"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC je vypnuto"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC je zapnuto"</string>
@@ -322,6 +324,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Odemknuto obličejem. Stisknutím otevřete."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Obličej rozpoznán. Stisknutím otevřete."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Obličej rozpoznán. Klepněte na ikonu odemknutí."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"Přejetím nahoru to zkusíte znovu"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC vyžaduje odemknutou obrazovku"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Toto zařízení patří vaší organizaci"</string>
@@ -473,7 +479,7 @@
<string name="wallet_title" msgid="5369767670735827105">"Peněženka"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"Nastavte si rychlejší a bezpečnější platby pomocí telefonu"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"Zobrazit vše"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"Přidat kartu"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"Klepnutím otevřete"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"Aktualizace"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Odemknout a použít"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Při načítání karet došlo k problému, zkuste to později"</string>
@@ -703,7 +709,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Upozornění"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Baterie"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Snímky obrazovek"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Všeobecné zprávy"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"Úložiště"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Tipy"</string>
<string name="instant_apps" msgid="8337185853050247304">"Okamžité aplikace"</string>
@@ -737,6 +746,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"Zapnout, když bude pravděpodobné, že se vybije baterie"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"Ne, díky"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Výpis haldy SysUI"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"Používá se"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Aplikace využívají tato oprávnění: <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" a "</string>
@@ -836,7 +846,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Pokud chcete přehrávat na zařízení <xliff:g id="DEVICENAME">%1$s</xliff:g>, přibližte se k němu"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Pokud zde chcete přehrávat média, přibližte se k zařízení <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Přehrávání v zařízení <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Přehrávání v tomto telefonu"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Došlo k chybě. Zkuste to znovu."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Neaktivní, zkontrolujte aplikaci"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Nenalezeno"</string>
@@ -865,6 +874,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"Uložit"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"Spouštění…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"Vysílání se nezdařilo"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Uložení se nezdařilo. Zkuste to znovu."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Uložení se nezdařilo."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Číslo sestavení"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Číslo sestavení bylo zkopírováno do schránky."</string>
<string name="basic_status" msgid="2315371112182658176">"Otevřít konverzaci"</string>
@@ -951,6 +962,13 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Upravit zkopírovaný text"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Upravit zkopírovaný obrázek"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Odeslat do zařízení v okolí"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"Zobrazíte klepnutím"</string>
+ <!-- no translation found for clipboard_text_copied (5100836834278976679) -->
+ <skip />
+ <!-- no translation found for clipboard_image_copied (3793365360174328722) -->
+ <skip />
+ <!-- no translation found for clipboard_content_copied (144452398567828145) -->
+ <skip />
<string name="add" msgid="81036585205287996">"Přidat"</string>
<string name="manage_users" msgid="1823875311934643849">"Správa uživatelů"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"Toto oznámení nepodporuje přetažení na rozdělenou obrazovku."</string>
@@ -959,4 +977,12 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Je nastaven budík"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Fotoaparát a mikrofon jsou vypnuté"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# oznámení}few{# oznámení}many{# oznámení}other{# oznámení}}"</string>
+ <!-- no translation found for broadcasting_description_is_broadcasting (765627502786404290) -->
+ <skip />
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Zastavit vysílání v aplikaci <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Pokud budete vysílat v aplikaci <xliff:g id="SWITCHAPP">%1$s</xliff:g> nebo změníte výstup, aktuální vysílání se zastaví"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Vysílat v aplikaci <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Změna výstupu"</string>
+ <!-- no translation found for bt_le_audio_broadcast_dialog_unknown_name (3791472237793443044) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-cs/tiles_states_strings.xml b/packages/SystemUI/res/values-cs/tiles_states_strings.xml
index 2af84d9..64e83e0 100644
--- a/packages/SystemUI/res/values-cs/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-cs/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Vypnuto"</item>
<item msgid="460891964396502657">"Zapnuto"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Nedostupné"</item>
+ <item msgid="8014986104355098744">"Vypnuto"</item>
+ <item msgid="5966994759929723339">"Zapnuto"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 321d63e..51d3836 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Prøv at tage et screenshot igen"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"Dit screenshot kunne ikke gemmes."</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Appen eller din organisation tillader ikke, at du tager screenshots"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Din it-administrator har blokeret screenshot-funktionen"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Rediger"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Rediger screenshot"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"Del screenshottet"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Roter automatisk"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Roter skærmen automatisk"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Lokation"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Pauseskærm"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Kameraadgang"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Mikrofonadgang"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Tilgængelig"</string>
@@ -318,6 +320,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Låst op ved hjælp af ansigt. Tryk for at åbne."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Ansigt genkendt. Tryk for at åbne."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Ansigt genkendt. Tryk på oplåsningsikonet for at åbne."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"Stryg opad for at prøve igen"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Lås op for at bruge NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Denne enhed tilhører din organisation"</string>
@@ -467,7 +473,7 @@
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"Bliv klar til at foretage hurtigere og mere sikre køb med din telefon"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"Vis alle"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"Tilføj et kort"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"Tryk for at åbne"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"Opdaterer"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Lås op for at bruge"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Dine kort kunne ikke hentes. Prøv igen senere."</string>
@@ -693,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Underretninger"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Batteri"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Screenshots"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Generelle meddelelser"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"Lagerplads"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Tips"</string>
<string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string>
@@ -727,6 +736,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"Aktivér, når det ser ud til, at batteriet løber tør"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"Nej tak"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Gem SysUI-heap"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"I brug"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Apps anvender enhedens <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" og "</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Flyt enheden tættere på for at afspille på <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Ryk tættere på <xliff:g id="DEVICENAME">%1$s</xliff:g> for at afspille her"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Afspilles på <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Afspilles på denne telefon"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Noget gik galt. Prøv igen."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inaktiv. Tjek appen"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Ikke fundet"</string>
@@ -853,6 +862,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"Gem"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"Starter…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"Der kan ikke udsendes en fællesbesked"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Der kan ikke gemmes. Prøv igen."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Der kan ikke gemmes."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Buildnummer"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Buildnummeret blev kopieret til udklipsholderen."</string>
<string name="basic_status" msgid="2315371112182658176">"Åben samtale"</string>
@@ -903,7 +914,7 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobildata"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Forbundet"</string>
- <string name="mobile_data_off_summary" msgid="3663995422004150567">"Der oprettes ikke automatisk mobildataforbindelse"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"Ingen automatisk mobildataforbindelse"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"Der er ingen forbindelse"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"Der er ingen andre tilgængelige netværk"</string>
<string name="all_network_unavailable" msgid="4112774339909373349">"Der er ingen tilgængelige netværk"</string>
@@ -937,6 +948,13 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Rediger kopieret tekst"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Rediger kopieret billede"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Send til enhed i nærheden"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"Tryk for at se"</string>
+ <!-- no translation found for clipboard_text_copied (5100836834278976679) -->
+ <skip />
+ <!-- no translation found for clipboard_image_copied (3793365360174328722) -->
+ <skip />
+ <!-- no translation found for clipboard_content_copied (144452398567828145) -->
+ <skip />
<string name="add" msgid="81036585205287996">"Tilføj"</string>
<string name="manage_users" msgid="1823875311934643849">"Administrer brugere"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"Denne notifikation kan ikke trækkes til en opdelt skærm."</string>
@@ -945,4 +963,12 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarmen er indstillet"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera og mikrofon er slået fra"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notifikation}one{# notifikation}other{# notifikationer}}"</string>
+ <!-- no translation found for broadcasting_description_is_broadcasting (765627502786404290) -->
+ <skip />
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Stop udsendelsen <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Hvis du udsender <xliff:g id="SWITCHAPP">%1$s</xliff:g> eller skifter output, stopper din aktuelle udsendelse"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Udsend <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Skift output"</string>
+ <!-- no translation found for bt_le_audio_broadcast_dialog_unknown_name (3791472237793443044) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-da/tiles_states_strings.xml b/packages/SystemUI/res/values-da/tiles_states_strings.xml
index 0fe06b3..f0132dc 100644
--- a/packages/SystemUI/res/values-da/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-da/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Fra"</item>
<item msgid="460891964396502657">"Til"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Ikke tilgængelig"</item>
+ <item msgid="8014986104355098744">"Fra"</item>
+ <item msgid="5966994759929723339">"Til"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 81006d8..19d9080 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Versuche noch einmal, den Screenshot zu erstellen"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"Screenshot kann nicht gespeichert werden"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Die App oder deine Organisation lässt das Erstellen von Screenshots nicht zu"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Dein IT-Administrator hat das Erstellen von Screenshots blockiert"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Bearbeiten"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Screenshot bearbeiten"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"Screenshot teilen"</string>
@@ -98,7 +99,7 @@
<string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Audioinhalte auf deinem Gerät, wie Musik, Anrufe und Klingeltöne"</string>
<string name="screenrecord_mic_label" msgid="2111264835791332350">"Mikrofon"</string>
<string name="screenrecord_device_audio_and_mic_label" msgid="1831323771978646841">"Audio des Geräts und über Mikrofon"</string>
- <string name="screenrecord_start" msgid="330991441575775004">"Start"</string>
+ <string name="screenrecord_start" msgid="330991441575775004">"Starten"</string>
<string name="screenrecord_ongoing_screen_only" msgid="4459670242451527727">"Bildschirm wird aufgezeichnet"</string>
<string name="screenrecord_ongoing_screen_and_audio" msgid="5351133763125180920">"Bildschirm und Ton werden aufgezeichnet"</string>
<string name="screenrecord_taps_label" msgid="1595690528298857649">"Berührungen des Bildschirms anzeigen"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automatisch drehen"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Bildschirm automatisch drehen"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Standort"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Bildschirmschoner"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Kamerazugriff"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Mikrofonzugriff"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Verfügbar"</string>
@@ -318,6 +320,10 @@
<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 udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"Zum Wiederholen nach oben wischen"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Zur Verwendung von NFC entsperren"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Dieses Gerät gehört deiner Organisation"</string>
@@ -467,7 +473,7 @@
<string name="wallet_title" msgid="5369767670735827105">"Geldbörse"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"Füge eine Zahlungsmethode hinzu, um noch schneller und sicherer mit deinem Smartphone zu bezahlen"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"Alle anzeigen"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"Karte hinzufügen"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"Zum Öffnen tippen"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"Wird aktualisiert"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Zum Verwenden entsperren"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Beim Abrufen deiner Karten ist ein Fehler aufgetreten – bitte versuch es später noch einmal"</string>
@@ -693,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Benachrichtigungen"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Akku"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Screenshots"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Nachrichten"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"Speicher"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Hinweise"</string>
<string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string>
@@ -727,6 +736,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"Aktivieren, wenn der Akku wahrscheinlich nicht mehr lange hält"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"Nein danke"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"In Verwendung"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Apps verwenden gerade Folgendes: <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" und "</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Gehe für die Wiedergabe näher an <xliff:g id="DEVICENAME">%1$s</xliff:g> heran"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Platziere für die Wiedergabe dein Gerät näher an „<xliff:g id="DEVICENAME">%1$s</xliff:g>“"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Wird auf „<xliff:g id="DEVICENAME">%1$s</xliff:g>“ abgespielt"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Wird auf diesem Smartphone abgespielt"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Es gab ein Problem. Versuch es noch einmal."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inaktiv – sieh in der App nach"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Nicht gefunden"</string>
@@ -853,6 +862,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"Speichern"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"Wird gestartet…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"Übertragung nicht möglich"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Speichern nicht möglich. Versuche es noch einmal."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Speichern nicht möglich."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Build-Nummer"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Build-Nummer in Zwischenablage kopiert."</string>
<string name="basic_status" msgid="2315371112182658176">"Offene Unterhaltung"</string>
@@ -937,6 +948,13 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Kopierten Text bearbeiten"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Kopiertes Bild bearbeiten"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"An Gerät in der Nähe senden"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"Zum Ansehen tippen"</string>
+ <!-- no translation found for clipboard_text_copied (5100836834278976679) -->
+ <skip />
+ <!-- no translation found for clipboard_image_copied (3793365360174328722) -->
+ <skip />
+ <!-- no translation found for clipboard_content_copied (144452398567828145) -->
+ <skip />
<string name="add" msgid="81036585205287996">"Hinzufügen"</string>
<string name="manage_users" msgid="1823875311934643849">"Nutzer verwalten"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"Diese Benachrichtigung lässt sich nicht auf einen geteilten Bildschirm ziehen."</string>
@@ -945,4 +963,12 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Wecker gestellt"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera und Mikrofon ausgeschaltet"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# Benachrichtigung}other{# Benachrichtigungen}}"</string>
+ <!-- no translation found for broadcasting_description_is_broadcasting (765627502786404290) -->
+ <skip />
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> nicht mehr streamen?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Wenn du <xliff:g id="SWITCHAPP">%1$s</xliff:g> streamst oder die Ausgabe änderst, wird dein aktueller Stream beendet"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> streamen"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Ausgabe ändern"</string>
+ <!-- no translation found for bt_le_audio_broadcast_dialog_unknown_name (3791472237793443044) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-de/tiles_states_strings.xml b/packages/SystemUI/res/values-de/tiles_states_strings.xml
index ba610b3..bc50e16 100644
--- a/packages/SystemUI/res/values-de/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-de/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Aus"</item>
<item msgid="460891964396502657">"An"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Nicht verfügbar"</item>
+ <item msgid="8014986104355098744">"Aus"</item>
+ <item msgid="5966994759929723339">"An"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index b32d032..6f17112 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Δοκιμάστε να κάνετε ξανά λήψη του στιγμιότυπου οθόνης"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"Δεν είναι δυνατή η αποθήκευση στιγμιότυπου οθόνης."</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Η λήψη στιγμιότυπων οθόνης δεν επιτρέπεται από την εφαρμογή ή τον οργανισμό σας"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Η λήψη στιγμιότυπων οθόνης έχει αποκλειστεί από τον διαχειριστή IT."</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Επεξεργασία"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Επεξεργασία στιγμιότυπου οθόνης"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"Κοινοποίηση στιγμιότυπου οθόνης"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Αυτόματη περιστροφή"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Αυτόματη περιστροφή οθόνης"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Τοποθεσία"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Προφύλαξη οθόνης"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Πρόσβαση κάμερας"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Πρόσβαση μικροφώνου"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Διαθέσιμη"</string>
@@ -318,6 +320,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Ξεκλείδωμα με αναγνώριση προσώπου. Πατήστε για άνοιγμα."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Το πρόσωπο αναγνωρίστηκε. Πατήστε για άνοιγμα."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Το πρόσωπο αναγνωρ. Πατήστ. το εικον. ξεκλειδ. για άνοιγμα."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"Σύρετε προς τα πάνω για να δοκιμάσετε ξανά"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Ξεκλείδωμα για χρήση του NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Αυτή η συσκευή ανήκει στον οργανισμό σας."</string>
@@ -467,7 +473,7 @@
<string name="wallet_title" msgid="5369767670735827105">"Πορτοφόλι"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"Ολοκληρώστε τη ρύθμιση για να κάνετε πιο γρήγορες και πιο ασφαλείς αγορές με το τηλέφωνό σας"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"Εμφάνιση όλων"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"Προσθήκη κάρτας"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"Πατήστε για άνοιγμα"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"Ενημέρωση σε εξέλιξη"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Ξεκλείδωμα για χρήση"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Παρουσιάστηκε πρόβλημα με τη λήψη των καρτών σας. Δοκιμάστε ξανά αργότερα"</string>
@@ -693,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Ειδοποιήσεις"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Μπαταρία"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Στιγμιότυπα οθόνης"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Γενικά μηνύματα"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"Αποθηκευτικός χώρος"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Συμβουλές"</string>
<string name="instant_apps" msgid="8337185853050247304">"Instant Εφαρμογές"</string>
@@ -727,6 +736,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"Ενεργοποίηση όταν υπάρχει σημαντική πιθανότητα εξάντλησης της μπαταρίας"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"Όχι, ευχαριστώ"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Στιγμ. μνήμης SysUI"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"Χρησιμοποιείται"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Οι εφαρμογές χρησιμοποιούν τις λειτουργίες <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" και "</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Πλησιάστε για αναπαραγωγή στη συσκευή <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Μετακινηθείτε πιο κοντά στη συσκευή <xliff:g id="DEVICENAME">%1$s</xliff:g> για αναπαραγωγή εδώ"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Αναπαραγωγή στη συσκευή <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Αναπαραγωγή σε αυτό το τηλέφωνο"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Παρουσιάστηκε κάποιο πρόβλημα. Δοκιμάστε ξανά."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Ανενεργό, έλεγχος εφαρμογής"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Δεν βρέθηκε."</string>
@@ -853,6 +862,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"Αποθήκευση"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"Εκκίνηση…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"Δεν είναι δυνατή η μετάδοση"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Δεν είναι δυνατή η αποθήκευση. Δοκιμάστε ξανά."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Δεν είναι δυνατή η αποθήκευση."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Αριθμός έκδοσης"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Ο αριθμός έκδοσης αντιγράφηκε στο πρόχειρο."</string>
<string name="basic_status" msgid="2315371112182658176">"Άνοιγμα συνομιλίας"</string>
@@ -937,6 +948,13 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Επεξεργασία αντιγραμμένου κειμένου"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Επεξεργασία αντιγραμμένης εικόνας"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Αποστολή σε κοντινή συσκευή"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"Πατήστε για προβολή"</string>
+ <!-- no translation found for clipboard_text_copied (5100836834278976679) -->
+ <skip />
+ <!-- no translation found for clipboard_image_copied (3793365360174328722) -->
+ <skip />
+ <!-- no translation found for clipboard_content_copied (144452398567828145) -->
+ <skip />
<string name="add" msgid="81036585205287996">"Προσθήκη"</string>
<string name="manage_users" msgid="1823875311934643849">"Διαχείριση χρηστών"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"Αυτή η ειδοποίηση δεν υποστηρίζει τη μεταφορά με σύρσιμο για χρήση του διαχωρισμού οθόνης."</string>
@@ -945,4 +963,12 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Το ξυπνητήρι ρυθμίστηκε"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Η κάμερα και το μικρόφωνο έχουν απενεργοποιηθεί"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# ειδοποίηση}other{# ειδοποιήσεις}}"</string>
+ <!-- no translation found for broadcasting_description_is_broadcasting (765627502786404290) -->
+ <skip />
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Διακοπή μετάδοσης με την εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g>;"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Εάν κάνετε μετάδοση με την εφαρμογή <xliff:g id="SWITCHAPP">%1$s</xliff:g> ή αλλάξετε την έξοδο, η τρέχουσα μετάδοση θα σταματήσει"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Μετάδοση με την εφαρμογή <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Αλλαγή εξόδου"</string>
+ <!-- no translation found for bt_le_audio_broadcast_dialog_unknown_name (3791472237793443044) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-el/tiles_states_strings.xml b/packages/SystemUI/res/values-el/tiles_states_strings.xml
index 74c091e..352af39 100644
--- a/packages/SystemUI/res/values-el/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-el/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Ανενεργή"</item>
<item msgid="460891964396502657">"Ενεργή"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Μη διαθέσιμο"</item>
+ <item msgid="8014986104355098744">"Ανενεργό"</item>
+ <item msgid="5966994759929723339">"Ενεργό"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 4e70b87..c978a2d 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Try taking screenshot again"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"Can\'t save screenshot"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Taking screenshots isn\'t allowed by the app or your organisation"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Taking screenshots is blocked by your IT admin"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Edit"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Edit screenshot"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"Share screenshot"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Auto-rotate"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Auto-rotate screen"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Location"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Screensaver"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Camera access"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Mic access"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Available"</string>
@@ -318,6 +320,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Unlocked by face. Press to open."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Face recognised. Press to open."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Face recognised. Press the unlock icon to open."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"Swipe up to try again"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Unlock to use NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"This device belongs to your organisation"</string>
@@ -467,7 +473,7 @@
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"Get set up to make faster, more secure purchases with your phone"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"Show all"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"Add a card"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"Tap to open"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"Updating"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Unlock to use"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"There was a problem getting your cards. Please try again later."</string>
@@ -693,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Alerts"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Battery"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Screenshots"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"General Messages"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"Storage"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Hints"</string>
<string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string>
@@ -727,6 +736,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"Turn on when battery is likely to run out"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"No, thanks"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"In use"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Applications are using your <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" and "</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Move closer to play on <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Move closer to <xliff:g id="DEVICENAME">%1$s</xliff:g> to play here"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Playing on <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Playing on this phone"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Something went wrong. Try again."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inactive, check app"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Not found"</string>
@@ -853,6 +862,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"Save"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"Starting…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"Can’t broadcast"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Can’t save. Try again."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Can’t save."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Build number"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Build number copied to clipboard."</string>
<string name="basic_status" msgid="2315371112182658176">"Open conversation"</string>
@@ -937,6 +948,10 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Edit copied text"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Edit copied image"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Send to nearby device"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"Tap to view"</string>
+ <string name="clipboard_text_copied" msgid="5100836834278976679">"Text copied"</string>
+ <string name="clipboard_image_copied" msgid="3793365360174328722">"Image copied"</string>
+ <string name="clipboard_content_copied" msgid="144452398567828145">"Content copied"</string>
<string name="add" msgid="81036585205287996">"Add"</string>
<string name="manage_users" msgid="1823875311934643849">"Manage users"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"This notification does not support dragging to Split screen."</string>
@@ -945,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm set"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Camera and mic are off"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notification}other{# notifications}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Broadcasting"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Stop broadcasting <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"If you broadcast <xliff:g id="SWITCHAPP">%1$s</xliff:g> or change the output, your current broadcast will stop"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Broadcast <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Change output"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Unknown"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rAU/tiles_states_strings.xml b/packages/SystemUI/res/values-en-rAU/tiles_states_strings.xml
index 6f8cfb6..56cdbef 100644
--- a/packages/SystemUI/res/values-en-rAU/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Off"</item>
<item msgid="460891964396502657">"On"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Unavailable"</item>
+ <item msgid="8014986104355098744">"Off"</item>
+ <item msgid="5966994759929723339">"On"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 3825f7c..8c7c855 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Try taking screenshot again"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"Can\'t save screenshot"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Taking screenshots isn\'t allowed by the app or your organisation"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Taking screenshots is blocked by your IT admin"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Edit"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Edit screenshot"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"Share screenshot"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Auto-rotate"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Auto-rotate screen"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Location"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Screensaver"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Camera access"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Mic access"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Available"</string>
@@ -318,6 +320,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Unlocked by face. Press to open."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Face recognised. Press to open."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Face recognised. Press the unlock icon to open."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"Swipe up to try again"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Unlock to use NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"This device belongs to your organisation"</string>
@@ -467,7 +473,7 @@
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"Get set up to make faster, more secure purchases with your phone"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"Show all"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"Add a card"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"Tap to open"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"Updating"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Unlock to use"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"There was a problem getting your cards. Please try again later."</string>
@@ -693,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Alerts"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Battery"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Screenshots"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"General Messages"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"Storage"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Hints"</string>
<string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string>
@@ -727,6 +736,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"Turn on when battery is likely to run out"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"No, thanks"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"In use"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Applications are using your <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" and "</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Move closer to play on <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Move closer to <xliff:g id="DEVICENAME">%1$s</xliff:g> to play here"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Playing on <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Playing on this phone"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Something went wrong. Try again."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inactive, check app"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Not found"</string>
@@ -853,6 +862,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"Save"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"Starting…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"Can’t broadcast"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Can’t save. Try again."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Can’t save."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Build number"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Build number copied to clipboard."</string>
<string name="basic_status" msgid="2315371112182658176">"Open conversation"</string>
@@ -937,6 +948,10 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Edit copied text"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Edit copied image"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Send to nearby device"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"Tap to view"</string>
+ <string name="clipboard_text_copied" msgid="5100836834278976679">"Text copied"</string>
+ <string name="clipboard_image_copied" msgid="3793365360174328722">"Image copied"</string>
+ <string name="clipboard_content_copied" msgid="144452398567828145">"Content copied"</string>
<string name="add" msgid="81036585205287996">"Add"</string>
<string name="manage_users" msgid="1823875311934643849">"Manage users"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"This notification does not support dragging to Split screen."</string>
@@ -945,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm set"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Camera and mic are off"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notification}other{# notifications}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Broadcasting"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Stop broadcasting <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"If you broadcast <xliff:g id="SWITCHAPP">%1$s</xliff:g> or change the output, your current broadcast will stop"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Broadcast <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Change output"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Unknown"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rCA/tiles_states_strings.xml b/packages/SystemUI/res/values-en-rCA/tiles_states_strings.xml
index 6f8cfb6..56cdbef 100644
--- a/packages/SystemUI/res/values-en-rCA/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Off"</item>
<item msgid="460891964396502657">"On"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Unavailable"</item>
+ <item msgid="8014986104355098744">"Off"</item>
+ <item msgid="5966994759929723339">"On"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 4e70b87..c978a2d 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Try taking screenshot again"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"Can\'t save screenshot"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Taking screenshots isn\'t allowed by the app or your organisation"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Taking screenshots is blocked by your IT admin"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Edit"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Edit screenshot"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"Share screenshot"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Auto-rotate"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Auto-rotate screen"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Location"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Screensaver"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Camera access"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Mic access"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Available"</string>
@@ -318,6 +320,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Unlocked by face. Press to open."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Face recognised. Press to open."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Face recognised. Press the unlock icon to open."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"Swipe up to try again"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Unlock to use NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"This device belongs to your organisation"</string>
@@ -467,7 +473,7 @@
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"Get set up to make faster, more secure purchases with your phone"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"Show all"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"Add a card"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"Tap to open"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"Updating"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Unlock to use"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"There was a problem getting your cards. Please try again later."</string>
@@ -693,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Alerts"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Battery"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Screenshots"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"General Messages"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"Storage"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Hints"</string>
<string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string>
@@ -727,6 +736,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"Turn on when battery is likely to run out"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"No, thanks"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"In use"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Applications are using your <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" and "</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Move closer to play on <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Move closer to <xliff:g id="DEVICENAME">%1$s</xliff:g> to play here"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Playing on <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Playing on this phone"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Something went wrong. Try again."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inactive, check app"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Not found"</string>
@@ -853,6 +862,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"Save"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"Starting…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"Can’t broadcast"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Can’t save. Try again."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Can’t save."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Build number"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Build number copied to clipboard."</string>
<string name="basic_status" msgid="2315371112182658176">"Open conversation"</string>
@@ -937,6 +948,10 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Edit copied text"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Edit copied image"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Send to nearby device"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"Tap to view"</string>
+ <string name="clipboard_text_copied" msgid="5100836834278976679">"Text copied"</string>
+ <string name="clipboard_image_copied" msgid="3793365360174328722">"Image copied"</string>
+ <string name="clipboard_content_copied" msgid="144452398567828145">"Content copied"</string>
<string name="add" msgid="81036585205287996">"Add"</string>
<string name="manage_users" msgid="1823875311934643849">"Manage users"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"This notification does not support dragging to Split screen."</string>
@@ -945,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm set"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Camera and mic are off"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notification}other{# notifications}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Broadcasting"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Stop broadcasting <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"If you broadcast <xliff:g id="SWITCHAPP">%1$s</xliff:g> or change the output, your current broadcast will stop"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Broadcast <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Change output"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Unknown"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rGB/tiles_states_strings.xml b/packages/SystemUI/res/values-en-rGB/tiles_states_strings.xml
index 6f8cfb6..56cdbef 100644
--- a/packages/SystemUI/res/values-en-rGB/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Off"</item>
<item msgid="460891964396502657">"On"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Unavailable"</item>
+ <item msgid="8014986104355098744">"Off"</item>
+ <item msgid="5966994759929723339">"On"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 4e70b87..c978a2d 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Try taking screenshot again"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"Can\'t save screenshot"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Taking screenshots isn\'t allowed by the app or your organisation"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Taking screenshots is blocked by your IT admin"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Edit"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Edit screenshot"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"Share screenshot"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Auto-rotate"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Auto-rotate screen"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Location"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Screensaver"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Camera access"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Mic access"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Available"</string>
@@ -318,6 +320,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Unlocked by face. Press to open."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Face recognised. Press to open."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Face recognised. Press the unlock icon to open."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"Swipe up to try again"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Unlock to use NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"This device belongs to your organisation"</string>
@@ -467,7 +473,7 @@
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"Get set up to make faster, more secure purchases with your phone"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"Show all"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"Add a card"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"Tap to open"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"Updating"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Unlock to use"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"There was a problem getting your cards. Please try again later."</string>
@@ -693,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Alerts"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Battery"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Screenshots"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"General Messages"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"Storage"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Hints"</string>
<string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string>
@@ -727,6 +736,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"Turn on when battery is likely to run out"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"No, thanks"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"In use"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Applications are using your <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" and "</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Move closer to play on <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Move closer to <xliff:g id="DEVICENAME">%1$s</xliff:g> to play here"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Playing on <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Playing on this phone"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Something went wrong. Try again."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inactive, check app"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Not found"</string>
@@ -853,6 +862,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"Save"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"Starting…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"Can’t broadcast"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Can’t save. Try again."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Can’t save."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Build number"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Build number copied to clipboard."</string>
<string name="basic_status" msgid="2315371112182658176">"Open conversation"</string>
@@ -937,6 +948,10 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Edit copied text"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Edit copied image"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Send to nearby device"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"Tap to view"</string>
+ <string name="clipboard_text_copied" msgid="5100836834278976679">"Text copied"</string>
+ <string name="clipboard_image_copied" msgid="3793365360174328722">"Image copied"</string>
+ <string name="clipboard_content_copied" msgid="144452398567828145">"Content copied"</string>
<string name="add" msgid="81036585205287996">"Add"</string>
<string name="manage_users" msgid="1823875311934643849">"Manage users"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"This notification does not support dragging to Split screen."</string>
@@ -945,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm set"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Camera and mic are off"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notification}other{# notifications}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Broadcasting"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Stop broadcasting <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"If you broadcast <xliff:g id="SWITCHAPP">%1$s</xliff:g> or change the output, your current broadcast will stop"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Broadcast <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Change output"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Unknown"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rIN/tiles_states_strings.xml b/packages/SystemUI/res/values-en-rIN/tiles_states_strings.xml
index 6f8cfb6..56cdbef 100644
--- a/packages/SystemUI/res/values-en-rIN/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Off"</item>
<item msgid="460891964396502657">"On"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Unavailable"</item>
+ <item msgid="8014986104355098744">"Off"</item>
+ <item msgid="5966994759929723339">"On"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index 8a85068..7636117 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Try taking screenshot again"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"Can\'t save screenshot"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Taking screenshots isn\'t allowed by the app or your organization"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Taking screenshots is blocked by your IT admin"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Edit"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Edit screenshot"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"Share screenshot"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Auto-rotate"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Auto-rotate screen"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Location"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Screen saver"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Camera access"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Mic access"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Available"</string>
@@ -318,6 +320,12 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Unlocked by face. Press to open."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Face recognized. Press to open."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Face recognized. Press the unlock icon to open."</string>
+ <string-array name="udfps_accessibility_touch_hints">
+ <item msgid="1901953991150295169">"Move left"</item>
+ <item msgid="5558598599408514296">"Move down"</item>
+ <item msgid="4844142668312841831">"Move right"</item>
+ <item msgid="5640521437931460125">"Move up"</item>
+ </string-array>
<string name="keyguard_retry" msgid="886802522584053523">"Swipe up to try again"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Unlock to use NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"This device belongs to your organization"</string>
@@ -467,7 +475,7 @@
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"Get set up to make faster, more secure purchases with your phone"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"Show all"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"Add a card"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"Tap to open"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"Updating"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Unlock to use"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"There was a problem getting your cards, please try again later"</string>
@@ -693,7 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Alerts"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Battery"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Screenshots"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"General Messages"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Instant Apps"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"Setup"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"Storage"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Hints"</string>
<string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string>
@@ -727,6 +736,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"Turn on when battery is likely to run out"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"No thanks"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"In use"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Applications are using your <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" and "</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Move closer to play on <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Move closer to <xliff:g id="DEVICENAME">%1$s</xliff:g> to play here"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Playing on <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Playing on this phone"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Something went wrong. Try again."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inactive, check app"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Not found"</string>
@@ -853,6 +862,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"Save"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"Starting…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"Can’t broadcast"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Can’t save. Try again."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Can’t save."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Build number"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Build number copied to clipboard."</string>
<string name="basic_status" msgid="2315371112182658176">"Open conversation"</string>
@@ -937,6 +948,10 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Edit copied text"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Edit copied image"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Send to nearby device"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"Tap to view"</string>
+ <string name="clipboard_text_copied" msgid="5100836834278976679">"Text copied"</string>
+ <string name="clipboard_image_copied" msgid="3793365360174328722">"Image copied"</string>
+ <string name="clipboard_content_copied" msgid="144452398567828145">"Content copied"</string>
<string name="add" msgid="81036585205287996">"Add"</string>
<string name="manage_users" msgid="1823875311934643849">"Manage users"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"This notification does not support dragging to Splitscreen."</string>
@@ -945,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm set"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Camera and mic are off"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notification}other{# notifications}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Broadcasting"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Stop broadcasting <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"If you broadcast <xliff:g id="SWITCHAPP">%1$s</xliff:g> or change the output, your current broadcast will stop"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Broadcast <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Change output"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Unknown"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rXC/tiles_states_strings.xml b/packages/SystemUI/res/values-en-rXC/tiles_states_strings.xml
index 99ef50c..3a8e34c 100644
--- a/packages/SystemUI/res/values-en-rXC/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Off"</item>
<item msgid="460891964396502657">"On"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Unavailable"</item>
+ <item msgid="8014986104355098744">"Off"</item>
+ <item msgid="5966994759929723339">"On"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 3529d4b..674810f 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Vuelve a hacer una captura de pantalla"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"No se pudo guardar la captura de pantalla"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"La app o tu organización no permiten las capturas de pantalla"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Tu administrador de TI bloquea las capturas de pantalla"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Editar"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Editar captura de pantalla"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"Compartir captura"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Girar automáticamente"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Girar la pantalla automáticamente"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Ubicación"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Protector de pantalla"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Acceso a la cámara"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Acceso al mic."</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Disponible"</string>
@@ -318,6 +320,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Desbloqueo con rostro. Presiona para abrir."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Rostro reconocido. Presiona para abrir."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Rostro reconocido. Presiona el desbloqueo para abrir."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"Desliza el dedo hacia arriba para volver a intentarlo"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Desbloquea el dispositivo para usar NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Este dispositivo pertenece a tu organización"</string>
@@ -467,12 +473,12 @@
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"Prepárate para realizar compras rápidas y seguras con tu teléfono"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"Mostrar todo"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"Agregar una tarjeta"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"Presiona para abrir"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"Actualizando"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Desbloquear para usar"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Ocurrió un problema al obtener las tarjetas; vuelve a intentarlo más tarde"</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Configuración de pantalla de bloqueo"</string>
- <string name="qr_code_scanner_title" msgid="5290201053875420785">"Escanear código QR"</string>
+ <string name="qr_code_scanner_title" msgid="5290201053875420785">"Escanear QR"</string>
<string name="status_bar_work" msgid="5238641949837091056">"Perfil de trabajo"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Modo de avión"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"No oirás la próxima alarma a la(s) <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -693,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Alertas"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Batería"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Capturas de pantalla"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Mensajes generales"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"Almacenamiento"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Sugerencias"</string>
<string name="instant_apps" msgid="8337185853050247304">"Apps instantáneas"</string>
@@ -727,6 +736,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"Actívalo cuando la batería se esté por acabar"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"No, gracias"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Volcar pila de SysUI"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"En uso"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Hay aplicaciones que están usando tu <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" y "</string>
@@ -804,7 +814,7 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Desliza el dedo para ver más elementos"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Cargando recomendaciones"</string>
<string name="controls_media_title" msgid="1746947284862928133">"Contenido multimedia"</string>
- <string name="controls_media_close_session" msgid="4780485355795635052">"¿Quieres ocultar este control multimedia para <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="controls_media_close_session" msgid="4780485355795635052">"¿Ocultar control multimedia para <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="controls_media_active_session" msgid="3146882316024153337">"No se puede ocultar la sesión multimedia actual."</string>
<string name="controls_media_dismiss_button" msgid="4485675693008031646">"Ocultar"</string>
<string name="controls_media_resume" msgid="1933520684481586053">"Reanudar"</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Acércate para reproducir en <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Acércate a <xliff:g id="DEVICENAME">%1$s</xliff:g> para reproducir aquí"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Reproduciendo en <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Reproduciendo en este teléfono"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Se produjo un error. Vuelve a intentarlo."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inactivo. Verifica la app"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"No se encontró"</string>
@@ -853,6 +862,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"Guardar"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"Iniciando…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"Error al iniciar transmisión"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"No se puede guardar. Vuelve a intentarlo."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"No se puede guardar."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Número de compilación"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Se copió el número de compilación en el portapapeles."</string>
<string name="basic_status" msgid="2315371112182658176">"Conversación abierta"</string>
@@ -927,7 +938,7 @@
</plurals>
<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="6839542063522121108">"Incluso aunque no uses estas apps, todavía están activas y podrían afectar la duración de batería"</string>
+ <string name="fgs_manager_dialog_message" msgid="6839542063522121108">"Aunque no uses estas apps, todavía están activas y podrían afectar la duración de batería"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Detener"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Detenida"</string>
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Listo"</string>
@@ -937,6 +948,13 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Editar el texto copiado"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Editar la imagen copiada"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Enviar a dispositivos cercanos"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"Presiona para ver"</string>
+ <!-- no translation found for clipboard_text_copied (5100836834278976679) -->
+ <skip />
+ <!-- no translation found for clipboard_image_copied (3793365360174328722) -->
+ <skip />
+ <!-- no translation found for clipboard_content_copied (144452398567828145) -->
+ <skip />
<string name="add" msgid="81036585205287996">"Agregar"</string>
<string name="manage_users" msgid="1823875311934643849">"Administrar usuarios"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"Esta notificación no admite arrastrar entre pantallas divididas."</string>
@@ -945,4 +963,12 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Se estableció la alarma"</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>
+ <!-- no translation found for broadcasting_description_is_broadcasting (765627502786404290) -->
+ <skip />
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"¿Quieres dejar de transmitir <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Si transmites <xliff:g id="SWITCHAPP">%1$s</xliff:g> o cambias la salida, tu transmisión actual se detendrá"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Transmitir <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Cambia la salida"</string>
+ <!-- no translation found for bt_le_audio_broadcast_dialog_unknown_name (3791472237793443044) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-es-rUS/tiles_states_strings.xml b/packages/SystemUI/res/values-es-rUS/tiles_states_strings.xml
index f7eaba6..b1e2af4 100644
--- a/packages/SystemUI/res/values-es-rUS/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"No"</item>
<item msgid="460891964396502657">"Sí"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"No disponible"</item>
+ <item msgid="8014986104355098744">"No"</item>
+ <item msgid="5966994759929723339">"Sí"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 93cf9c4..2b42040 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Vuelve a intentar hacer la captura de pantalla"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"No se puede guardar la captura de pantalla"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"La aplicación o tu organización no permiten realizar capturas de pantalla"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Tu administrador de TI ha bloqueado las capturas de pantalla"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Editar"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Editar captura de pantalla"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"Compartir captura de pantalla"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Giro automático"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Girar pantalla automáticamente"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Ubicación"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Salvapantallas"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Acceso a cámara"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Acceso al micro"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Disponible"</string>
@@ -318,6 +320,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Desbloqueado con la cara. Pulsa para abrir."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Cara reconocida. Pulsa para abrir."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Cara reconocida. Pulsa el icono de desbloquear para abrir."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"Desliza el dedo hacia arriba para volverlo a intentar"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Desbloquea para usar el NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Este dispositivo pertenece a tu organización"</string>
@@ -344,9 +350,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"¿Quieres continuar con tu sesión?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Volver a empezar"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Sí, continuar"</string>
- <string name="guest_notification_app_name" msgid="2110425506754205509">"Modo Invitados"</string>
- <string name="guest_notification_session_active" msgid="5567273684713471450">"Estás en modo Invitados"</string>
- <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Si añades un usuario nuevo, saldrás del modo Invitados y se eliminarán todas las aplicaciones y datos de la sesión de invitado actual."</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"Modo Invitado"</string>
+ <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>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="other">Puedes añadir hasta <xliff:g id="COUNT">%d</xliff:g> usuarios.</item>
@@ -467,7 +473,7 @@
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"Configura un método de pago para comprar de forma más rápida y segura con tu teléfono"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"Mostrar todo"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"Añade una tarjeta"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"Toca para abrir"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"Actualizando"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Desbloquear para usar"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Se ha producido un problema al obtener tus tarjetas. Inténtalo de nuevo más tarde."</string>
@@ -693,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Alertas"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Batería"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Capturas de pantalla"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Mensajes generales"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"Almacenamiento"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Sugerencias"</string>
<string name="instant_apps" msgid="8337185853050247304">"Aplicaciones Instantáneas"</string>
@@ -727,6 +736,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"Activar cuando sea probable que se quede sin batería"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"No, gracias"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Volcar montículo de SysUI"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"En uso"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Hay aplicaciones que usan tu <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" y "</string>
@@ -804,7 +814,7 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Desliza el dedo para ver más"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Cargando recomendaciones"</string>
<string name="controls_media_title" msgid="1746947284862928133">"Multimedia"</string>
- <string name="controls_media_close_session" msgid="4780485355795635052">"¿Ocultar este control multimedia a <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="controls_media_close_session" msgid="4780485355795635052">"¿Ocultar este control multimedia para <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="controls_media_active_session" msgid="3146882316024153337">"La sesión multimedia no se puede ocultar."</string>
<string name="controls_media_dismiss_button" msgid="4485675693008031646">"Ocultar"</string>
<string name="controls_media_resume" msgid="1933520684481586053">"Reanudar"</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Acércate a <xliff:g id="DEVICENAME">%1$s</xliff:g> para que se reproduzca en ese dispositivo"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Acércate a <xliff:g id="DEVICENAME">%1$s</xliff:g> para jugar aquí"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Reproduciendo en <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Reproduciendo en este dispositivo"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Se ha producido un error. Inténtalo de nuevo."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inactivo, comprobar aplicación"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"No se ha encontrado"</string>
@@ -853,6 +862,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"Guardar"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"Iniciando…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"No se puede emitir"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"No se puede guardar. Inténtalo de nuevo."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"No se puede guardar."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Número de compilación"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Número de compilación copiado en el portapapeles."</string>
<string name="basic_status" msgid="2315371112182658176">"Conversación abierta"</string>
@@ -913,9 +924,9 @@
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Buscando redes…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"No se ha podido conectar a la red"</string>
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Por ahora no se conectará automáticamente a redes Wi-Fi"</string>
- <string name="see_all_networks" msgid="3773666844913168122">"Ver todo"</string>
+ <string name="see_all_networks" msgid="3773666844913168122">"Ver todas"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Para cambiar de red, desconecta el cable Ethernet"</string>
- <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Para mejorar la experiencia con el dispositivo, las aplicaciones y los servicios podrán buscar redes Wi-Fi en cualquier momento, aunque la conexión Wi-Fi esté desactivada. Puedes cambiar esto en los ajustes de búsqueda de redes Wi-Fi. "<annotation id="link">"Cambiar"</annotation></string>
+ <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Para mejorar la experiencia con el dispositivo, las aplicaciones y los servicios podrán buscar redes Wi-Fi en cualquier momento aunque la conexión Wi-Fi esté desactivada. Puedes cambiar esto en los ajustes de búsqueda de redes Wi-Fi. "<annotation id="link">"Cambiar"</annotation></string>
<string name="turn_off_airplane_mode" msgid="8425587763226548579">"Desactivar modo Avión"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> quiere añadir el siguiente recuadro a ajustes rápidos"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Añadir recuadro"</string>
@@ -937,6 +948,13 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Editar texto copiado"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Editar imagen copiada"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Enviar a dispositivo cercano"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"Toca para ver"</string>
+ <!-- no translation found for clipboard_text_copied (5100836834278976679) -->
+ <skip />
+ <!-- no translation found for clipboard_image_copied (3793365360174328722) -->
+ <skip />
+ <!-- no translation found for clipboard_content_copied (144452398567828145) -->
+ <skip />
<string name="add" msgid="81036585205287996">"Añadir"</string>
<string name="manage_users" msgid="1823875311934643849">"Gestionar usuarios"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"Esta notificación no se puede arrastrar a la pantalla dividida."</string>
@@ -945,4 +963,12 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarma añadida"</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>
+ <!-- no translation found for broadcasting_description_is_broadcasting (765627502786404290) -->
+ <skip />
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"¿Dejar de emitir <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Si emites <xliff:g id="SWITCHAPP">%1$s</xliff:g> o cambias la salida, tu emisión actual se detendrá"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Emitir <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Cambiar salida"</string>
+ <!-- no translation found for bt_le_audio_broadcast_dialog_unknown_name (3791472237793443044) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-es/tiles_states_strings.xml b/packages/SystemUI/res/values-es/tiles_states_strings.xml
index 7d728ac..e1082bf 100644
--- a/packages/SystemUI/res/values-es/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-es/tiles_states_strings.xml
@@ -58,8 +58,8 @@
</string-array>
<string-array name="tile_states_flashlight">
<item msgid="3465257127433353857">"No disponible"</item>
- <item msgid="5044688398303285224">"Desactivado"</item>
- <item msgid="8527389108867454098">"Activado"</item>
+ <item msgid="5044688398303285224">"Desactivada"</item>
+ <item msgid="8527389108867454098">"Activada"</item>
</string-array>
<string-array name="tile_states_rotation">
<item msgid="4578491772376121579">"No disponible"</item>
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Desactivado"</item>
<item msgid="460891964396502657">"Activado"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"No disponible"</item>
+ <item msgid="8014986104355098744">"Desactivado"</item>
+ <item msgid="5966994759929723339">"Activado"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index da5167d..e91ca64 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Proovige ekraanipilt uuesti jäädvustada"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"Ekraanipilti ei saa salvestada"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Rakendus või teie organisatsioon ei luba ekraanipilte jäädvustada"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"IT-administraator on ekraanipiltide jäädvustamise blokeerinud"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Muutmine"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Ekraanipildi muutmine"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"Jaga ekraanipilti"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Autom. pööramine"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Kuva automaatne pööramine"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Asukoht"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Ekraanisäästja"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Juurdepääs kaamerale"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Juurdepääs mikrofonile"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Saadaval"</string>
@@ -318,6 +320,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Avati näoga. Avamiseks vajutage."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Nägu tuvastati. Avamiseks vajutage."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Nägu tuvastati. Avamiseks vajutage avamise ikooni."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"Uuesti proovimiseks pühkige üles"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC kasutamiseks avage."</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"See seade kuulub teie organisatsioonile"</string>
@@ -467,7 +473,7 @@
<string name="wallet_title" msgid="5369767670735827105">"Rahakott"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"Seadistage kiirem ja turvalisem viis telefoniga ostmiseks"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"Kuva kõik"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"Lisage kaart"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"Puudutage avamiseks"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"Värskendamine"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Avage kasutamiseks"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Teie kaartide hankimisel ilmnes probleem, proovige hiljem uuesti"</string>
@@ -693,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Hoiatused"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Aku"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Ekraanipildid"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Üldised sõnumid"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"Salvestusruum"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Vihjed"</string>
<string name="instant_apps" msgid="8337185853050247304">"Installimata avatavad rakendused"</string>
@@ -727,6 +736,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"Lülitatakse sisse, kui aku hakkab tühjaks saama"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"Tänan, ei"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"Kasutusel"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Rakendused kasutavad järgmisi: <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" ja "</string>
@@ -804,7 +814,7 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Pühkige sõrmega, et näha rohkem"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Soovituste laadimine"</string>
<string name="controls_media_title" msgid="1746947284862928133">"Meedia"</string>
- <string name="controls_media_close_session" msgid="4780485355795635052">"Kas peita rakenduses <xliff:g id="APP_NAME">%1$s</xliff:g> see meedia juhtnupp?"</string>
+ <string name="controls_media_close_session" msgid="4780485355795635052">"Kas peita rakenduses <xliff:g id="APP_NAME">%1$s</xliff:g> see meediajuhik?"</string>
<string name="controls_media_active_session" msgid="3146882316024153337">"Praegust meediaseanssi ei saa peita."</string>
<string name="controls_media_dismiss_button" msgid="4485675693008031646">"Peida"</string>
<string name="controls_media_resume" msgid="1933520684481586053">"Jätka"</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Teisaldage lähemale, et seadmes <xliff:g id="DEVICENAME">%1$s</xliff:g> esitada"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Siin esitamiseks liigutage seadmele <xliff:g id="DEVICENAME">%1$s</xliff:g> lähemale"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Esitatakse seadmes <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Esitatakse selles telefonis"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Midagi läks valesti. Proovige uuesti."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Passiivne, vaadake rakendust"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Ei leitud"</string>
@@ -853,6 +862,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"Salvesta"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"Alustamine …"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"Ei saa üle kanda"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Ei saa salvestada. Proovige uuesti."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Ei saa salvestada."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Järgunumber"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Järgunumber kopeeriti lõikelauale."</string>
<string name="basic_status" msgid="2315371112182658176">"Avage vestlus"</string>
@@ -937,6 +948,13 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Muuda kopeeritud teksti"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Muuda kopeeritud pilti"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Saada läheduses olevasse seadmesse"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"Puudutage kuvamiseks"</string>
+ <!-- no translation found for clipboard_text_copied (5100836834278976679) -->
+ <skip />
+ <!-- no translation found for clipboard_image_copied (3793365360174328722) -->
+ <skip />
+ <!-- no translation found for clipboard_content_copied (144452398567828145) -->
+ <skip />
<string name="add" msgid="81036585205287996">"Lisa"</string>
<string name="manage_users" msgid="1823875311934643849">"Kasutajate haldamine"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"See märguanne ei toeta jagatud ekraanikuvale lohistamist."</string>
@@ -945,4 +963,12 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm on määratud"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kaamera ja mikrofon on välja lülitatud"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# märguanne}other{# märguannet}}"</string>
+ <!-- no translation found for broadcasting_description_is_broadcasting (765627502786404290) -->
+ <skip />
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Kas peatada rakenduse <xliff:g id="APP_NAME">%1$s</xliff:g> ülekandmine?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Kui kannate rakendust <xliff:g id="SWITCHAPP">%1$s</xliff:g> üle või muudate väljundit, peatatakse teie praegune ülekanne"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Rakenduse <xliff:g id="SWITCHAPP">%1$s</xliff:g> ülekandmine"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Väljundi muutmine"</string>
+ <!-- no translation found for bt_le_audio_broadcast_dialog_unknown_name (3791472237793443044) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-et/tiles_states_strings.xml b/packages/SystemUI/res/values-et/tiles_states_strings.xml
index 29895d1..07eddef 100644
--- a/packages/SystemUI/res/values-et/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-et/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Väljas"</item>
<item msgid="460891964396502657">"Sees"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Pole saadaval"</item>
+ <item msgid="8014986104355098744">"Väljas"</item>
+ <item msgid="5966994759929723339">"Sees"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 8fa1e08..986b557 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Saiatu berriro pantaila-argazkia ateratzen"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"Ezin da gorde pantaila-argazkia"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Aplikazioak edo erakundeak ez du onartzen pantaila-argazkiak ateratzea"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"IKT saileko administratzaileak blokeatu egin dizu pantaila-argazkiak ateratzeko aukera"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Editatu"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Editatu pantaila-argazkia"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"Partekatu pantaila-argazkia"</string>
@@ -92,7 +93,7 @@
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Pantaila-grabaketa prozesatzen"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Pantailaren grabaketa-saioaren jakinarazpen jarraitua"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"Grabatzen hasi nahi duzu?"</string>
- <string name="screenrecord_description" msgid="1123231719680353736">"Pantaila grabatzen duzun bitartean, baliteke Android sistemak pantailan agertzen den edo gailuak erreproduzitzen duen kontuzko informazioa detektatzea; besteak beste, pasahitzak, ordainketa-informazioa, argazkiak, mezuak eta audioa."</string>
+ <string name="screenrecord_description" msgid="1123231719680353736">"Pantaila grabatzen duzun bitartean, baliteke Android sistemak pantailan agertzen den edo gailuak erreproduzitzen duen kontuzko informazioa grabatzea; besteak beste, pasahitzak, ordainketa-informazioa, argazkiak, mezuak eta audioa."</string>
<string name="screenrecord_audio_label" msgid="6183558856175159629">"Grabatu audioa"</string>
<string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Gailuaren audioa"</string>
<string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Gailuko soinuak; adibidez, musika, deiak eta tonuak"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Biratze automatikoa"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Biratu pantaila automatikoki"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Kokapena"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Pantaila-babeslea"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Kamera"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Mikrofonoa"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Baimenduta"</string>
@@ -318,6 +320,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Aurpegiaren bidez desblokeatu da. Sakatu irekitzeko."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Ezagutu da aurpegia. Sakatu irekitzeko."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Ezagutu da aurpegia. Irekitzeko, sakatu desblokeatzeko ikonoa."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"Berriro saiatzeko, pasatu hatza gora"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Desblokea ezazu NFCa erabiltzeko"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Gailu hau zure erakundearena da"</string>
@@ -467,7 +473,7 @@
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"Konfiguratu erosketa bizkorrago eta seguruagoak egiteko telefonoarekin"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"Erakutsi guztiak"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"Gehitu txartel bat"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"Irekitzeko, sakatu hau"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"Eguneratzen"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Desblokeatu erabiltzeko"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Arazo bat izan da txartelak eskuratzean. Saiatu berriro geroago."</string>
@@ -693,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Alertak"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Bateria"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Pantaila-argazkiak"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Mezu orokorrak"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"Memoria"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Aholkuak"</string>
<string name="instant_apps" msgid="8337185853050247304">"Zuzeneko aplikazioak"</string>
@@ -727,6 +736,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"Aktibatu aurrezlea bateria agortzeko arriskua dagoenean"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"Ez, eskerrik asko"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"Erabiltzen ari da"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Aplikazio batzuk <xliff:g id="TYPES_LIST">%s</xliff:g> erabiltzen ari dira."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" eta "</string>
@@ -804,7 +814,7 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Pasatu hatza aukera gehiago ikusteko"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Gomendioak kargatzen"</string>
<string name="controls_media_title" msgid="1746947284862928133">"Multimedia-edukia"</string>
- <string name="controls_media_close_session" msgid="4780485355795635052">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioaren multimedia-edukiaren kontrolagailu hau ezkutatu?"</string>
+ <string name="controls_media_close_session" msgid="4780485355795635052">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioaren multimedia kontr. aukerak ezkutatu?"</string>
<string name="controls_media_active_session" msgid="3146882316024153337">"Ezin da ezkutatu multimedia-saioa."</string>
<string name="controls_media_dismiss_button" msgid="4485675693008031646">"Ezkutatu"</string>
<string name="controls_media_resume" msgid="1933520684481586053">"Berrekin"</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Gertura ezazu <xliff:g id="DEVICENAME">%1$s</xliff:g> gailuan erreproduzitzeko"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Gerturatu <xliff:g id="DEVICENAME">%1$s</xliff:g> gailura bertan erreproduzitzen ari dena hemen erreproduzitzeko"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> gailuan erreproduzitzen"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Telefono honetan erreproduzitzen"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Arazoren bat izan da. Saiatu berriro."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inaktibo; egiaztatu aplikazioa"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Ez da aurkitu"</string>
@@ -853,6 +862,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"Gorde"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"Abiarazten…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"Ezin da iragarri"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Ezin da gorde. Saiatu berriro."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Ezin da gorde."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Konpilazio-zenbakia"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Kopiatu da konpilazio-zenbakia arbelean."</string>
<string name="basic_status" msgid="2315371112182658176">"Elkarrizketa irekia"</string>
@@ -927,7 +938,7 @@
</plurals>
<string name="fgs_dot_content_description" msgid="2865071539464777240">"Informazio berria"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Aktibo dauden aplikazioak"</string>
- <string name="fgs_manager_dialog_message" msgid="6839542063522121108">"Aplikazio horiek erabiltzen ari ez bazara ere, aktibo daude eta bateria kontsumitzen jarraitzen dute"</string>
+ <string name="fgs_manager_dialog_message" msgid="6839542063522121108">"Aplikazio hauek erabiltzen ari ez bazara ere, aktibo daude eta bateria kontsumitzen jarraitzen dute"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Gelditu"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Geldituta"</string>
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Eginda"</string>
@@ -937,6 +948,13 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Editatu kopiatutako testua"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Editatu kopiatutako irudia"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Bidali inguruko gailu batera"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"Ikusteko, sakatu hau"</string>
+ <!-- no translation found for clipboard_text_copied (5100836834278976679) -->
+ <skip />
+ <!-- no translation found for clipboard_image_copied (3793365360174328722) -->
+ <skip />
+ <!-- no translation found for clipboard_content_copied (144452398567828145) -->
+ <skip />
<string name="add" msgid="81036585205287996">"Gehitu"</string>
<string name="manage_users" msgid="1823875311934643849">"Kudeatu erabiltzaileak"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"Jakinarazpen hau ezin da arrastatu pantaila zatitura."</string>
@@ -945,4 +963,12 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarma ezarrita dago"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera eta mikrofonoa desaktibatuta daude"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# jakinarazpen}other{# jakinarazpen}}"</string>
+ <!-- no translation found for broadcasting_description_is_broadcasting (765627502786404290) -->
+ <skip />
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioaren audioa igortzeari utzi nahi diozu?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> aplikazioaren audioa igortzen baduzu, edo audio-irteera aldatzen baduzu, une hartako igorpena eten egingo da"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Igorri <xliff:g id="SWITCHAPP">%1$s</xliff:g> aplikazioaren audioa"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Aldatu audio-irteera"</string>
+ <!-- no translation found for bt_le_audio_broadcast_dialog_unknown_name (3791472237793443044) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-eu/tiles_states_strings.xml b/packages/SystemUI/res/values-eu/tiles_states_strings.xml
index baddea1..3bf49c8 100644
--- a/packages/SystemUI/res/values-eu/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-eu/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Desaktibatuta"</item>
<item msgid="460891964396502657">"Aktibatuta"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Ez dago erabilgarri"</item>
+ <item msgid="8014986104355098744">"Desaktibatuta"</item>
+ <item msgid="5966994759929723339">"Aktibatuta"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 2e93708..60c9e7f 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -60,7 +60,7 @@
<string name="wifi_debugging_title" msgid="7300007687492186076">"اشکالزدایی بیسیم در این شبکه مجاز شود؟"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"نام شبکه (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nنشانی Wi‑Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"همیشه در این شبکه مجاز شود"</string>
- <string name="wifi_debugging_allow" msgid="4573224609684957886">"مجاز است"</string>
+ <string name="wifi_debugging_allow" msgid="4573224609684957886">"اجازه دادن"</string>
<string name="wifi_debugging_secondary_user_title" msgid="2493201475880517725">"اشکالزدایی بیسیم مجاز نیست"</string>
<string name="wifi_debugging_secondary_user_message" msgid="4492383073970079751">"کاربری که درحالحاضر در این دستگاه به سیستم وارد شده است نمیتواند اشکالزدایی بیسیم را روشن کند. برای استفاده از این ویژگی، به کاربر اصلی بروید."</string>
<string name="usb_contaminant_title" msgid="894052515034594113">"درگاه USB غیرفعال شده است"</string>
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"دوباره نماگرفت بگیرید"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"نماگرفت ذخیره نمیشود"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"برنامه یا سازمان شما اجازه نمیدهند نماگرفت بگیرید."</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"سرپرست سیستم گرفتن نماگرفت را مسدود کرده است"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"ویرایش"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"ویرایش نماگرفت"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"همرسانی نماگرفت"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"چرخش خودکار"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"چرخش خودکار صفحهنمایش"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"مکان"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"محافظ صفحه"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"دسترسی به دوربین"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"دسترسی به میکروفون"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"دردسترس"</string>
@@ -318,6 +320,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"قفلْ با چهره باز شد. برای باز کردن، فشار دهید."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"چهره شناسایی شد. برای باز کردن، فشار دهید."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"چهره شناسایی شد. برای باز کردن، نماد قفلگشایی را فشار دهید."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"برای امتحان مجدد، انگشتتان را تند بهبالا بکشید"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"برای استفاده از NFC، قفل را باز کنید"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"این دستگاه به سازمان شما تعلق دارد"</string>
@@ -422,7 +428,7 @@
<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>
- <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"به این ترتیب تا زمانی پین آن را برندارید قابلمشاهده است. برای برداشتن سنجاق، از پایین صفحه تند بهطرف بالا بکشید و نگه دارید."</string>
+ <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"به این ترتیب تا زمانی که پین آن را برندارید قابلمشاهده است. برای برداشتن سنجاق، از پایین صفحه تند بهطرف بالا بکشید و نگه دارید."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"تا زمانی که پین را بردارید، در نما نگهداشته میشود. برای برداشتن سنجاق، «نمای کلی» را لمس کنید و نگهدارید."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"تا برداشتن سنجاق، در نما نگهداشته میشود. برای برداشتن سنجاق، «صفحه اصلی» را لمس کنید و نگهدارید."</string>
<string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"ممکن است دادههای شخصی (مانند مخاطبین و محتوای ایمیل) در دسترس باشد."</string>
@@ -467,7 +473,7 @@
<string name="wallet_title" msgid="5369767670735827105">"کیفپول"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"برای خرید سریعتر و امنتر با تلفن، راهاندازی کنید"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"نمایش همه"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"افزودن کارت"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"برای باز کردن ضربه بزنید"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"درحال بهروزرسانی"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"برای استفاده، قفل را باز کنید"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"هنگام دریافت کارتها مشکلی پیش آمد، لطفاً بعداً دوباره امتحان کنید"</string>
@@ -693,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"هشدارها"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"باتری"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"نماگرفتها"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"پیامهای عمومی"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"فضای ذخیرهسازی"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"نکات"</string>
<string name="instant_apps" msgid="8337185853050247304">"برنامههای فوری"</string>
@@ -721,12 +730,13 @@
<string name="slice_permission_text_1" msgid="6675965177075443714">"- میتواند اطلاعات <xliff:g id="APP">%1$s</xliff:g> را بخواند"</string>
<string name="slice_permission_text_2" msgid="6758906940360746983">"- میتواند در <xliff:g id="APP">%1$s</xliff:g> اقدام انجام دهد"</string>
<string name="slice_permission_checkbox" msgid="4242888137592298523">"به <xliff:g id="APP">%1$s</xliff:g> اجازه داده شود تکههایی از برنامهها نشان دهد"</string>
- <string name="slice_permission_allow" msgid="6340449521277951123">"مجاز"</string>
+ <string name="slice_permission_allow" msgid="6340449521277951123">"اجازه دادن"</string>
<string name="slice_permission_deny" msgid="6870256451658176895">"مجاز نبودن"</string>
<string name="auto_saver_title" msgid="6873691178754086596">"برای زمانبندی «بهینهسازی باتری» ضربه بزنید"</string>
<string name="auto_saver_text" msgid="3214960308353838764">"وقتی باتری روبهاتمام است، بهینهسازی باتری را روشن کنید"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"نه متشکرم"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"استفاده شده"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"برنامهها از <xliff:g id="TYPES_LIST">%s</xliff:g> شما استفاده میکنند."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">"، "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" و "</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"برای پخش در <xliff:g id="DEVICENAME">%1$s</xliff:g> به دستگاه نزدیکتر شوید"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"برای پخش در اینجا، به <xliff:g id="DEVICENAME">%1$s</xliff:g> نزدیکتر شوید"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"درحال پخش در <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"درحال پخش در این تلفن"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"مشکلی پیش آمد. دوباره امتحان کنید."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"غیرفعال، برنامه را بررسی کنید"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"پیدا نشد"</string>
@@ -853,6 +862,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"ذخیره کردن"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"درحال شروع…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"همهفرستی انجام نشد"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"ذخیره نشد. دوباره امتحان کنید."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"ذخیره نشد."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"شماره ساخت"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"شماره ساخت در بریدهدان کپی شد."</string>
<string name="basic_status" msgid="2315371112182658176">"باز کردن مکالمه"</string>
@@ -937,6 +948,10 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"ویرایش نوشتار کپیشده"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"ویرایش تصویر کپیشده"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"ارسال به دستگاهی در اطراف"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"برای مشاهده، ضربه بزنید"</string>
+ <string name="clipboard_text_copied" msgid="5100836834278976679">"نوشتار کپی شد"</string>
+ <string name="clipboard_image_copied" msgid="3793365360174328722">"تصویر کپی شد"</string>
+ <string name="clipboard_content_copied" msgid="144452398567828145">"محتوا کپی شد"</string>
<string name="add" msgid="81036585205287996">"افزودن"</string>
<string name="manage_users" msgid="1823875311934643849">"مدیریت کاربران"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"این اعلان از تنظیم کشیدن برای دو نیمه کردن صفحه پشتیبانی نمیکند."</string>
@@ -945,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"زنگ ساعت تنظیم شد"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"دوربین و میکروفون خاموش هستند"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# اعلان}one{# اعلان}other{# اعلان}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"همهفرستی"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"همهفرستی <xliff:g id="APP_NAME">%1$s</xliff:g> متوقف شود؟"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"اگر <xliff:g id="SWITCHAPP">%1$s</xliff:g> را همهفرستی کنید یا خروجی را تغییر دهید، همهفرستی کنونی متوقف خواهد شد"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"همهفرستی <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"تغییر خروجی"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"نامشخص"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fa/tiles_states_strings.xml b/packages/SystemUI/res/values-fa/tiles_states_strings.xml
index ecc8d1cc..85f0bfd 100644
--- a/packages/SystemUI/res/values-fa/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-fa/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"خاموش"</item>
<item msgid="460891964396502657">"روشن"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"دردسترس نیست"</item>
+ <item msgid="8014986104355098744">"خاموش"</item>
+ <item msgid="5966994759929723339">"روشن"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 629becb..9588a69 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Yritä ottaa kuvakaappaus uudelleen."</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"Kuvakaappausta ei voi tallentaa"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Sovellus tai organisaatio ei salli kuvakaappauksien tallentamista."</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"IT-järjestelmänvalvoja on estänyt kuvakaappauksien ottamisen."</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Muuta"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Muokkaa kuvakaappausta"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"Jaa kuvakaappaus"</string>
@@ -92,9 +93,9 @@
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Näytön tallennusta käsitellään"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Pysyvä ilmoitus näytön tallentamisesta"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"Aloitetaanko tallennus?"</string>
- <string name="screenrecord_description" msgid="1123231719680353736">"Tallennuksen aikana Android-järjestelmä voi tallentaa mitä tahansa näytöllä näkyvää tai laitteen toistamaa arkaluontoista tietoa. Näitä tietoja ovat esimerkiksi salasanat, maksutiedot, kuvat, viestit ja äänisisältö."</string>
- <string name="screenrecord_audio_label" msgid="6183558856175159629">"Tallenna ääntä"</string>
- <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Laitteen äänet"</string>
+ <string name="screenrecord_description" msgid="1123231719680353736">"Tallennuksen aikana Android-järjestelmä voi tallentaa mitä tahansa näytöllä näkyvää tai laitteen toistamaa arkaluontoista tietoa. Näitä tietoja ovat esimerkiksi salasanat, maksutiedot, kuvat, viestit ja audio."</string>
+ <string name="screenrecord_audio_label" msgid="6183558856175159629">"Tallenna audiota"</string>
+ <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Laitteen audio"</string>
<string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Musiikki, puhelut, soittoäänet ja muut äänet laitteesta"</string>
<string name="screenrecord_mic_label" msgid="2111264835791332350">"Mikrofoni"</string>
<string name="screenrecord_device_audio_and_mic_label" msgid="1831323771978646841">"Laitteen äänet ja mikrofoni"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automaattinen kääntö"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Käännä näyttöä automaattisesti."</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Sijainti"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Näytönsäästäjä"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Pääsy kameraan"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Pääsy mikrofoniin"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Käytettävissä"</string>
@@ -318,6 +320,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Avattu kasvojen avulla. Avaa painamalla."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Kasvot tunnistettu. Avaa painamalla."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Kasvot tunnistettu. Jatka lukituksen avauskuvakkeella."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"Yritä uudelleen pyyhkäisemällä ylös"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Avaa lukitus, jotta voit käyttää NFC:tä"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Organisaatiosi omistaa tämän laitteen"</string>
@@ -467,7 +473,7 @@
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"Lisää maksutapa, niin voit maksaa nopeasti ja turvallisesti puhelimella"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"Näytä kaikki"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"Lisää kortti"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"Avaa napauttamalla"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"Päivitetään"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Avaa lukitus ja käytä"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Korttien noutamisessa oli ongelma, yritä myöhemmin uudelleen"</string>
@@ -693,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Ilmoitukset"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Akku"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Kuvakaappaukset"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Yleiset viestit"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"Tallennustila"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Vihjeet"</string>
<string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string>
@@ -727,6 +736,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"Ota käyttöön, jos akku todennäköisesti loppuu"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"Ei kiitos"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Luo SysUI-keon vedos"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"Käytössä"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"<xliff:g id="TYPES_LIST">%s</xliff:g> ovat sovellusten käytössä."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" ja "</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Siirry lähemmäs, jotta <xliff:g id="DEVICENAME">%1$s</xliff:g> voi toistaa tämän"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Siirrä <xliff:g id="DEVICENAME">%1$s</xliff:g> lähemmäs toistaaksesi täällä"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Toistetaan: <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Toistetaan tällä puhelimella"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Jotain meni pieleen. Yritä uudelleen."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Epäaktiivinen, tarkista sovellus"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Ei löydy"</string>
@@ -853,6 +862,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"Tallenna"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"Aloitetaan…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"Ei voi lähettää"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Tallennus ei onnistu. Yritä uudelleen."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Tallennus ei onnistu."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Koontiversion numero"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Koontiversion numero kopioitu leikepöydälle"</string>
<string name="basic_status" msgid="2315371112182658176">"Avaa keskustelu"</string>
@@ -928,7 +939,7 @@
<string name="fgs_dot_content_description" msgid="2865071539464777240">"Uutta tietoa"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Aktiiviset sovellukset"</string>
<string name="fgs_manager_dialog_message" msgid="6839542063522121108">"Vaikka et käyttäisikään näitä sovelluksia, ne ovat silti aktiivisia ja saattavat vaikuttaa akunkestoon."</string>
- <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Lopeta"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Pysäytä"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Pysäytetty"</string>
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Valmis"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Kopioitu"</string>
@@ -937,6 +948,13 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Muokkaa kopioitua tekstiä"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Muokkaa kopioitua kuvaa"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Lähetä lähellä olevaan laitteeseen"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"Katso napauttamalla"</string>
+ <!-- no translation found for clipboard_text_copied (5100836834278976679) -->
+ <skip />
+ <!-- no translation found for clipboard_image_copied (3793365360174328722) -->
+ <skip />
+ <!-- no translation found for clipboard_content_copied (144452398567828145) -->
+ <skip />
<string name="add" msgid="81036585205287996">"Lisää"</string>
<string name="manage_users" msgid="1823875311934643849">"Ylläpidä käyttäjiä"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"Ilmoitus ei tue jaetulle näytölle vetämistä."</string>
@@ -945,4 +963,12 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Hälytys asetettu"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera ja mikrofoni ovat pois päältä"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# ilmoitus}other{# ilmoitusta}}"</string>
+ <!-- no translation found for broadcasting_description_is_broadcasting (765627502786404290) -->
+ <skip />
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Lopetetaanko <xliff:g id="APP_NAME">%1$s</xliff:g>-sovelluksen lähettäminen?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Jos lähetät <xliff:g id="SWITCHAPP">%1$s</xliff:g>-sovellusta tai muutat ulostuloa, nykyinen lähetyksesi loppuu"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Lähetä <xliff:g id="SWITCHAPP">%1$s</xliff:g>-sovellusta"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Muuta ulostuloa"</string>
+ <!-- no translation found for bt_le_audio_broadcast_dialog_unknown_name (3791472237793443044) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-fi/tiles_states_strings.xml b/packages/SystemUI/res/values-fi/tiles_states_strings.xml
index 5844fb9..1505dc5 100644
--- a/packages/SystemUI/res/values-fi/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-fi/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Poissa päältä"</item>
<item msgid="460891964396502657">"Päällä"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Ei saatavilla"</item>
+ <item msgid="8014986104355098744">"Poissa päältä"</item>
+ <item msgid="5966994759929723339">"Päällä"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 05e947d..6674aca 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Essayez de faire une autre capture d\'écran"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"Impossible d\'enregistrer la capture d\'écran"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"L\'application ou votre organisation n\'autorise pas les saisies d\'écran"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"La prise de captures d\'écran est bloquée par votre administrateur informatique"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Modifier"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Modifier la capture d\'écran"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"Partagez la capture d\'écran"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Rotation automatique"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Rotation automatique de l\'écran"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Localisation"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Écran de veille"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Accès à l\'appareil photo"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Accès au micro"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Accessible"</string>
@@ -318,6 +320,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Déverrouillé avec le visage. Appuyez pour ouvrir."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Visage reconnu. Appuyez pour ouvrir."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Visage reconnu. Appuyez sur Déverrouiller pour ouvrir."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"Balayez l\'écran vers le haut pour réessayer"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Déverrouillez l\'écran pour utiliser la CCP"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Cet appareil appartient à votre organisation"</string>
@@ -346,7 +352,7 @@
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Oui, continuer"</string>
<string name="guest_notification_app_name" msgid="2110425506754205509">"Mode Invité"</string>
<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"L\'ajout d\'un nouvel utilisateur aura pour effet de quitter le mode Invité ainsi que de supprimer toutes les applications et données de la session d\'invité en cours."</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>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="one">Vous pouvez ajouter jusqu\'à <xliff:g id="COUNT">%d</xliff:g> utilisateur.</item>
@@ -467,7 +473,7 @@
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"Préparez-vous à faire des achats plus rapidement et de façon plus sûre avec votre téléphone"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"Tout afficher"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"Ajouter une carte"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"Touchez pour ouvrir"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"Mise à jour en cours…"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Déverrouiller pour utiliser"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Un problème est survenu lors de la récupération de vos cartes, veuillez réessayer plus tard"</string>
@@ -693,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Alertes"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Pile"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Saisies d\'écran"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Messages généraux"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"Stockage"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Conseils"</string>
<string name="instant_apps" msgid="8337185853050247304">"Applications instantanées"</string>
@@ -727,6 +736,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"Activer si la pile est susceptible de s\'épuiser totalement"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"Non merci"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Copier mémoire SysUI"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"En cours d\'utilisation"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Des applications utilisent votre <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" et "</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Rapprochez-vous pour faire jouer le contenu sur <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Rapprochez-vous de <xliff:g id="DEVICENAME">%1$s</xliff:g> pour lire le contenu"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Lecture sur <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Lecture sur ce téléphone"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Un problème est survenu. Réessayez."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Délai expiré, vérifiez l\'appli"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Introuvable"</string>
@@ -853,6 +862,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"Enregistrer"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"Démarrage en cours…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"Impossible de diffuser"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Impossible d\'enregistrer. Réessayez."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Impossible d\'enregistrer."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Numéro de version"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Le numéro de version a été copié dans le presse-papiers."</string>
<string name="basic_status" msgid="2315371112182658176">"Ouvrir la conversation"</string>
@@ -937,6 +948,13 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Modifier le texte copié"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Modifier l\'image copiée"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Envoyer à un appareil à proximité"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"Touchez pour afficher"</string>
+ <!-- no translation found for clipboard_text_copied (5100836834278976679) -->
+ <skip />
+ <!-- no translation found for clipboard_image_copied (3793365360174328722) -->
+ <skip />
+ <!-- no translation found for clipboard_content_copied (144452398567828145) -->
+ <skip />
<string name="add" msgid="81036585205287996">"Ajouter"</string>
<string name="manage_users" msgid="1823875311934643849">"Gérer les utilisateurs"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"Cette notification ne prend pas en charge le partage d\'écran par glissement."</string>
@@ -945,4 +963,12 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"L\'alarme a été réglée"</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>
+ <!-- no translation found for broadcasting_description_is_broadcasting (765627502786404290) -->
+ <skip />
+ <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>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Si vous diffusez <xliff:g id="SWITCHAPP">%1$s</xliff:g> ou changez la sortie, votre diffusion actuelle s\'arrêtera"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Diffuser <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Changer la sortie"</string>
+ <!-- no translation found for bt_le_audio_broadcast_dialog_unknown_name (3791472237793443044) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/tiles_states_strings.xml b/packages/SystemUI/res/values-fr-rCA/tiles_states_strings.xml
index 9d78e91..4ec0084 100644
--- a/packages/SystemUI/res/values-fr-rCA/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Désactivé"</item>
<item msgid="460891964396502657">"Activé"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Non accessible"</item>
+ <item msgid="8014986104355098744">"Désactivé"</item>
+ <item msgid="5966994759929723339">"Activé"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index d071d51..aa7bd4c 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Essayez de nouveau de faire une capture d\'écran"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"Impossible d\'enregistrer la capture d\'écran"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Les captures d\'écran ne sont pas autorisées par l\'application ni par votre organisation"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"La prise de captures d\'écran est bloquée par votre administrateur informatique"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Modifier"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Modifier la capture d\'écran"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"Partager la capture d\'écran"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Rotation automatique"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Rotation automatique de l\'écran"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Localisation"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Économiseur d\'écran"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Accès à l\'appareil photo"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Accès au micro"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Disponible"</string>
@@ -318,6 +320,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Déverrouillé par visage. Appuyez pour ouvrir."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Visage reconnu. Appuyez pour ouvrir."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Visage reconnu. Appuyez sur l\'icône de déverrouillage pour ouvrir."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"Balayez l\'écran vers le haut pour réessayer"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Déverrouillez l\'écran pour pouvoir utiliser la NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Cet appareil appartient à votre organisation"</string>
@@ -467,7 +473,7 @@
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"Configurez un mode de paiement pour régler vos achats de façon sûre et rapide via votre téléphone"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"Tout afficher"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"Ajouter une carte"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"Appuyer pour ouvrir"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"Mise à jour…"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Déverrouiller pour utiliser"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Problème de récupération de vos cartes. Réessayez plus tard"</string>
@@ -693,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Alertes"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Batterie"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Captures d\'écran"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Nouveaux messages"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"Espace de stockage"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Astuces"</string>
<string name="instant_apps" msgid="8337185853050247304">"Applis instantanées"</string>
@@ -727,6 +736,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"Activer l\'économiseur de batterie si l\'autonomie restante risque d\'être insuffisante"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"Non, merci"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Copier mémoire SysUI"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"En cours d\'utilisation"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Des applications utilisent votre <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" et "</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Rapprochez-vous pour lire sur <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Rapprochez l\'appareil pour transférer la diffusion à votre <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Lecture sur <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Lire sur ce téléphone"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Un problème est survenu. Réessayez."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Délai expiré, vérifier l\'appli"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Introuvable"</string>
@@ -853,6 +862,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"Enregistrer"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"Démarrage…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"Impossible de diffuser"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Impossible d\'enregistrer. Réessayez."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Impossible d\'enregistrer."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Numéro de build"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Numéro de build copié dans le presse-papiers."</string>
<string name="basic_status" msgid="2315371112182658176">"Conversation ouverte"</string>
@@ -919,7 +930,7 @@
<string name="turn_off_airplane_mode" msgid="8425587763226548579">"Désactiver le mode Avion"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> veut ajouter le bloc suivant aux Réglages rapides"</string>
<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 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>
<plurals name="fgs_manager_footer_label" formatted="false" msgid="790443735462280164">
<item quantity="one"><xliff:g id="COUNT_1">%s</xliff:g> appli est active</item>
@@ -937,6 +948,13 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Modifier le texte copié"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Modifier l\'image copiée"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Envoyer à un appareil à proximité"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"Appuyez pour afficher"</string>
+ <!-- no translation found for clipboard_text_copied (5100836834278976679) -->
+ <skip />
+ <!-- no translation found for clipboard_image_copied (3793365360174328722) -->
+ <skip />
+ <!-- no translation found for clipboard_content_copied (144452398567828145) -->
+ <skip />
<string name="add" msgid="81036585205287996">"Ajouter"</string>
<string name="manage_users" msgid="1823875311934643849">"Gérer les utilisateurs"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"Impossible de faire glisser cette notification vers l\'écran partagé."</string>
@@ -945,4 +963,12 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarme réglée"</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>
+ <!-- no translation found for broadcasting_description_is_broadcasting (765627502786404290) -->
+ <skip />
+ <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>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Si vous diffusez <xliff:g id="SWITCHAPP">%1$s</xliff:g> ou que vous modifiez le résultat, votre annonce actuelle s\'arrêtera"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Diffuser <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Modifier le résultat"</string>
+ <!-- no translation found for bt_le_audio_broadcast_dialog_unknown_name (3791472237793443044) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-fr/tiles_states_strings.xml b/packages/SystemUI/res/values-fr/tiles_states_strings.xml
index 47fa9c5..8c6c4f5 100644
--- a/packages/SystemUI/res/values-fr/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-fr/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Désactivé"</item>
<item msgid="460891964396502657">"Activé"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Indisponible"</item>
+ <item msgid="8014986104355098744">"Désactivé"</item>
+ <item msgid="5966994759929723339">"Activé"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 9f5c817..72fb5c4 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Volve tentar crear unha captura de pantalla"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"Non se puido gardar a captura de pantalla"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"A aplicación ou a túa organización non permite realizar capturas de pantalla"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"O teu administrador de TI bloqueou a opción de facer capturas de pantalla"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Editar"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Editar a captura de pantalla"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"Compartir captura de pantalla"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Xirar automaticamente"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Xirar pantalla automaticamente"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Localización"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Protector de pantalla"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Acceso á cámara"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Acceso ao micrófono"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Dispoñible"</string>
@@ -318,6 +320,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Usouse o desbloqueo facial. Preme para abrir."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Recoñeceuse a cara. Preme para abrir."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Recoñeceuse a cara. Preme a icona de desbloquear para abrir."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"Pasa o dedo cara arriba para tentalo de novo"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Desbloquea o dispositivo para utilizar a NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Este dispositivo pertence á túa organización."</string>
@@ -467,7 +473,7 @@
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"Configura un método de pago para comprar de xeito máis rápido e seguro co teléfono"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"Amosar todo"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"Engadir tarxeta"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"Tocar para abrir"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"Actualizando"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Desbloquear para usar"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Produciuse un problema ao obter as tarxetas. Téntao de novo máis tarde"</string>
@@ -527,7 +533,7 @@
<string name="feedback_prompt" msgid="3656728972307896379">"Faille saber a túa opinión ao programador. A información era correcta?"</string>
<string name="notification_channel_controls_opened_accessibility" msgid="6111817750774381094">"Abríronse os controis de notificacións da aplicación <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="notification_channel_controls_closed_accessibility" msgid="1561909368876911701">"Pecháronse os controis de notificacións da aplicación <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
- <string name="notification_more_settings" msgid="4936228656989201793">"Máis opcións"</string>
+ <string name="notification_more_settings" msgid="4936228656989201793">"Máis opcións de configuración"</string>
<string name="notification_app_settings" msgid="8963648463858039377">"Personalizar"</string>
<string name="notification_conversation_bubble" msgid="2242180995373949022">"Mostrar burbulla"</string>
<string name="notification_conversation_unbubble" msgid="6908427185031099868">"Quitar burbullas"</string>
@@ -693,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Alertas"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Batería"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Capturas de pantalla"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Mensaxes xerais"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"Almacenamento"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Consellos"</string>
<string name="instant_apps" msgid="8337185853050247304">"Aplicacións Instantáneas"</string>
@@ -727,6 +736,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"Activa a función se prevés que a batería pode esgotarse"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"Non, grazas"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Baleirado mem. SysUI"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"En uso"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Hai aplicacións que están utilizando <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" e "</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Achega o dispositivo para reproducir o contido en: <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Achégate ao dispositivo (<xliff:g id="DEVICENAME">%1$s</xliff:g>) para reproducir o contido neste"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Reproducindo contido noutro dispositivo (<xliff:g id="DEVICENAME">%1$s</xliff:g>)"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Reproducindo contido neste teléfono"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Produciuse un erro. Téntao de novo."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inactivo. Comproba a app"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Non se atopou"</string>
@@ -853,6 +862,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"Gardar"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"Iniciando…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"Non se puido iniciar a emisión"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Non se puido gardar a información. Téntao de novo."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Non se pode gardar a información."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Número de compilación"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Copiouse o número de compilación no portapapeis."</string>
<string name="basic_status" msgid="2315371112182658176">"Conversa aberta"</string>
@@ -937,6 +948,13 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Editar texto copiado"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Editar imaxe copiada"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Enviar a dispositivo próximo"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"Toca para ver o contido"</string>
+ <!-- no translation found for clipboard_text_copied (5100836834278976679) -->
+ <skip />
+ <!-- no translation found for clipboard_image_copied (3793365360174328722) -->
+ <skip />
+ <!-- no translation found for clipboard_content_copied (144452398567828145) -->
+ <skip />
<string name="add" msgid="81036585205287996">"Engadir"</string>
<string name="manage_users" msgid="1823875311934643849">"Xestionar usuarios"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"Esta notificación non pode arrastrarse á pantalla dividida."</string>
@@ -945,4 +963,12 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarma definida"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"A cámara e o micrófono están desactivados"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notificación}other{# notificacións}}"</string>
+ <!-- no translation found for broadcasting_description_is_broadcasting (765627502786404290) -->
+ <skip />
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Queres deixar de emitir contido a través de <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Se emites contido a través de <xliff:g id="SWITCHAPP">%1$s</xliff:g> ou cambias de saída, a emisión en curso deterase"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Emitir contido a través de <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Cambiar de saída"</string>
+ <!-- no translation found for bt_le_audio_broadcast_dialog_unknown_name (3791472237793443044) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-gl/tiles_states_strings.xml b/packages/SystemUI/res/values-gl/tiles_states_strings.xml
index 229836c..590ec4a 100644
--- a/packages/SystemUI/res/values-gl/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-gl/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Desactivado"</item>
<item msgid="460891964396502657">"Activado"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Non dispoñible"</item>
+ <item msgid="8014986104355098744">"Desactivado"</item>
+ <item msgid="5966994759929723339">"Activado"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index e33eb35..2c57824 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"ફરીથી સ્ક્રીનશૉટ લેવાનો પ્રયાસ કરો"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"સ્ક્રીનશૉટ સાચવી શકાતો નથી"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"ઍપ્લિકેશન કે તમારી સંસ્થા દ્વારા સ્ક્રીનશૉટ લેવાની મંજૂરી નથી"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"તમારા IT ઍડમિન દ્વારા સ્ક્રીનશૉટ લેવાની સુવિધા બ્લૉક કરવામાં આવી છે"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"ફેરફાર કરો"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"સ્ક્રીનશૉટમાં ફેરફાર કરો"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"સ્ક્રીનશૉટ શેર કરો"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"ઑટો રોટેટ"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"ઑટો રોટેટ સ્ક્રીન"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"સ્થાન"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"સ્ક્રીન સેવર"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"કૅમેરાનો ઍક્સેસ"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"માઇકનો ઍક્સેસ"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"ઉપલબ્ધ છે"</string>
@@ -318,6 +320,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"ચહેરા દ્વારા અનલૉક કર્યું. ખોલવા માટે દબાવો."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"ચહેરો ઓળખ્યો. ખોલવા માટે દબાવો."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"ચહેરો ઓળખ્યો. ખોલવા માટે \'અનલૉક કરો\' આઇકન દબાવો."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"ફરી પ્રયાસ કરવા માટે ઉપરની તરફ સ્વાઇપ કરો"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFCનો ઉપયોગ કરવા માટે અનલૉક કરો"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"આ ડિવાઇસ તમારી સંસ્થાની માલિકીનું છે"</string>
@@ -467,7 +473,7 @@
<string name="wallet_title" msgid="5369767670735827105">"વૉલેટ"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"તમારા ફોન વડે વધુ ઝડપી તેમજ સુરક્ષિત ખરીદીઓ કરવાની રીત સેટઅપ કરી લો"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"બધું બતાવો"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"કોઈ કાર્ડ ઉમેરો"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"ખોલવા માટે ટૅપ કરો"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"અપડેટ કરી રહ્યાં છીએ"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ઉપયોગ કરવા માટે અનલૉક કરો"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"તમારા કાર્ડની માહિતી મેળવવામાં સમસ્યા આવી હતી, કૃપા કરીને થોડા સમય પછી ફરી પ્રયાસ કરો"</string>
@@ -693,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"અલર્ટ"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"બૅટરી"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"સ્ક્રીનશૉટ"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"સામાન્ય સંદેશા"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"સ્ટોરેજ"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"હિન્ટ"</string>
<string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string>
@@ -727,6 +736,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"જ્યારે બૅટરી સંભવિત રૂપે પૂરી થવામાં હોય ત્યારે બૅટરી સેવર ચાલુ કરો"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"ના, આભાર"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"ઉપયોગમાં છે"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"ઍપ્લિકેશન તમારા <xliff:g id="TYPES_LIST">%s</xliff:g>નો ઉપયોગ કરી રહી છે."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" અને "</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g> પર ચલાવવા માટે વધુ નજીક ખસેડો"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"આમાં ચલાવવા માટે ડિવાઇસને <xliff:g id="DEVICENAME">%1$s</xliff:g>ની નજીક ખસેડો"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> પર ચલાવવામાં આવી રહ્યું છે"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"આ ફોન પર ચલાવવામાં આવી રહ્યું છે"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"કંઈક ખોટું થયું. ફરી પ્રયાસ કરો."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"નિષ્ક્રિય, ઍપને ચેક કરો"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"મળ્યું નથી"</string>
@@ -853,6 +862,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"સાચવો"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"શરૂ થઈ રહ્યું છે…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"બ્રોડકાસ્ટ કરી શકતા નથી"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"સાચવી શકતા નથી. ફરી પ્રયાસ કરો."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"સાચવી શકતા નથી."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"બિલ્ડ નંબર"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"બિલ્ડ નંબર ક્લિપબૉર્ડ પર કૉપિ કર્યો."</string>
<string name="basic_status" msgid="2315371112182658176">"વાતચીત ખોલો"</string>
@@ -937,6 +948,13 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"કૉપિ કરેલી ટેક્સ્ટમાં ફેરફાર કરો"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"કૉપિ કરેલી છબીમાં ફેરફાર કરો"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"નજીકના ડિવાઇસને મોકલો"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"જોવા માટે ટૅપ કરો"</string>
+ <!-- no translation found for clipboard_text_copied (5100836834278976679) -->
+ <skip />
+ <!-- no translation found for clipboard_image_copied (3793365360174328722) -->
+ <skip />
+ <!-- no translation found for clipboard_content_copied (144452398567828145) -->
+ <skip />
<string name="add" msgid="81036585205287996">"ઉમેરો"</string>
<string name="manage_users" msgid="1823875311934643849">"વપરાશકર્તાઓને મેનેજ કરો"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"આ નોટિફિકેશન તેને સ્પ્લિટસ્ક્રીનમાં ખેંચવાની સુવિધાને સપોર્ટ કરતું નથી."</string>
@@ -945,4 +963,12 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"અલાર્મ સેટ"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"કૅમેરા અને માઇક બંધ છે"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# નોટિફિકેશન}one{# નોટિફિકેશન}other{# નોટિફિકેશન}}"</string>
+ <!-- no translation found for broadcasting_description_is_broadcasting (765627502786404290) -->
+ <skip />
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> બ્રોડકાસ્ટ કરવાનું રોકીએ?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"જો તમે <xliff:g id="SWITCHAPP">%1$s</xliff:g> બ્રોડકાસ્ટ કરો અથવા આઉટપુટ બદલો, તો તમારું હાલનું બ્રોડકાસ્ટ બંધ થઈ જશે"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> બ્રોડકાસ્ટ કરો"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"આઉટપુટ બદલો"</string>
+ <!-- no translation found for bt_le_audio_broadcast_dialog_unknown_name (3791472237793443044) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-gu/tiles_states_strings.xml b/packages/SystemUI/res/values-gu/tiles_states_strings.xml
index c502ba3..73b3720 100644
--- a/packages/SystemUI/res/values-gu/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-gu/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"બંધ છે"</item>
<item msgid="460891964396502657">"ચાલુ છે"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"અનુપલબ્ધ"</item>
+ <item msgid="8014986104355098744">"બંધ છે"</item>
+ <item msgid="5966994759929723339">"ચાલુ છે"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 45e1c5e..ae3c2d5 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"स्क्रीनशॉट दोबारा लेने की कोशिश करें"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"स्क्रीनशॉट को सेव नहीं किया जा सकता"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"ऐप्लिकेशन या आपका संगठन स्क्रीनशॉट लेने की अनुमति नहीं देता"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"आईटी एडमिन ने स्क्रीनशॉट लेने पर रोक लगाई है"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"बदलाव करें"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"स्क्रीनशॉट में बदलाव करें"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"स्क्रीनशॉट शेयर करें"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"ऑटो-रोटेट"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"स्क्रीन का अपने-आप दिशा बदलना (ऑटो-रोटेट)"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"जगह"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"स्क्रीन सेवर"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"कैमरे का ऐक्सेस"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"माइक्रोफ़ोन का ऐक्सेस"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"उपलब्ध"</string>
@@ -318,6 +320,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"चेहरे से अनलॉक किया गया. डिवाइस खोलने के लिए टैप करें."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"चेहरे की पहचान हो गई. डिवाइस खोलने के लिए टैप करें."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"चेहरे की पहचान हो गई. डिवाइस खोलने के लिए अनलॉक आइकॉन को टैप करें."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"फिर से कोशिश करने के लिए ऊपर की ओर स्वाइप करें"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"एनएफ़सी इस्तेमाल करने के लिए स्क्रीन को अनलॉक करें"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"इस डिवाइस का मालिकाना हक आपके संगठन के पास है"</string>
@@ -467,7 +473,7 @@
<string name="wallet_title" msgid="5369767670735827105">"वॉलेट"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"फ़ोन के ज़रिए तेज़ी से और सुरक्षित तरीके से खरीदारी करने के लिए सेट अप करें"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"सभी दिखाएं"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"कार्ड जोड़ें"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"अनलॉक करने के लिए टैप करें"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"अपडेट हो रहा है"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"इस्तेमाल करने के लिए, डिवाइस अनलॉक करें"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"आपके कार्ड की जानकारी पाने में कोई समस्या हुई है. कृपया बाद में कोशिश करें"</string>
@@ -693,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"सूचनाएं"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"बैटरी"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"स्क्रीनशॉट"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"सामान्य संदेश"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"स्टोरेज"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"संकेत"</string>
<string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string>
@@ -727,6 +736,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"जब बैटरी खत्म होने वाली हो तब \'बैटरी सेवर\' चालू करें"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"जी नहीं, शुक्रिया"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"इस्तेमाल किया जा रहा है"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"ऐप्लिकेशन आपकी <xliff:g id="TYPES_LIST">%s</xliff:g> का इस्तेमाल कर रहे हैं."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" और "</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g> पर मीडिया चलाने के लिए, अपने डिवाइस को उसके पास ले जाएं"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"अपने डिवाइस पर मीडिया फ़ाइल ट्रांसफ़र करने के लिए, उसे <xliff:g id="DEVICENAME">%1$s</xliff:g> के पास ले जाएं"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> पर मीडिया चल रहा है"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"इस फ़ोन पर मीडिया चल रहा है"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"कोई गड़बड़ी हुई. फिर से कोशिश करें."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"काम नहीं कर रहा, ऐप जांचें"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"कंट्रोल नहीं है"</string>
@@ -853,6 +862,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"सेव करें"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"शुरू हो रहा है…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"ब्रॉडकास्ट नहीं किया जा सकता"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"सेव नहीं किया जा सका. फिर से कोशिश करें."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"सेव नहीं किया जा सका."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"बिल्ड नंबर"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"बिल्ड नंबर को क्लिपबोर्ड पर कॉपी किया गया."</string>
<string name="basic_status" msgid="2315371112182658176">"ऐसी बातचीत जिसमें इंटरैक्शन डेटा मौजूद नहीं है"</string>
@@ -937,6 +948,13 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"कॉपी किए गए टेक्स्ट में बदलाव करें"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"कॉपी की गई इमेज में बदलाव करें"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"कॉन्टेंट को आस-पास मौजूद डिवाइस पर भेजें"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"देखने के लिए टैप करें"</string>
+ <!-- no translation found for clipboard_text_copied (5100836834278976679) -->
+ <skip />
+ <!-- no translation found for clipboard_image_copied (3793365360174328722) -->
+ <skip />
+ <!-- no translation found for clipboard_content_copied (144452398567828145) -->
+ <skip />
<string name="add" msgid="81036585205287996">"जोड़ें"</string>
<string name="manage_users" msgid="1823875311934643849">"उपयोगकर्ताओं को मैनेज करें"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"इस सूचना को स्प्लिट स्क्रीन मोड में, खींचा और छोड़ा नहीं जा सकता."</string>
@@ -945,4 +963,12 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"अलार्म सेट किया गया"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"कैमरा और माइक बंद हैं"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# सूचना}one{# सूचना}other{# सूचनाएं}}"</string>
+ <!-- no translation found for broadcasting_description_is_broadcasting (765627502786404290) -->
+ <skip />
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> पर ब्रॉडकास्ट करना रोकें?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> पर ब्रॉडकास्ट शुरू करने पर या आउटपुट बदलने पर, आपका मौजूदा ब्रॉडकास्ट बंद हो जाएगा"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> पर ब्रॉडकास्ट करें"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"आउटपुट बदलें"</string>
+ <!-- no translation found for bt_le_audio_broadcast_dialog_unknown_name (3791472237793443044) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-hi/tiles_states_strings.xml b/packages/SystemUI/res/values-hi/tiles_states_strings.xml
index 9af07bc..a156b0c 100644
--- a/packages/SystemUI/res/values-hi/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-hi/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"बंद है"</item>
<item msgid="460891964396502657">"चालू है"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"उपलब्ध नहीं है"</item>
+ <item msgid="8014986104355098744">"बंद है"</item>
+ <item msgid="5966994759929723339">"चालू है"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index d17aef7..23a78ec 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Pokušajte ponovo napraviti snimku zaslona"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"Nije moguće spremiti snimku zaslona"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Aplikacija ili vaša organizacija ne dopuštaju snimanje zaslona"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Izradu snimki zaslona blokirao je IT administrator"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Uredi"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Uređivanje snimke zaslona"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"Podijeli snimku zaslona"</string>
@@ -226,6 +227,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Autom. zakretanje"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Automatsko zakretanje zaslona"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Lokacija"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Čuvar zaslona"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Pristup fotoaparatu"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Pristup mikrofonu"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Dostupno"</string>
@@ -320,6 +322,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Otključano pomoću lica. Pritisnite da biste otvorili."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Lice je prepoznato. Pritisnite da biste otvorili."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Lice je prepoznato. Pritisnite ikonu otključavanja da biste otvorili."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"Prijeđite prstom prema gore za ponovni pokušaj"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Otključajte da biste upotrijebili NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Ovaj uređaj pripada vašoj organizaciji"</string>
@@ -470,7 +476,7 @@
<string name="wallet_title" msgid="5369767670735827105">"Novčanik"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"Postavite aplikaciju za bržu i sigurniju kupnju telefonom"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"Prikaži sve"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"Dodajte karticu"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"Dodirnite za otvaranje"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"Ažuriranje"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Otključajte da biste koristili"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Pojavio se problem prilikom dohvaćanja kartica, pokušajte ponovo kasnije"</string>
@@ -698,7 +704,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Upozorenja"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Baterija"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Snimke zaslona"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Općenite poruke"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"Pohrana"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Savjeti"</string>
<string name="instant_apps" msgid="8337185853050247304">"Instant aplikacije"</string>
@@ -732,6 +741,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"Uključite kad bi se baterija mogla isprazniti"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"Ne, hvala"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Izdvoji mem. SysUI-a"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"U upotrebi"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Aplikacije upotrebljavaju <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" i "</string>
@@ -830,7 +840,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Približite se radi reprodukcije na uređaju <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Približite se uređaju <xliff:g id="DEVICENAME">%1$s</xliff:g> da biste na njemu reproducirali"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Reproducira se na uređaju <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Reproducira se na ovom telefonu"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Nešto nije u redu. Pokušajte ponovo."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Neaktivno, provjerite aplik."</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Nije pronađeno"</string>
@@ -859,6 +868,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"Spremi"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"Pokretanje…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"Emitiranje nije uspjelo"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Spremanje nije uspjelo. Pokušajte ponovo."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Spremanje nije uspjelo."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Broj međuverzije"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Broj međuverzije kopiran je u međuspremnik."</string>
<string name="basic_status" msgid="2315371112182658176">"Otvoreni razgovor"</string>
@@ -944,6 +955,10 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Uredi kopirani tekst"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Uredi kopiranu sliku"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Pošalji uređaju u blizini"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"Dodirnite za prikaz"</string>
+ <string name="clipboard_text_copied" msgid="5100836834278976679">"Tekst je kopiran"</string>
+ <string name="clipboard_image_copied" msgid="3793365360174328722">"Slika je kopirana"</string>
+ <string name="clipboard_content_copied" msgid="144452398567828145">"Sadržaj je kopiran"</string>
<string name="add" msgid="81036585205287996">"Dodaj"</string>
<string name="manage_users" msgid="1823875311934643849">"Upravljanje korisnicima"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"Ova obavijest ne podržava povlačenje na podijeljeni zaslon."</string>
@@ -952,4 +967,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm je postavljen"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Fotoaparat i mikrofon su isključeni"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# obavijest}one{# obavijest}few{# obavijesti}other{# obavijesti}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Emitiranje"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Zaustaviti emitiranje aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Ako emitirate aplikaciju <xliff:g id="SWITCHAPP">%1$s</xliff:g> ili promijenite izlaz, vaše će se trenutačno emitiranje zaustaviti"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Emitiranje aplikacije <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Promjena izlaza"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Nepoznato"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hr/tiles_states_strings.xml b/packages/SystemUI/res/values-hr/tiles_states_strings.xml
index a057c48..b69b064 100644
--- a/packages/SystemUI/res/values-hr/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-hr/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Isključeno"</item>
<item msgid="460891964396502657">"Uključeno"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Nedostupno"</item>
+ <item msgid="8014986104355098744">"Isključeno"</item>
+ <item msgid="5966994759929723339">"Uključeno"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index a3baf52..5eb4836 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Próbálja meg újra elkészíteni a képernyőképet"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"Nem lehetséges a képernyőkép mentése"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Az alkalmazás vagy az Ön szervezete nem engedélyezi képernyőkép készítését"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"A képernyőkép készítésének lehetőségét a rendszergazda letiltotta"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Szerkesztés"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Képernyőkép szerkesztése"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"Képernyőkép megosztása"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automatikus elforgatás"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Automatikus képernyőforgatás"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Tartózkodási hely"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Képernyővédő"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Hozzáférés a kamerához"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Mikrofonelérés"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Rendelkezésre áll"</string>
@@ -318,6 +320,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Zárolás arccal feloldva. Koppintson az eszköz használatához."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Arc felismerve. Koppintson az eszköz használatához."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Arc felismerve. Eszköz használata: Feloldás ikon."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"Az újrapróbálkozáshoz csúsztassa felfelé az ujját"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Az NFC használatához oldja fel a képernyőzárat"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Ez az eszköz az Ön szervezetének tulajdonában van"</string>
@@ -467,7 +473,7 @@
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"Végezze el a beállítást a telefonjával való gyorsabb és biztonságosabb vásárláshoz"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"Összes mutatása"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"Kártya hozzáadása"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"Koppintson ide a megnyitáshoz"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"Frissítés"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Oldja fel a használathoz"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Probléma merült fel a kártyák lekérésekor, próbálja újra később"</string>
@@ -693,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Értesítések"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Akkumulátor"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Képernyőképek"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Általános üzenetek"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"Tárhely"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Tippek"</string>
<string name="instant_apps" msgid="8337185853050247304">"Azonnali alkalmazások"</string>
@@ -727,6 +736,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"Kapcsolja be, ha az akkumulátor hamarosan lemerül"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"Nem"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"SysUI-memória-kiírás"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"Használatban"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Több alkalmazás használja a következőket: <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" és "</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Menjen közelebb a következőn való lejátszáshoz: <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Menjen közelebb a(z) <xliff:g id="DEVICENAME">%1$s</xliff:g> eszközhöz, hogy itt játszhassa le a tartalmat"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Lejátszás folyamatban a(z) <xliff:g id="DEVICENAME">%1$s</xliff:g> eszközön"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Lejátszás ezen a telefonon"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Hiba történt. Próbálkozzon újra."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inaktív, ellenőrizze az appot"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Nem található"</string>
@@ -853,6 +862,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"Mentés"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"Indítás…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"Nem sikerült a közvetítés"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"A mentés nem sikerült. Próbálja újra."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"A mentés nem sikerült."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Buildszám"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Buildszám a vágólapra másolva."</string>
<string name="basic_status" msgid="2315371112182658176">"Beszélgetés megnyitása"</string>
@@ -937,6 +948,13 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Vágólapra másolt szöveg szerkesztése"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Vágólapra másolt kép szerkesztése"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Küldés közeli eszközre"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"Koppintson a megtekintéshez"</string>
+ <!-- no translation found for clipboard_text_copied (5100836834278976679) -->
+ <skip />
+ <!-- no translation found for clipboard_image_copied (3793365360174328722) -->
+ <skip />
+ <!-- no translation found for clipboard_content_copied (144452398567828145) -->
+ <skip />
<string name="add" msgid="81036585205287996">"Hozzáadás"</string>
<string name="manage_users" msgid="1823875311934643849">"Felhasználók kezelése"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"Az értesítés nem támogatja a megosztott képernyőre való áthúzást."</string>
@@ -945,4 +963,12 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Ébresztő beállítva"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"A kamera és a mikrofon ki vannak kapcsolva"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# értesítés}other{# értesítés}}"</string>
+ <!-- no translation found for broadcasting_description_is_broadcasting (765627502786404290) -->
+ <skip />
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Leállítja a(z) <xliff:g id="APP_NAME">%1$s</xliff:g> közvetítését?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"A(z) <xliff:g id="SWITCHAPP">%1$s</xliff:g> közvetítése vagy a kimenet módosítása esetén a jelenlegi közvetítés leáll"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> közvetítése"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Kimenet módosítása"</string>
+ <!-- no translation found for bt_le_audio_broadcast_dialog_unknown_name (3791472237793443044) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-hu/tiles_states_strings.xml b/packages/SystemUI/res/values-hu/tiles_states_strings.xml
index 47109a3..050bc14 100644
--- a/packages/SystemUI/res/values-hu/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-hu/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Ki"</item>
<item msgid="460891964396502657">"Be"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Nem áll rendelkezésre"</item>
+ <item msgid="8014986104355098744">"Ki"</item>
+ <item msgid="5966994759929723339">"Be"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index b365bfa..590d9c1 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Փորձեք նորից"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"Չհաջողվեց պահել սքրինշոթը"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Հավելվածը կամ ձեր կազմակերպությունը չի թույլատրում սքրինշոթի ստացումը"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Ձեր ՏՏ ադմինիստրատորն արգելափակել է սքրինշոթներ անելու հնարավորությունը"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Փոփոխել"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Փոփոխել սքրինշոթը"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"Ուղարկել սքրինշոթ"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Ինքնապտտում"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Ավտոմատ պտտել էկրանը"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Տեղորոշում"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Էկրանապահ"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Տեսախցիկի հասանելիություն"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Խոսափողի հասանելիություն"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Հասանելի է"</string>
@@ -318,6 +320,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Ապակողպվել է դեմքով։ Սեղմեք բացելու համար։"</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Դեմքը ճանաչվեց։ Սեղմեք բացելու համար։"</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Դեմքը ճանաչվեց։ Բացելու համար սեղմեք ապակողպման պատկերակը։"</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"Սահեցրեք վերև՝ նորից փորձելու համար"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Ապակողպեք՝ NFC-ն օգտագործելու համար"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Այս սարքը պատկանում է ձեր կազմակերպությանը"</string>
@@ -425,7 +431,7 @@
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Էկրանը կցուցադրվի, մինչև չեղարկեք ամրացումը: Չեղարկելու համար մատը սահեցրեք վեր և պահեք։"</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Էկրանը կմնա տեսադաշտում, մինչև այն ապամրացնեք: Ապամրացնելու համար հպեք և պահեք Համատեսք կոճակը:"</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Էկրանը կցուցադրվի, մինչև չեղարկեք ամրացումը: Չեղարկելու համար հպեք և պահեք գլխավոր էկրանի կոճակը:"</string>
- <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Ձեր անձնական տվյալները (օր․՝ կոնտակտները և նամակների բովանդակությունը) կարող են հասանելի դառնալ։"</string>
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Ձեր անձնական տվյալները (կոնտակտները, նամակների բովանդակությունը և այլն) կարող են հասանելի լինել։"</string>
<string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Ամրացված հավելվածը կարող է այլ հավելվածներ գործարկել։"</string>
<string name="screen_pinning_toast" msgid="8177286912533744328">"Հավելվածն ապամրացնելու համար հպեք և պահեք «Հետ» և «Համատեսք» կոճակները"</string>
<string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Հավելվածն ապամրացնելու համար հպեք և պահեք «Հետ» և «Գլխավոր էկրան» կոճակները"</string>
@@ -467,7 +473,7 @@
<string name="wallet_title" msgid="5369767670735827105">"Դրամապանակ"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"Վճարեք հեռախոսով՝ ավելի արագ և ապահով"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"Ցույց տալ բոլորը"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"Ավելացնել քարտ"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"Հպեք բացելու համար"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"Թարմացվում է"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Ապակողպել՝ օգտագործելու համար"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Չհաջողվեց բեռնել քարտերը։ Նորից փորձեք։"</string>
@@ -693,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Ծանուցումներ"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Մարտկոց"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Սքրինշոթներ"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Ընդհանուր հաղորդագրություններ"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"Տարածք"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Հուշումներ"</string>
<string name="instant_apps" msgid="8337185853050247304">"Ակնթարթային հավելվածներ"</string>
@@ -727,6 +736,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"Միացնել էներգախնայումը, երբ մարտկոցի լիցքը գրեթե սպառված է"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"Ոչ"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"Օգտագործվում է"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Հավելվածներն օգտագործում են ձեր <xliff:g id="TYPES_LIST">%s</xliff:g>:"</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" և "</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Ավելի մոտ եկեք՝ <xliff:g id="DEVICENAME">%1$s</xliff:g> սարքում նվագարկելու համար"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Ավելի մոտեցեք «<xliff:g id="DEVICENAME">%1$s</xliff:g>» սարքին՝ նվագարկումը սկսելու համար"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Նվագարկվում է «<xliff:g id="DEVICENAME">%1$s</xliff:g>» սարքում"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Նվագարկվում է այս հեռախոսում"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Սխալ առաջացավ։ Նորից փորձեք։"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Ակտիվ չէ, ստուգեք հավելվածը"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Չի գտնվել"</string>
@@ -853,6 +862,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"Պահել"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"Սկսվում է…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"Չհաջողվեց հեռարձակել"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Չհաջողվեց պահել։ Նորից փորձեք։"</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Չհաջողվեց պահել։"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Կառուցման համարը"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Կառուցման համարը պատճենվեց սեղմատախտակին։"</string>
<string name="basic_status" msgid="2315371112182658176">"Բաց զրույց"</string>
@@ -937,6 +948,13 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Փոփոխել պատճենված տեքստը"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Փոփոխել պատճենված պատկերը"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Ուղարկել մոտակա սարքի"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"Հպեք դիտելու համար"</string>
+ <!-- no translation found for clipboard_text_copied (5100836834278976679) -->
+ <skip />
+ <!-- no translation found for clipboard_image_copied (3793365360174328722) -->
+ <skip />
+ <!-- no translation found for clipboard_content_copied (144452398567828145) -->
+ <skip />
<string name="add" msgid="81036585205287996">"Ավելացնել"</string>
<string name="manage_users" msgid="1823875311934643849">"Օգտատերերի կառավարում"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"Այս ծանուցումը հնարավոր չէ քաշել տրոհված էկրանի մեկ հատվածից մյուսը։"</string>
@@ -945,4 +963,12 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Զարթուցիչը դրված է"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Տեսախցիկը և խոսափողն անջատված են"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# ծանուցում}one{# ծանուցում}other{# ծանուցում}}"</string>
+ <!-- no translation found for broadcasting_description_is_broadcasting (765627502786404290) -->
+ <skip />
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Կանգնեցնել <xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածի հեռարձակումը"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Եթե հեռարձակեք <xliff:g id="SWITCHAPP">%1$s</xliff:g> հավելվածը կամ փոխեք աուդիո ելքը, ձեր ընթացիկ հեռարձակումը կկանգնեցվի։"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Հեռարձակել <xliff:g id="SWITCHAPP">%1$s</xliff:g> հավելվածը"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Փոխել աուդիո ելքը"</string>
+ <!-- no translation found for bt_le_audio_broadcast_dialog_unknown_name (3791472237793443044) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-hy/tiles_states_strings.xml b/packages/SystemUI/res/values-hy/tiles_states_strings.xml
index a78b7a1..6015fbd 100644
--- a/packages/SystemUI/res/values-hy/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-hy/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Անջատված է"</item>
<item msgid="460891964396502657">"Միացված է"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Հասանելի չէ"</item>
+ <item msgid="8014986104355098744">"Անջատված է"</item>
+ <item msgid="5966994759929723339">"Միացված է"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 2e5506b..ce9219c 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Coba ambil screenshot lagi"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"Tidak dapat menyimpan screenshot"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Mengambil screenshot tidak diizinkan oleh aplikasi atau organisasi"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Mengambil screenshot diblokir oleh admin IT Anda"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Edit"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Mengedit screenshot"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"Bagikan screenshot"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Putar Otomatis"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Putar layar otomatis"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Lokasi"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Screensaver"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Akses kamera"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Akses mikrofon"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Tersedia"</string>
@@ -318,6 +320,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Kunci dibuka dengan wajah. Tekan untuk membuka."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Wajah dikenali. Tekan untuk membuka."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Wajah dikenali. Tekan ikon buka kunci untuk membuka."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"Geser ke atas untuk mencoba lagi"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Buka kunci untuk menggunakan NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Perangkat ini milik organisasi Anda"</string>
@@ -425,8 +431,8 @@
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Aplikasi akan terus ditampilkan sampai sematan dilepaskan. Geser ke atas dan tahan agar sematan lepas."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Ini akan terus ditampilkan sampai Anda melepas sematan. Sentuh lama tombol Ringkasan untuk melepas sematan."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Ini akan terus ditampilkan sampai Anda melepas sematan. Sentuh lama tombol Beranda untuk melepas sematan."</string>
- <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Data pribadi dapat diakses (seperti kontak dan konten email)."</string>
- <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Aplikasi yang disematkan dapat membuka aplikasi lain."</string>
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Data pribadi mungkin dapat diakses (seperti kontak dan konten email)."</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Aplikasi yang disematkan mungkin dapat membuka aplikasi lain."</string>
<string name="screen_pinning_toast" msgid="8177286912533744328">"Untuk melepas sematan aplikasi ini, sentuh lama tombol Kembali dan Ringkasan"</string>
<string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Untuk melepas sematan aplikasi ini, sentuh lama tombol Kembali dan Layar utama"</string>
<string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"Untuk melepas sematan aplikasi ini, geser ke atas & tahan"</string>
@@ -467,7 +473,7 @@
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"Siapkan metode pembayaran untuk melakukan pembelian dengan lebih cepat dan aman menggunakan ponsel Anda"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"Tampilkan semua"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"Tambahkan kartu"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"Ketuk untuk membuka"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"Memperbarui"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Buka kunci untuk menggunakan"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Terjadi masalah saat mendapatkan kartu Anda, coba lagi nanti"</string>
@@ -693,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Notifikasi"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Baterai"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Screenshot"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Pesan Umum"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"Penyimpanan"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Petunjuk"</string>
<string name="instant_apps" msgid="8337185853050247304">"Aplikasi Instan"</string>
@@ -727,6 +736,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"Aktifkan jika daya baterai kemungkinan akan habis"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"Tidak, terima kasih"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Hapus Heap SysUI"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"Sedang digunakan"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Aplikasi menggunakan <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" dan "</string>
@@ -778,7 +788,7 @@
<string name="accessibility_control_move" msgid="8980344493796647792">"Pindah ke posisi <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="controls_favorite_default_title" msgid="967742178688938137">"Kontrol"</string>
<string name="controls_favorite_subtitle" msgid="6481675111056961083">"Pilih kontrol untuk diakses dari Setelan Cepat"</string>
- <string name="controls_favorite_rearrange" msgid="5616952398043063519">"Tahan & tarik untuk mengatur ulang kontrol"</string>
+ <string name="controls_favorite_rearrange" msgid="5616952398043063519">"Tahan & tarik untuk menata ulang kontrol"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Semua kontrol dihapus"</string>
<string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Perubahan tidak disimpan"</string>
<string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"Lihat aplikasi lainnya"</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Dekatkan untuk memutar di <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Dekatkan ke <xliff:g id="DEVICENAME">%1$s</xliff:g> untuk memutar di sini"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Diputar di <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Diputar di ponsel ini"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Terjadi error. Coba lagi."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Nonaktif, periksa aplikasi"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Tidak ditemukan"</string>
@@ -853,6 +862,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"Simpan"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"Memulai …"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"Tidak dapat menyiarkan"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Tidak dapat menyimpan. Coba lagi."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Tidak dapat menyimpan."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Nomor build"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Nomor versi disalin ke papan klip."</string>
<string name="basic_status" msgid="2315371112182658176">"Membuka percakapan"</string>
@@ -937,6 +948,13 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Edit teks yang disalin"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Edit gambar yang disalin"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Kirim ke perangkat di sekitar"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"Ketuk untuk melihat"</string>
+ <!-- no translation found for clipboard_text_copied (5100836834278976679) -->
+ <skip />
+ <!-- no translation found for clipboard_image_copied (3793365360174328722) -->
+ <skip />
+ <!-- no translation found for clipboard_content_copied (144452398567828145) -->
+ <skip />
<string name="add" msgid="81036585205287996">"Tambahkan"</string>
<string name="manage_users" msgid="1823875311934643849">"Kelola pengguna"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"Notifikasi ini tidak mendukung fitur tarik ke Layar terpisah."</string>
@@ -945,4 +963,12 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm disetel"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera dan mikrofon nonaktif"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notifikasi}other{# notifikasi}}"</string>
+ <!-- no translation found for broadcasting_description_is_broadcasting (765627502786404290) -->
+ <skip />
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Hentikan siaran <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Jika Anda menyiarkan <xliff:g id="SWITCHAPP">%1$s</xliff:g> atau mengubah output, siaran saat ini akan dihentikan"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Siarkan <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Ubah output"</string>
+ <!-- no translation found for bt_le_audio_broadcast_dialog_unknown_name (3791472237793443044) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-in/tiles_states_strings.xml b/packages/SystemUI/res/values-in/tiles_states_strings.xml
index 6f81b29..b8eb2f7 100644
--- a/packages/SystemUI/res/values-in/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-in/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Nonaktif"</item>
<item msgid="460891964396502657">"Aktif"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Tidak tersedia"</item>
+ <item msgid="8014986104355098744">"Nonaktif"</item>
+ <item msgid="5966994759929723339">"Aktif"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index ea97e1c..c32d861 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Prófaðu að taka skjámynd aftur"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"Ekki er hægt að vista skjámynd"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Forritið eða fyrirtækið þitt leyfir ekki skjámyndatöku"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Kerfisstjórinn lokaði á skjámyndatöku"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Breyta"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Breyta skjámynd"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"Deila skjámynd"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Sjálfvirkur snúningur"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Snúa skjá sjálfkrafa"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Staðsetning"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Skjávari"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Aðgangur að myndavél"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Aðgangur að hljóðnema"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Tiltækt"</string>
@@ -318,6 +320,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Opnað með andliti. Ýttu til að opna."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Andlitið var greint. Ýttu til að opna."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Andlitið var greint. Ýttu á opnunartáknið til að opna."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"Strjúktu upp til að reyna aftur"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Taktu úr lás til að nota NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Þetta tæki tilheyrir fyrirtækinu þínu"</string>
@@ -425,7 +431,7 @@
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Þetta heldur þessu opnu þangað til það er losað. Strjúktu upp og haltu inni til að losa."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Þetta heldur þessu opnu þangað til þú losar það. Haltu fingri á „Yfirlit“ til að losa."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Þetta heldur þessu opnu þangað til það er losað. Haltu heimahnappinum inni til að losa."</string>
- <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Persónuupplýsingar gætu verið aðgengilegar (til dæmis tengiliðir og innihald tölvupósts)."</string>
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Persónuupplýsingar gætu verið aðgengilegar (s.s. tengiliðir og efni tölvupósta)."</string>
<string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Fest forrit getur opnað önnur forrit."</string>
<string name="screen_pinning_toast" msgid="8177286912533744328">"Til að losa þetta forrit skaltu halda inni bakkhnappinum og yfirlitshnappinum"</string>
<string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Til að losa þetta forrit skaltu halda inni bakkhnappinum og heimahnappinum"</string>
@@ -467,7 +473,7 @@
<string name="wallet_title" msgid="5369767670735827105">"Veski"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"Stilltu hlutina þannig að þú getir verslað með símanum á hraðari og öruggari hátt"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"Sýna allt"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"Bæta korti við"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"Ýttu til að opna"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"Uppfærir"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Taktu úr lás til að nota"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Vandamál kom upp við að sækja kortin þín. Reyndu aftur síðar"</string>
@@ -693,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Tilkynningar"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Rafhlaða"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Skjámyndir"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Almenn skilaboð"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"Geymslurými"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Vísbendingar"</string>
<string name="instant_apps" msgid="8337185853050247304">"Skyndiforrit"</string>
@@ -727,6 +736,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"Kveikja þegar rafhlaða er við það að klárast"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"Nei, takk"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Vista SysUI-gögn"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"Í notkun"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Forrit eru að nota <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" og "</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Færðu nær til að spila í <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Færðu tækið nær <xliff:g id="DEVICENAME">%1$s</xliff:g> til að spila hér"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Í spilun í <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Í spilun í þessum síma"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Eitthvað fór úrskeiðis. Reyndu aftur."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Óvirkt, athugaðu forrit"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Fannst ekki"</string>
@@ -853,6 +862,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"Vista"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"Ræsir…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"Ekki hægt að senda út"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Ekki hægt að vista. Reyndu aftur."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Ekki hægt að vista."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Útgáfunúmer smíðar"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Útgáfunúmer smíðar afritað á klippiborð."</string>
<string name="basic_status" msgid="2315371112182658176">"Opna samtal"</string>
@@ -937,6 +948,13 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Breyta afrituðum texta"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Breyta afritaðri mynd"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Senda í nálægt tæki"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"Ýttu til að skoða"</string>
+ <!-- no translation found for clipboard_text_copied (5100836834278976679) -->
+ <skip />
+ <!-- no translation found for clipboard_image_copied (3793365360174328722) -->
+ <skip />
+ <!-- no translation found for clipboard_content_copied (144452398567828145) -->
+ <skip />
<string name="add" msgid="81036585205287996">"Bæta við"</string>
<string name="manage_users" msgid="1823875311934643849">"Stjórna notendum"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"Þessi tilkynning styður ekki að draga yfir á skiptan skjá."</string>
@@ -945,4 +963,12 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Vekjari stilltur"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Slökkt á myndavél og hljóðnema"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# tilkynning}one{# tilkynning}other{# tilkynningar}}"</string>
+ <!-- no translation found for broadcasting_description_is_broadcasting (765627502786404290) -->
+ <skip />
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Hætta að senda út <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Ef þú sendir út <xliff:g id="SWITCHAPP">%1$s</xliff:g> eða skiptir um úttak lýkur yfirstandandi útsendingu"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Senda út <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Skipta um úttak"</string>
+ <!-- no translation found for bt_le_audio_broadcast_dialog_unknown_name (3791472237793443044) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-is/tiles_states_strings.xml b/packages/SystemUI/res/values-is/tiles_states_strings.xml
index 29bce82..12dd776 100644
--- a/packages/SystemUI/res/values-is/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-is/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Slökkt"</item>
<item msgid="460891964396502657">"Kveikt"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Ekki í boði"</item>
+ <item msgid="8014986104355098744">"Slökkt"</item>
+ <item msgid="5966994759929723339">"Kveikt"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index ff5e9ff..3f49541 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Riprova ad acquisire lo screenshot"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"Impossibile salvare lo screenshot"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"L\'acquisizione di screenshot non è consentita dall\'app o dall\'organizzazione"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"L\'acquisizione di screenshot è stata bloccata dall\'amministratore IT"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Modifica"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Modifica screenshot"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"Condividi screenshot"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Rotazione automatica"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Rotazione automatica dello schermo"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Geolocalizzazione"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Salvaschermo"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Accesso alla fotocamera"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Accesso al microfono"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Disponibile"</string>
@@ -318,6 +320,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Sbloccato con il volto. Premi per aprire."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Volto riconosciuto. Premi per aprire."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Volto riconosciuto. Premi l\'icona Sblocca per aprire."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"Scorri verso l\'alto per riprovare"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Sblocca per usare NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Questo dispositivo appartiene alla tua organizzazione"</string>
@@ -467,7 +473,7 @@
<string name="wallet_title" msgid="5369767670735827105">"Portafoglio"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"Imposta un metodo di pagamento per effettuare acquisti in modo più rapido e sicuro con il telefono"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"Espandi"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"Aggiungi una carta"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"Tocca per aprire"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"Aggiornamento in corso…"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Sblocca per usare"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Si è verificato un problema durante il recupero delle tue carte. Riprova più tardi."</string>
@@ -693,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Avvisi"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Batteria"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Screenshot"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Messaggi generali"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"Spazio di archiviazione"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Suggerimenti"</string>
<string name="instant_apps" msgid="8337185853050247304">"App istantanee"</string>
@@ -727,6 +736,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"Attiva questa funzionalità se è probabile che la batteria si scarichi"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"No grazie"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump heap SysUI"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"In uso"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Le app stanno usando <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" e "</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Avvicinati per riprodurre su <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Avvicinati a <xliff:g id="DEVICENAME">%1$s</xliff:g> per riprodurre i contenuti qui"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"In riproduzione su <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"In riproduzione su questo telefono"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Si è verificato un errore. Riprova."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inattivo, controlla l\'app"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Controllo non trovato"</string>
@@ -851,8 +860,10 @@
<string name="media_output_broadcast_name" msgid="8786127091542624618">"Nome annuncio"</string>
<string name="media_output_broadcast_code" msgid="870795639644728542">"Password"</string>
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"Salva"</string>
- <string name="media_output_broadcast_starting" msgid="8130153654166235557">"Avvio in corso…"</string>
+ <string name="media_output_broadcast_starting" msgid="8130153654166235557">"In fase di avvio"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"Impossibile trasmettere"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Impossibile salvare. Riprova."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Impossibile salvare."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Numero build"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Numero build copiato negli appunti."</string>
<string name="basic_status" msgid="2315371112182658176">"Apri conversazione"</string>
@@ -922,8 +933,8 @@
<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>
<plurals name="fgs_manager_footer_label" formatted="false" msgid="790443735462280164">
- <item quantity="other">Ci sono <xliff:g id="COUNT_1">%s</xliff:g> app attive</item>
- <item quantity="one">C\'è <xliff:g id="COUNT_0">%s</xliff:g> app attiva</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> app attive</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> app attiva</item>
</plurals>
<string name="fgs_dot_content_description" msgid="2865071539464777240">"Nuove informazioni"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"App attive"</string>
@@ -937,6 +948,13 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Modifica testo copiato"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Modifica immagine copiata"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Invia a dispositivo nelle vicinanze"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"Tocca per visualizzare"</string>
+ <!-- no translation found for clipboard_text_copied (5100836834278976679) -->
+ <skip />
+ <!-- no translation found for clipboard_image_copied (3793365360174328722) -->
+ <skip />
+ <!-- no translation found for clipboard_content_copied (144452398567828145) -->
+ <skip />
<string name="add" msgid="81036585205287996">"Aggiungi"</string>
<string name="manage_users" msgid="1823875311934643849">"Gestisci utenti"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"Non è possibile trascinare questa notifica tra le due parti dello schermo diviso."</string>
@@ -945,4 +963,12 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Sveglia impostata"</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>
+ <!-- no translation found for broadcasting_description_is_broadcasting (765627502786404290) -->
+ <skip />
+ <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>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Se trasmetti l\'app <xliff:g id="SWITCHAPP">%1$s</xliff:g> o cambi l\'uscita, la trasmissione attuale viene interrotta"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Trasmetti l\'app <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Cambia uscita"</string>
+ <!-- no translation found for bt_le_audio_broadcast_dialog_unknown_name (3791472237793443044) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-it/tiles_states_strings.xml b/packages/SystemUI/res/values-it/tiles_states_strings.xml
index 757a866..5ec557b 100644
--- a/packages/SystemUI/res/values-it/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-it/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Off"</item>
<item msgid="460891964396502657">"On"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Non disponibile"</item>
+ <item msgid="8014986104355098744">"Off"</item>
+ <item msgid="5966994759929723339">"On"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 14a1c06..dafdcac 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"אפשר לצלם שוב את המסך"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"לא ניתן לשמור את צילום המסך"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"האפליקציה או הארגון שלך אינם מתירים ליצור צילומי מסך"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"יצירת צילומי המסך נחסמה על ידי מנהל ה-IT"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"עריכה"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"עריכת צילום מסך"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"שיתוף של צילום מסך"</string>
@@ -227,6 +228,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"סיבוב אוטומטי"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"סיבוב אוטומטי של המסך"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"מיקום"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"שומר מסך"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"גישה למצלמה"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"גישה למיקרופון"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"יש גישה"</string>
@@ -248,7 +250,7 @@
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"היפוך צבעים"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"תיקון צבע"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"הגדרות המשתמש"</string>
- <string name="quick_settings_done" msgid="2163641301648855793">"בוצע"</string>
+ <string name="quick_settings_done" msgid="2163641301648855793">"סיום"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"סגירה"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"מחובר"</string>
<string name="quick_settings_connected_battery_level" msgid="1322075669498906959">"המכשיר מחובר. סוללה: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
@@ -322,6 +324,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"הנעילה בוטלה באמצעות זיהוי הפנים. יש ללחוץ כדי לפתוח."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"הפנים זוהו. יש ללחוץ כדי לפתוח."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"הפנים זוהו. יש ללחוץ על סמל ביטול הנעילה כדי לפתוח."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"יש להחליק למעלה כדי לנסות שוב"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"יש לבטל את הנעילה כדי להשתמש ב-NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"המכשיר הזה שייך לארגון שלך"</string>
@@ -417,7 +423,7 @@
<string name="monitoring_description_vpn_settings" msgid="5264167033247632071">"להגדרות ה-VPN"</string>
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"מכשיר זה מנוהל על ידי ההורה שלך. להורה שלך יש אפשרות לצפות בפרטים כמו האפליקציות שבשימוש, המיקום וזמן המסך שלך, ולנהל אותם."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
- <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"הנעילה נמנעת על ידי סביבה אמינה"</string>
+ <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"הנעילה נמנעת על ידי סביבה מהימנה"</string>
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"הגדרות צליל"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"הוספת כתוביות באופן אוטומטי למדיה"</string>
@@ -473,7 +479,7 @@
<string name="wallet_title" msgid="5369767670735827105">"ארנק"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"מגדירים אמצעי תשלום ונהנים מביצוע מהיר ומאובטח יותר של רכישות באמצעות הטלפון"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"הצגת הכול"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"הוספת כרטיס"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"יש להקיש לפתיחה"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"מתבצע עדכון"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"יש לבטל את הנעילה כדי להשתמש"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"הייתה בעיה בקבלת הכרטיסים שלך. כדאי לנסות שוב מאוחר יותר"</string>
@@ -611,7 +617,7 @@
<string name="switch_bar_off" msgid="5669805115416379556">"כבוי"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"לא זמין"</string>
<string name="tile_disabled" msgid="373212051546573069">"מושבת"</string>
- <string name="nav_bar" msgid="4642708685386136807">"סרגל ניווט"</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>
<string name="right_nav_bar_button_type" msgid="4472566498647364715">"סוג נוסף של לחצן ימני"</string>
@@ -703,7 +709,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"התראות"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"סוללה"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"צילומי מסך"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"הודעות כלליות"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"אחסון"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"טיפים"</string>
<string name="instant_apps" msgid="8337185853050247304">"אפליקציות ללא התקנה"</string>
@@ -737,6 +746,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"מומלץ להפעיל את התכונה כשיש סבירות גבוהה שהסוללה תתרוקן"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"לא תודה"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"בשימוש"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"אפליקציות משתמשות ב<xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" וגם "</string>
@@ -836,7 +846,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"צריך להתקרב כדי להפעיל מוזיקה במכשיר <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"צריך להתקרב אל <xliff:g id="DEVICENAME">%1$s</xliff:g> כדי להפעיל כאן"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"פועלת ב-<xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"פועלת בטלפון הזה"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"משהו השתבש. יש לנסות שוב."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"לא פעיל, יש לבדוק את האפליקציה"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"לא נמצא"</string>
@@ -865,6 +874,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"שמירה"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"בתהליך הפעלה…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"לא ניתן לשדר"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"לא ניתן לשמור. כדאי לנסות שוב."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"לא ניתן לשמור."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"מספר Build"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"מספר ה-Build הועתק ללוח."</string>
<string name="basic_status" msgid="2315371112182658176">"פתיחת שיחה"</string>
@@ -951,6 +962,13 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"עריכת הטקסט שהועתק"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"עריכת התמונה שהועתקה"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"שליחה למכשיר בקרבת מקום"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"יש להקיש כדי להציג"</string>
+ <!-- no translation found for clipboard_text_copied (5100836834278976679) -->
+ <skip />
+ <!-- no translation found for clipboard_image_copied (3793365360174328722) -->
+ <skip />
+ <!-- no translation found for clipboard_content_copied (144452398567828145) -->
+ <skip />
<string name="add" msgid="81036585205287996">"הוספה"</string>
<string name="manage_users" msgid="1823875311934643849">"ניהול משתמשים"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"ההתראה הזו לא תומכת בגרירה למסך מפוצל."</string>
@@ -959,4 +977,12 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"ההתראה מוגדרת"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"המצלמה והמיקרופון כבויים"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{התראה אחת}two{# התראות}many{# התראות}other{# התראות}}"</string>
+ <!-- no translation found for broadcasting_description_is_broadcasting (765627502786404290) -->
+ <skip />
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"האם להפסיק לשדר את התוכן מאפליקציית <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"אם משדרים את התוכן מאפליקציית <xliff:g id="SWITCHAPP">%1$s</xliff:g> או משנים את הפלט, השידור הנוכחי יפסיק לפעול"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"שידור תוכן מאפליקציית <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"שינוי הפלט"</string>
+ <!-- no translation found for bt_le_audio_broadcast_dialog_unknown_name (3791472237793443044) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-iw/tiles_states_strings.xml b/packages/SystemUI/res/values-iw/tiles_states_strings.xml
index 46be20c..91577b8 100644
--- a/packages/SystemUI/res/values-iw/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-iw/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"כבוי"</item>
<item msgid="460891964396502657">"פועל"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"לא זמין"</item>
+ <item msgid="8014986104355098744">"כבוי"</item>
+ <item msgid="5966994759929723339">"מופעל"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 37c4479..aebfa2b 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"スクリーンショットを撮り直してください"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"スクリーンショットを保存できません"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"スクリーンショットの作成はアプリまたは組織で許可されていません"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"スクリーンショットの撮影は IT 管理者によってブロックされています。"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"編集"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"スクリーンショットを編集します"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"スクリーンショットを共有"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"自動回転"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"画面を自動回転します"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"位置情報"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"スクリーン セーバー"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"カメラへのアクセス"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"マイクへのアクセス"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"使用可能"</string>
@@ -318,6 +320,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"顔でロック解除しました。押すと開きます。"</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"顔を認識しました。押すと開きます。"</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"顔を認識しました。ロック解除アイコンを押して開きます。"</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"上にスワイプしてもう一度お試しください"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC を使用するには、ロックを解除してください"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"これは組織が所有するデバイスです"</string>
@@ -467,7 +473,7 @@
<string name="wallet_title" msgid="5369767670735827105">"ウォレット"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"スマートフォンを使ってよりすばやく安全に購入できるように設定しましょう"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"すべて表示"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"カードを追加する"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"タップして開く"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"更新しています"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ロックを解除して使用"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"カードの取得中に問題が発生しました。しばらくしてからもう一度お試しください"</string>
@@ -693,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"アラート"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"バッテリー"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"スクリーンショット"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"一般メッセージ"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"ストレージ"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"ヒント"</string>
<string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string>
@@ -727,6 +736,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"電池切れになる可能性が高くなると有効になります"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"いいえ"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"SysUI ヒープのダンプ"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"使用中"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"アプリは<xliff:g id="TYPES_LIST">%s</xliff:g>を使用しています。"</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">"、 "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" 、 "</string>
@@ -804,7 +814,7 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"スワイプすると他の構造が表示されます"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"候補を読み込んでいます"</string>
<string name="controls_media_title" msgid="1746947284862928133">"メディア"</string>
- <string name="controls_media_close_session" msgid="4780485355795635052">"<xliff:g id="APP_NAME">%1$s</xliff:g> のこのメディア コントロールを非表示にしますか?"</string>
+ <string name="controls_media_close_session" msgid="4780485355795635052">"<xliff:g id="APP_NAME">%1$s</xliff:g> のこのコントロールを非表示にしますか?"</string>
<string name="controls_media_active_session" msgid="3146882316024153337">"現在のメディア セッションは非表示にできません。"</string>
<string name="controls_media_dismiss_button" msgid="4485675693008031646">"非表示"</string>
<string name="controls_media_resume" msgid="1933520684481586053">"再開"</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g>で再生するにはもっと近づけてください"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"ここで再生するには<xliff:g id="DEVICENAME">%1$s</xliff:g>に近づいてください"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g>で再生しています"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"このスマートフォンで再生しています"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"エラーが発生しました。もう一度お試しください。"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"無効: アプリをご確認ください"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"見つかりませんでした"</string>
@@ -853,6 +862,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"保存"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"開始しています…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"ブロードキャストできません"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"保存できません。もう一度お試しください。"</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"保存できません。"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"ビルド番号"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"ビルド番号をクリップボードにコピーしました。"</string>
<string name="basic_status" msgid="2315371112182658176">"空の会話"</string>
@@ -922,8 +933,8 @@
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"タイルを追加しない"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"ユーザーの選択"</string>
<plurals name="fgs_manager_footer_label" formatted="false" msgid="790443735462280164">
- <item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> 個のアプリがアクティブです</item>
- <item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> 個のアプリがアクティブです</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> 個のアプリが実行中です</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> 個のアプリが実行中です</item>
</plurals>
<string name="fgs_dot_content_description" msgid="2865071539464777240">"最新情報"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"実行中のアプリ"</string>
@@ -937,6 +948,10 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"コピーしたテキストを編集"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"コピーした画像を編集"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"付近のデバイスに送信"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"タップして表示"</string>
+ <string name="clipboard_text_copied" msgid="5100836834278976679">"テキストをコピーしました"</string>
+ <string name="clipboard_image_copied" msgid="3793365360174328722">"画像をコピーしました"</string>
+ <string name="clipboard_content_copied" msgid="144452398567828145">"コンテンツをコピーしました"</string>
<string name="add" msgid="81036585205287996">"追加"</string>
<string name="manage_users" msgid="1823875311934643849">"ユーザーの管理"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"この通知は、分割画面へのドラッグがサポートされていません。"</string>
@@ -945,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"アラームを設定しました"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"カメラとマイクが OFF です"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# 件の通知}other{# 件の通知}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"ブロードキャスト"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> のブロードキャストを停止しますか?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> をブロードキャストしたり、出力を変更したりすると、現在のブロードキャストが停止します。"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> をブロードキャスト"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"出力を変更"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"不明"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ja/tiles_states_strings.xml b/packages/SystemUI/res/values-ja/tiles_states_strings.xml
index fd966da..c2a3321 100644
--- a/packages/SystemUI/res/values-ja/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ja/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"OFF"</item>
<item msgid="460891964396502657">"ON"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"使用不可"</item>
+ <item msgid="8014986104355098744">"OFF"</item>
+ <item msgid="5966994759929723339">"ON"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 93c0cad..9d8b67d 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"ხელახლა ცადეთ ეკრანის ანაბეჭდის გაკეთება"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"ეკრანის ანაბეჭდის შენახვა ვერ ხერხდება"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"ეკრანის ანაბეჭდების შექმნა არ არის ნებადართული აპის ან თქვენი ორგანიზაციის მიერ"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"ეკრანის ანაბეჭდის გადაღება დაბლოკილია თქვენი IT ადმინისტრატორის მიერ"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"რედაქტირება"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"ეკრანის ანაბეჭდის რედაქტირება"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"ეკრანის ანაბეჭდის გაზიარება"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"ავტოროტაცია"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"ეკრანის ავტომატური შეტრიალება"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"მდებარეობა"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"ეკრანმზოგი"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"კამერაზე წვდომა"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"მიკროფონზე წვდომა"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"ხელმისაწვდომი"</string>
@@ -318,6 +320,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"განიბლოკა სახით. დააჭირეთ გასახსნელად."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"ამოცნობილია სახით. დააჭირეთ გასახსნელად."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"ამოცნობილია სახით. გასახსნელად დააჭირეთ განბლოკვის ხატულას."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"ხელახლა საცდელად გადაფურცლეთ ზემოთ"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"განბლოკეთ NFC-ის გამოსაყენებლად"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"ამ მოწყობილობას ფლობს თქვენი ორგანიზაცია"</string>
@@ -467,7 +473,7 @@
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"დააყენეთ შესყიდვების თქვენი ტელეფონით უფრო სწრაფად და უსაფრთხოდ შესასრულებლად"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"ყველას ჩვენება"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"ბარათის დამატება"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"შეეხეთ გასახსნელად"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"მიმდინარეობს განახლება"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"გამოსაყენებლად განბლოკვა"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"თქვენი ბარათების მიღებისას პრობლემა წარმოიშვა. ცადეთ ხელახლა მოგვიანებით"</string>
@@ -693,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"გაფრთხილებები"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"ბატარეა"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"ეკრანის ანაბეჭდები"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"ზოგადი შეტყობინებები"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"მეხსიერება"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"მინიშნებები"</string>
<string name="instant_apps" msgid="8337185853050247304">"მყისიერი აპები"</string>
@@ -727,6 +736,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"ჩაირთოს, როცა ბატარეა დაცლის პირას არის"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"არა, გმადლობთ"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"SysUI გროვის გამოტანა"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"გამოიყენება"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"აპლიკაციების მიერ გამოიყენება თქვენი <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" და "</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"მიიტანეთ უფრო ახლოს, რომ დაუკრათ <xliff:g id="DEVICENAME">%1$s</xliff:g>-ზე"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"მიუახლოვდით <xliff:g id="DEVICENAME">%1$s</xliff:g>-ს მისი მეშვეობით დასაკრავად"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"მიმდინარეობს დაკვრა <xliff:g id="DEVICENAME">%1$s</xliff:g>-ზე"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"მიმდინარეობს დაკვრა ამ ტელეფონზე"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"რაღაც შეცდომა მოხდა. ცადეთ ხელახლა."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"არააქტიურია, გადაამოწმეთ აპი"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"ვერ მოიძებნა"</string>
@@ -853,6 +862,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"შენახვა"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"იწყება…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"ტრანსლაცია შეუძლებელია"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"შენახვა ვერ ხერხდება. ცადეთ ხელახლა."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"შენახვა ვერ ხერხდება."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"ანაწყობის ნომერი"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"ანაწყობის ნომერი დაკოპირებულია გაცვლის ბუფერში."</string>
<string name="basic_status" msgid="2315371112182658176">"მიმოწერის გახსნა"</string>
@@ -937,6 +948,10 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"კოპირებული ტექსტის რედაქტირება"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"კოპირებული სურათის რედაქტირება"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"ახლომახლო მოწყობილობაზე გაგზავნა"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"შეეხეთ სანახავად"</string>
+ <string name="clipboard_text_copied" msgid="5100836834278976679">"ტექსტი დაკოპირდა"</string>
+ <string name="clipboard_image_copied" msgid="3793365360174328722">"სურათი დაკოპირდა"</string>
+ <string name="clipboard_content_copied" msgid="144452398567828145">"კონტენტი დაკოპირდა"</string>
<string name="add" msgid="81036585205287996">"დამატება"</string>
<string name="manage_users" msgid="1823875311934643849">"მომხმარებლების მართვა"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"ამ შეტყობინების გადათრევა გაყოფილ ეკრანებს შორის არ არის მხარდაჭერილი."</string>
@@ -945,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"მაღვიძარა დაყენებულია"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"კამერა და მიკროფონი გამორთულია"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# შეტყობინება}other{# შეტყობინება}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"იწყებთ მაუწყებლობას"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"გსურთ <xliff:g id="APP_NAME">%1$s</xliff:g>-ის ტრანსლაციის შეჩერება?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"<xliff:g id="SWITCHAPP">%1$s</xliff:g>-ის ტრანსლაციის შემთხვევაში ან აუდიოს გამოსასვლელის შეცვლისას, მიმდინარე ტრანსლაცია შეჩერდება"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g>-ის ტრანსლაცია"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"აუდიოს გამოსასვლელის შეცვლა"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"უცნობი"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ka/tiles_states_strings.xml b/packages/SystemUI/res/values-ka/tiles_states_strings.xml
index 0c7d5af..c951874 100644
--- a/packages/SystemUI/res/values-ka/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ka/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"გამორთვა"</item>
<item msgid="460891964396502657">"ჩართვა"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"მიუწვდომელია"</item>
+ <item msgid="8014986104355098744">"გამორთულია"</item>
+ <item msgid="5966994759929723339">"ჩართულია"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 2cce920..d93cd31 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Қайта скриншот жасап көріңіз"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"Скриншотты сақтау мүмкін емес."</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Қолданба немесе ұйым скриншоттар түсіруге рұқсат етпейді"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Әкімшіңіз скриншот жасауға тыйым салды."</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Өзгерту"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Скриншотты өзгерту"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"Скриншотты бөлісу"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Автоматты түрде бұру"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Автоматты айналатын экран"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Локация"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Скринсейвер"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Камераны пайдалану"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Микрофонды пайдалану"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Қолжетімді"</string>
@@ -318,6 +320,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Бетпен ашылды. Ашу үшін басыңыз."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Бет танылды. Ашу үшін басыңыз."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Бет танылды. Ашу үшін құлыпты ашу белгішесін басыңыз."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"Әрекетті қайталау үшін жоғары сырғытыңыз."</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC пайдалану үшін құлыпты ашыңыз."</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Бұл құрылғы ұйымыңызға тиесілі."</string>
@@ -467,7 +473,7 @@
<string name="wallet_title" msgid="5369767670735827105">"Әмиян"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"Телефоныңызбен бұрынғыдан да жылдам әрі қауіпсіз сатып алу үшін параметрлерді орнатыңыз."</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"Барлығын көрсету"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"Карта қосу"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"Ашу үшін түртіңіз"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"Жаңартылуда"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Пайдалану үшін құлыпты ашу"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Карталарыңыз алынбады, кейінірек қайталап көріңіз."</string>
@@ -693,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Ескертулер"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Батарея"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Скриншоттар"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Жалпы хабарлар"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"Жад"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Кеңестер"</string>
<string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string>
@@ -727,6 +736,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"Батареяның заряды бітуге жақындағанда қосыңыз."</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"Жоқ, рақмет"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"Қолданыста"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Қолданбаларда <xliff:g id="TYPES_LIST">%s</xliff:g> пайдаланылуда."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" және "</string>
@@ -804,7 +814,7 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Толығырақ ақпарат алу үшін сырғытыңыз."</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Жүктеуге қатысты ұсыныстар"</string>
<string name="controls_media_title" msgid="1746947284862928133">"Мультимедиа"</string>
- <string name="controls_media_close_session" msgid="4780485355795635052">"<xliff:g id="APP_NAME">%1$s</xliff:g> үшін медиамазмұн контроллері жасырылсын ба?"</string>
+ <string name="controls_media_close_session" msgid="4780485355795635052">"<xliff:g id="APP_NAME">%1$s</xliff:g> үшін медиа контроллері жасырылсын ба?"</string>
<string name="controls_media_active_session" msgid="3146882316024153337">"Ағымдағы мультимедиа сеансын жасыру мүмкін емес."</string>
<string name="controls_media_dismiss_button" msgid="4485675693008031646">"Жасыру"</string>
<string name="controls_media_resume" msgid="1933520684481586053">"Жалғастыру"</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g> құрылғысында музыка ойнату үшін оған жақындаңыз."</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Осы жерде ойнау үшін <xliff:g id="DEVICENAME">%1$s</xliff:g> құрылғысына жақындаңыз"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> құрылғысында ойнатылуда."</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Осы телефонда ойнатылуда."</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Бірдеңе дұрыс болмады. Қайталап көріңіз."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Өшірулі. Қолданба тексеріңіз."</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Табылмады"</string>
@@ -853,6 +862,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"Сақтау"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"Басталып жатыр…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"Тарату мүмкін емес"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Сақталмайды. Қайталап көріңіз."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Сақталмайды."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Құрама нөмірі"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Құрама нөмірі буферге көшірілді."</string>
<string name="basic_status" msgid="2315371112182658176">"Ашық әңгіме"</string>
@@ -937,6 +948,13 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Көшірілген мәтінді өңдеу"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Көшірілген суретті өңдеу"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Маңайдағы құрылғыға жіберу"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"Көру үшін түртіңіз."</string>
+ <!-- no translation found for clipboard_text_copied (5100836834278976679) -->
+ <skip />
+ <!-- no translation found for clipboard_image_copied (3793365360174328722) -->
+ <skip />
+ <!-- no translation found for clipboard_content_copied (144452398567828145) -->
+ <skip />
<string name="add" msgid="81036585205287996">"Қосу"</string>
<string name="manage_users" msgid="1823875311934643849">"Пайдаланушыларды басқару"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"Бұл хабарландыруды бөлінген экранға сүйреп апару мүмкін емес."</string>
@@ -945,4 +963,12 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Оятқыш орнатылды"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Камера мен микрофон өшірулі"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# хабарландыру}other{# хабарландыру}}"</string>
+ <!-- no translation found for broadcasting_description_is_broadcasting (765627502786404290) -->
+ <skip />
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасын таратуды тоқтатасыз ба?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> қолданбасын таратсаңыз немесе аудио шығысын өзгертсеңіз, қазіргі тарату сеансы тоқтайды."</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> қолданбасын тарату"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Аудио шығысын өзгерту"</string>
+ <!-- no translation found for bt_le_audio_broadcast_dialog_unknown_name (3791472237793443044) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-kk/tiles_states_strings.xml b/packages/SystemUI/res/values-kk/tiles_states_strings.xml
index 5466663..c312b49 100644
--- a/packages/SystemUI/res/values-kk/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-kk/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Өшірулі"</item>
<item msgid="460891964396502657">"Қосулы"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Қолжетімді емес."</item>
+ <item msgid="8014986104355098744">"Өшірулі."</item>
+ <item msgid="5966994759929723339">"Қосулы."</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 67d63a6..0d348a1 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"សាកល្បងថតរូបថតអេក្រង់ម្តងទៀត"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"មិនអាចរក្សាទុករូបថតអេក្រង់បានទេ"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"ការថតរូបអេក្រង់មិនត្រូវបានអនុញ្ញាតដោយកម្មវិធីនេះ ឬស្ថាប័នរបស់អ្នក"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"ការថតអេក្រង់ត្រូវបានទប់ស្កាត់ដោយអ្នកគ្រប់គ្រងផ្នែកព័ត៌មានវិទ្យារបស់អ្នក"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"កែ"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"កែរូបថតអេក្រង់"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"ចែករំលែករូបថតអេក្រង់"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"បង្វិលស្វ័យប្រវត្តិ"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"បង្វិលអេក្រង់ស្វ័យប្រវត្តិ"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"ទីតាំង"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"ធាតុរក្សាអេក្រង់"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"ការចូលប្រើកាមេរ៉ា"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"ការចូលប្រើមីក្រូហ្វូន"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"អាចចូលប្រើបាន"</string>
@@ -318,6 +320,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"បានដោះសោដោយប្រើមុខ។ សូមចុច ដើម្បីបើក។"</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"បានស្គាល់មុខ។ សូមចុច ដើម្បីបើក។"</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"បានស្គាល់មុខ។ សូមចុចរូបដោះសោ ដើម្បីបើក។"</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"អូសឡើងលើ ដើម្បីព្យាយាមម្ដងទៀត"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"ដោះសោ ដើម្បីប្រើ NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"ឧបករណ៍នេះគឺជាកម្មសិទ្ធិរបស់ស្ថាប័នអ្នក"</string>
@@ -467,7 +473,7 @@
<string name="wallet_title" msgid="5369767670735827105">"កាបូប"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"ធ្វើការរៀបចំ ដើម្បីធ្វើការទិញកាន់តែលឿនជាងមុន សុវត្ថិភាពជាងមុន ដោយប្រើទូរសព្ទរបស់អ្នក"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"បង្ហាញទាំងអស់"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"បញ្ចូលកាត"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"ចុចដើម្បីបើក"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"កំពុងធ្វើបច្ចុប្បន្នភាព"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ដោះសោដើម្បីប្រើប្រាស់"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"មានបញ្ហាក្នុងការទាញយកកាតរបស់អ្នក សូមព្យាយាមម្ដងទៀតនៅពេលក្រោយ"</string>
@@ -693,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"ការជូនដំណឹង"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"ថ្ម"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"រូបថតអេក្រង់"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"សារទូទៅ"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"ទំហំផ្ទុក"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"ការសម្រួល"</string>
<string name="instant_apps" msgid="8337185853050247304">"កម្មវិធីប្រើភ្លាមៗ"</string>
@@ -727,6 +736,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"បើកនៅពេលថ្មទំនងជាអស់"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"ទេ អរគុណ"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"កំពុងប្រើ"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"កម្មវិធីកំពុងប្រើ <xliff:g id="TYPES_LIST">%s</xliff:g> របស់អ្នក។"</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" និង "</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"រំកិលឱ្យកាន់តែជិត ដើម្បីចាក់នៅលើ <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"រំកិលឱ្យកាន់តែជិត <xliff:g id="DEVICENAME">%1$s</xliff:g> ដើម្បីចាក់នៅទីនេះ"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"កំពុងចាក់នៅលើ <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"កំពុងចាក់នៅលើទូរសព្ទនេះ"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"មានអ្វីមួយខុសប្រក្រតី។ សូមព្យាយាមម្ដងទៀត។"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"អសកម្ម ពិនិត្យមើលកម្មវិធី"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"រកមិនឃើញទេ"</string>
@@ -853,6 +862,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"រក្សាទុក"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"កំពុងចាប់ផ្ដើម…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"មិនអាចផ្សាយបានទេ"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"មិនអាចរក្សាទុកបានទេ។ សូមព្យាយាមម្ដងទៀត។"</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"មិនអាចរក្សាទុកបានទេ។"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"លេខកំណែបង្កើត"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"បានចម្លងលេខកំណែបង្កើតទៅឃ្លីបបត។"</string>
<string name="basic_status" msgid="2315371112182658176">"បើកការសន្ទនា"</string>
@@ -937,6 +948,13 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"កែអត្ថបទដែលបានចម្លង"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"កែរូបភាពដែលបានចម្លង"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"ផ្ញើទៅឧបករណ៍នៅជិត"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"ចុចដើម្បីមើល"</string>
+ <!-- no translation found for clipboard_text_copied (5100836834278976679) -->
+ <skip />
+ <!-- no translation found for clipboard_image_copied (3793365360174328722) -->
+ <skip />
+ <!-- no translation found for clipboard_content_copied (144452398567828145) -->
+ <skip />
<string name="add" msgid="81036585205287996">"បញ្ចូល"</string>
<string name="manage_users" msgid="1823875311934643849">"គ្រប់គ្រងអ្នកប្រើប្រាស់"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"ការជូនដំណឹងនេះមិនអាចឱ្យអូសដើម្បីបំបែកអេក្រង់បានទេ។"</string>
@@ -945,4 +963,12 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"រូបកំណត់ម៉ោងរោទ៍"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"កាមេរ៉ា និងមីក្រូហ្វូនត្រូវបានបិទ"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{ការជូនដំណឹង #}other{ការជូនដំណឹង #}}"</string>
+ <!-- no translation found for broadcasting_description_is_broadcasting (765627502786404290) -->
+ <skip />
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"បញ្ឈប់ការផ្សាយ <xliff:g id="APP_NAME">%1$s</xliff:g> ឬ?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"ប្រសិនបើអ្នកផ្សាយ <xliff:g id="SWITCHAPP">%1$s</xliff:g> ឬប្ដូរឧបករណ៍បញ្ចេញសំឡេង ការផ្សាយបច្ចុប្បន្នរបស់អ្នកនឹងបញ្ឈប់"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"ការផ្សាយ <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"ប្ដូរឧបករណ៍បញ្ចេញសំឡេង"</string>
+ <!-- no translation found for bt_le_audio_broadcast_dialog_unknown_name (3791472237793443044) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-km/tiles_states_strings.xml b/packages/SystemUI/res/values-km/tiles_states_strings.xml
index f4830f5..ec748cf 100644
--- a/packages/SystemUI/res/values-km/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-km/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"បិទ"</item>
<item msgid="460891964396502657">"បើក"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"មិនមានទេ"</item>
+ <item msgid="8014986104355098744">"បិទ"</item>
+ <item msgid="5966994759929723339">"បើក"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index e31ec39..981fc30 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"ಸ್ಕ್ರೀನ್ಶಾಟ್ ಅನ್ನು ಪುನಃ ತೆಗೆದುಕೊಳ್ಳಲು ಪ್ರಯತ್ನಿಸಿ"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"ಸ್ಕ್ರೀನ್ಶಾಟ್ ಉಳಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"ಅಪ್ಲಿಕೇಶನ್ ಅಥವಾ ಸಂಸ್ಥೆಯು ಸ್ಕ್ರೀನ್ಶಾಟ್ಗಳನ್ನು ತೆಗೆಯುವುದನ್ನು ಅನುಮತಿಸುವುದಿಲ್ಲ"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"ಸ್ಕ್ರೀನ್ಶಾಟ್ಗಳನ್ನು ತೆಗೆದುಕೊಳ್ಳುವುದನ್ನು ನಿಮ್ಮ IT ನಿರ್ವಾಹಕರು ನಿರ್ಬಂಧಿಸಿದ್ದಾರೆ"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"ಎಡಿಟ್ ಮಾಡಿ"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"ಸ್ಕ್ರೀನ್ಶಾಟ್ ಅನ್ನು ಎಡಿಟ್ ಮಾಡಿ"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"ಸ್ಕ್ರೀನ್ಶಾಟ್ ಅನ್ನು ಹಂಚಿಕೊಳ್ಳಿ"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"ಸ್ವಯಂ-ತಿರುಗುವಿಕೆ"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"ಪರದೆಯನ್ನು ಸ್ವಯಂ-ತಿರುಗಿಸಿ"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"ಸ್ಥಳ"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"ಸ್ಕ್ರೀನ್ ಸೇವರ್"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"ಕ್ಯಾಮರಾ ಆ್ಯಕ್ಸೆಸ್"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"ಮೈಕ್ ಆ್ಯಕ್ಸೆಸ್"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"ಲಭ್ಯವಿದೆ"</string>
@@ -318,6 +320,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"ಮುಖವನ್ನು ಬಳಸಿ ಅನ್ಲಾಕ್ ಮಾಡಲಾಗಿದೆ. ತೆರೆಯಲು ಒತ್ತಿ."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"ಮುಖ ಗುರುತಿಸಲಾಗಿದೆ. ತೆರೆಯಲು ಒತ್ತಿ."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"ಮುಖ ಗುರುತಿಸಲಾಗಿದೆ. ತೆರೆಯಲು ಅನ್ಲಾಕ್ ಐಕಾನ್ ಅನ್ನು ಒತ್ತಿ."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಲು ಮೇಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC ಬಳಸಲು ಅನ್ಲಾಕ್ ಮಾಡಿ"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"ಈ ಸಾಧನವು ನಿಮ್ಮ ಸಂಸ್ಥೆಗೆ ಸೇರಿದೆ"</string>
@@ -467,7 +473,7 @@
<string name="wallet_title" msgid="5369767670735827105">"ವಾಲೆಟ್"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"ನಿಮ್ಮ ಫೋನ್ ಮೂಲಕ ವೇಗವಾದ, ಹೆಚ್ಚು ಸುರಕ್ಷಿತ ಖರೀದಿಗಳನ್ನು ಮಾಡಲು ಸೆಟಪ್ ಮಾಡಿಕೊಳ್ಳಿ"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"ಎಲ್ಲವನ್ನೂ ತೋರಿಸಿ"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"ಕಾರ್ಡ್ ಅನ್ನು ಸೇರಿಸಿ"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"ತೆರೆಯಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"ಅಪ್ಡೇಟ್ ಮಾಡಲಾಗುತ್ತಿದೆ"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ಬಳಸಲು ಅನ್ಲಾಕ್ ಮಾಡಿ"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"ನಿಮ್ಮ ಕಾರ್ಡ್ಗಳನ್ನು ಪಡೆಯುವಾಗ ಸಮಸ್ಯೆ ಉಂಟಾಗಿದೆ, ನಂತರ ಪುನಃ ಪ್ರಯತ್ನಿಸಿ"</string>
@@ -693,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"ಅಲರ್ಟ್ಗಳು"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"ಬ್ಯಾಟರಿ"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"ಸ್ಕ್ರೀನ್ಶಾಟ್ಗಳು"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"ಸಾಮಾನ್ಯ ಸಂದೇಶಗಳು"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"ಸಂಗ್ರಹಣೆ"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"ಸುಳಿವುಗಳು"</string>
<string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string>
@@ -727,6 +736,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"ಬ್ಯಾಟರಿ ಖಾಲಿಯಾಗುವ ಸಾಧ್ಯತೆ ಇದ್ದಾಗ ಆನ್ ಮಾಡಿ"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"ಬೇಡ"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"ಬಳಕೆಯಲ್ಲಿದೆ"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"ನಿಮ್ಮ <xliff:g id="TYPES_LIST">%s</xliff:g> ಅನ್ನು ಆ್ಯಪ್ಗಳು ಬಳಸುತ್ತಿವೆ."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" ಮತ್ತು "</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g> ನಲ್ಲಿ ಪ್ಲೇ ಮಾಡಲು ಅದರ ಹತ್ತಿರಕ್ಕೆ ಸರಿಯಿರಿ"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"ಇಲ್ಲಿ ಪ್ಲೇ ಮಾಡಲು <xliff:g id="DEVICENAME">%1$s</xliff:g> ಸಮೀಪಕ್ಕೆ ಹೋಗಿ"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> ನಲ್ಲಿ ಪ್ಲೇ ಆಗುತ್ತಿದೆ"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"ಈ ಫೋನ್ನಲ್ಲಿ ಪ್ಲೇ ಆಗುತ್ತಿದೆ"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"ಏನೋ ತಪ್ಪಾಗಿದೆ. ಪುನಃ ಪ್ರಯತ್ನಿಸಿ."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"ನಿಷ್ಕ್ರಿಯ, ಆ್ಯಪ್ ಪರಿಶೀಲಿಸಿ"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"ಕಂಡುಬಂದಿಲ್ಲ"</string>
@@ -853,6 +862,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"ಉಳಿಸಿ"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"ಪ್ರಾರಂಭಿಸಲಾಗುತ್ತಿದೆ…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"ಪ್ರಸಾರ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"ಉಳಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ. ಪುನಃ ಪ್ರಯತ್ನಿಸಿ."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"ಉಳಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"ಬಿಲ್ಡ್ ಸಂಖ್ಯೆ"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"ಬಿಲ್ಡ್ ಸಂಖ್ಯೆಯನ್ನು ಕ್ಲಿಪ್ಬೋರ್ಡ್ನಲ್ಲಿ ನಕಲಿಸಲಾಗಿದೆ."</string>
<string name="basic_status" msgid="2315371112182658176">"ಸಂಭಾಷಣೆಯನ್ನು ತೆರೆಯಿರಿ"</string>
@@ -937,6 +948,13 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"ನಕಲಿಸಿದ ಪಠ್ಯವನ್ನು ಎಡಿಟ್ ಮಾಡಿ"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"ನಕಲಿಸಿದ ಚಿತ್ರವನ್ನು ಎಡಿಟ್ ಮಾಡಿ"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"ಸಮೀಪದಲ್ಲಿರುವ ಸಾಧನಕ್ಕೆ ಕಳುಹಿಸಿ"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"ವೀಕ್ಷಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
+ <!-- no translation found for clipboard_text_copied (5100836834278976679) -->
+ <skip />
+ <!-- no translation found for clipboard_image_copied (3793365360174328722) -->
+ <skip />
+ <!-- no translation found for clipboard_content_copied (144452398567828145) -->
+ <skip />
<string name="add" msgid="81036585205287996">"ಸೇರಿಸಿ"</string>
<string name="manage_users" msgid="1823875311934643849">"ಬಳಕೆದಾರರನ್ನು ನಿರ್ವಹಿಸಿ"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"ಸ್ಪ್ಲಿಟ್ ಸ್ಕ್ರೀನ್ಗೆ ಡ್ರ್ಯಾಗ್ ಮಾಡುವುದನ್ನು ಈ ಅಧಿಸೂಚನೆಯು ಬೆಂಬಲಿಸುವುದಿಲ್ಲ."</string>
@@ -945,4 +963,12 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"ಅಲಾರಾಂ ಹೊಂದಿಸಲಾಗಿದೆ"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"ಕ್ಯಾಮರಾ ಮತ್ತು ಮೈಕ್ ಆಫ್ ಆಗಿದೆ"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# ಅಧಿಸೂಚನೆ}one{# ಅಧಿಸೂಚನೆಗಳು}other{# ಅಧಿಸೂಚನೆಗಳು}}"</string>
+ <!-- no translation found for broadcasting_description_is_broadcasting (765627502786404290) -->
+ <skip />
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> ನ ಪ್ರಸಾರವನ್ನು ನಿಲ್ಲಿಸಬೇಕೆ?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"ನೀವು <xliff:g id="SWITCHAPP">%1$s</xliff:g> ಅನ್ನು ಪ್ರಸಾರ ಮಾಡಿದರೆ ಅಥವಾ ಔಟ್ಪುಟ್ ಅನ್ನು ಬದಲಾಯಿಸಿದರೆ, ನಿಮ್ಮ ಪ್ರಸ್ತುತ ಪ್ರಸಾರವು ಸ್ಥಗಿತಗೊಳ್ಳುತ್ತದೆ"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> ಅನ್ನು ಪ್ರಸಾರ ಮಾಡಿ"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"ಔಟ್ಪುಟ್ ಅನ್ನು ಬದಲಾಯಿಸಿ"</string>
+ <!-- no translation found for bt_le_audio_broadcast_dialog_unknown_name (3791472237793443044) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-kn/tiles_states_strings.xml b/packages/SystemUI/res/values-kn/tiles_states_strings.xml
index 5cf2f5c..864a607 100644
--- a/packages/SystemUI/res/values-kn/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-kn/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"ಆಫ್ ಮಾಡಿ"</item>
<item msgid="460891964396502657">"ಆನ್ ಮಾಡಿ"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"ಲಭ್ಯವಿಲ್ಲ"</item>
+ <item msgid="8014986104355098744">"ಆಫ್ ಮಾಡಿ"</item>
+ <item msgid="5966994759929723339">"ಆನ್ ಮಾಡಿ"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 70ddafd..e4c185c 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"스크린샷을 다시 찍어 보세요."</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"스크린샷을 저장할 수 없습니다."</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"앱이나 조직에서 스크린샷 촬영을 허용하지 않습니다."</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"IT 관리자가 스크린샷 촬영을 허용하지 않습니다."</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"수정"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"스크린샷 수정"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"스크린샷 공유"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"자동 회전"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"화면 자동 회전"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"위치"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"화면 보호기"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"카메라 액세스"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"마이크 액세스"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"사용 가능"</string>
@@ -318,6 +320,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"얼굴 인식으로 잠금 해제되었습니다. 열려면 누르세요."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"얼굴이 인식되었습니다. 열려면 누르세요."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"얼굴이 인식되었습니다. 열려면 잠금 해제 아이콘을 누르세요."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"위로 스와이프하여 다시 시도해 주세요"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"잠금 해제하여 NFC 사용"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"내 조직에 속한 기기입니다."</string>
@@ -467,7 +473,7 @@
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"설정하여 휴대전화로 더욱 빠르고 안전하게 구매하세요."</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"모두 표시"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"카드 추가"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"탭하여 열기"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"업데이트 중"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"잠금 해제하여 사용"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"카드를 가져오는 중에 문제가 발생했습니다. 나중에 다시 시도해 보세요."</string>
@@ -693,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"알림"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"배터리"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"스크린샷"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"일반 메시지"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"저장용량"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"힌트"</string>
<string name="instant_apps" msgid="8337185853050247304">"인스턴트 앱"</string>
@@ -727,6 +736,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"배터리가 소진될 것 같으면 사용 설정"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"사용 안함"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"사용 중"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"애플리케이션이 <xliff:g id="TYPES_LIST">%s</xliff:g>을(를) 사용 중입니다."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" 및 "</string>
@@ -804,7 +814,7 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"자세히 보려면 스와이프하세요."</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"추천 제어 기능 로드 중"</string>
<string name="controls_media_title" msgid="1746947284862928133">"미디어"</string>
- <string name="controls_media_close_session" msgid="4780485355795635052">"<xliff:g id="APP_NAME">%1$s</xliff:g>에서 이 미디어 컨트롤 숨기기"</string>
+ <string name="controls_media_close_session" msgid="4780485355795635052">"<xliff:g id="APP_NAME">%1$s</xliff:g>에 대한 미디어 컨트롤을 숨길까요?"</string>
<string name="controls_media_active_session" msgid="3146882316024153337">"현재 미디어 세션은 숨길 수 없습니다."</string>
<string name="controls_media_dismiss_button" msgid="4485675693008031646">"숨기기"</string>
<string name="controls_media_resume" msgid="1933520684481586053">"다시 시작"</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g>에서 재생하려면 기기를 더 가까이로 옮기세요."</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"현재 기기에서 재생하려면 <xliff:g id="DEVICENAME">%1$s</xliff:g>에 더 가까이 이동합니다."</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g>에서 재생 중"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"휴대전화에서 재생 중"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"문제가 발생했습니다. 다시 시도해 주세요."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"비활성. 앱을 확인하세요."</string>
<string name="controls_error_removed" msgid="6675638069846014366">"찾을 수 없음"</string>
@@ -853,6 +862,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"저장"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"시작 중…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"방송할 수 없음"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"저장할 수 없습니다. 다시 시도해 주세요."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"저장할 수 없습니다."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"빌드 번호"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"빌드 번호가 클립보드에 복사되었습니다."</string>
<string name="basic_status" msgid="2315371112182658176">"대화 열기"</string>
@@ -937,6 +948,13 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"복사된 텍스트 편집"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"복사된 이미지 편집"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"근처 기기에 전송"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"탭하여 보기"</string>
+ <!-- no translation found for clipboard_text_copied (5100836834278976679) -->
+ <skip />
+ <!-- no translation found for clipboard_image_copied (3793365360174328722) -->
+ <skip />
+ <!-- no translation found for clipboard_content_copied (144452398567828145) -->
+ <skip />
<string name="add" msgid="81036585205287996">"추가"</string>
<string name="manage_users" msgid="1823875311934643849">"사용자 관리"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"드래그하여 화면을 분할하는 기능이 지원되지 않는 알림입니다."</string>
@@ -945,4 +963,12 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"알람이 설정되었습니다."</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"카메라 및 마이크가 사용 중지되었습니다."</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{알림 #개}other{알림 #개}}"</string>
+ <!-- no translation found for broadcasting_description_is_broadcasting (765627502786404290) -->
+ <skip />
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> 방송을 중지하시겠습니까?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> 앱을 방송하거나 출력을 변경하면 기존 방송이 중단됩니다"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> 방송"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"출력 변경"</string>
+ <!-- no translation found for bt_le_audio_broadcast_dialog_unknown_name (3791472237793443044) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ko/tiles_states_strings.xml b/packages/SystemUI/res/values-ko/tiles_states_strings.xml
index 3244ffa..c52c17c 100644
--- a/packages/SystemUI/res/values-ko/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ko/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"꺼짐"</item>
<item msgid="460891964396502657">"켜짐"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"사용 불가"</item>
+ <item msgid="8014986104355098744">"꺼짐"</item>
+ <item msgid="5966994759929723339">"켜짐"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index d5ee215..d46bc5d 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Скриншотту кайра тартып көрүңүз"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"Скриншот сакталган жок"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Скриншот тартууга колдонмо же ишканаңыз тыюу салган."</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"IT администраторуңуз скриншот тартууга тыюу салган"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Түзөтүү"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Скриншотту түзөтүү"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"Скриншотту бөлүшүү"</string>
@@ -126,7 +127,7 @@
<string name="phone_label" msgid="5715229948920451352">"телефонду ачуу"</string>
<string name="voice_assist_label" msgid="3725967093735929020">"үн жардамчысысын ачуу"</string>
<string name="camera_label" msgid="8253821920931143699">"камераны ачуу"</string>
- <string name="cancel" msgid="1089011503403416730">"Жокко чыгаруу"</string>
+ <string name="cancel" msgid="1089011503403416730">"Жок"</string>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"Ырастоо"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"Кайталоо"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"Аныктыгын текшерүүнү жокко чыгаруу үчүн таптаңыз"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Авто буруу"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Экранды авто буруу"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Жайгашкан жер"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Көшөгө"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Камера"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Микрофон"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Жеткиликтүү"</string>
@@ -245,7 +247,7 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Жарыктыгы"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Түстөрдү инверсиялоо"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Түстөрдү тууралоо"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Колдонуучунун жөндөөлөрү"</string>
+ <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Колдонуучунун параметрлери"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Бүттү"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Жабуу"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"Туташкан"</string>
@@ -318,6 +320,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Кулпусун жүзүңүз менен ачтыңыз. Ачуу үчүн басыңыз."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Жүз таанылды. Ачуу үчүн басыңыз."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Жүз таанылды. Ачуу үчүн кулпусун ачуу сүрөтчөсүн басыңыз."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"Кайталоо үчүн экранды өйдө сүрүңүз"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC колдонуу үчүн түзмөктүн кулпусун ачыңыз"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Бул түзмөк уюмуңузга таандык"</string>
@@ -339,14 +345,14 @@
<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>
<string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<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="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Бул сеанстагы бардык колдонмолор жана маалыматтар өчүрүлөт."</string>
+ <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Бул сеанстагы бардык колдонмолор жана аларга байланыштуу нерселер өчүрүлөт."</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Кайтып келишиңиз менен!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Сеансыңызды улантасызбы?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Кайра баштоо"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Ооба, уланта берели"</string>
<string name="guest_notification_app_name" msgid="2110425506754205509">"Конок режими"</string>
<string name="guest_notification_session_active" msgid="5567273684713471450">"Конок режиминдесиз"</string>
- <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Жаңы колдонуучуну кошсоңуз, конок режими жабылат жана учурдагы конок сеансындагы бардык колдонмолор жана дайындар өчүрүлөт."</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Жаңы колдонуучуну кошсоңуз, конок режими жабылып, учурдагы конок сеансындагы бардык колдонмолор жана башка нерселер өчүп калат."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"Дагы колдонуучу кошууга болбойт"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="other"><xliff:g id="COUNT">%d</xliff:g> колдонуучуга чейин кошууга болот.</item>
@@ -467,7 +473,7 @@
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"Телефонуңуз менен тез жана коопсуз сатып алуу үчүн жөндөңүз"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"Баарын көрсөтүү"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"Картаны кошуу"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"Ачуу үчүн таптап коюңуз"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"Жаңырууда"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Колдонуу үчүн кулпусун ачыңыз"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Кыйытмаларды алууда ката кетти. Бир аздан кийин кайталап көрүңүз."</string>
@@ -527,7 +533,7 @@
<string name="feedback_prompt" msgid="3656728972307896379">"Иштеп чыгуучуга пикириңизди билдириңиз. Бул туурабы?"</string>
<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_more_settings" msgid="4936228656989201793">"Дагы параметрлер"</string>
<string name="notification_app_settings" msgid="8963648463858039377">"Ыңгайлаштыруу"</string>
<string name="notification_conversation_bubble" msgid="2242180995373949022">"Калкып чыкма билдирмени көрсөтүү"</string>
<string name="notification_conversation_unbubble" msgid="6908427185031099868">"Калкып чыкма билдирмелерди алып салуу"</string>
@@ -693,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Эскертүүлөр"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Батарея"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Скриншоттор"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Жалпы билдирүүлөр"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"Сактагыч"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Кеңештер"</string>
<string name="instant_apps" msgid="8337185853050247304">"Ыкчам ачылуучу колдонмолор"</string>
@@ -727,6 +736,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"Батареянын кубаты түгөнүп калганда, күйгүзүлсүн"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"Жок, рахмат"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"Колдонулууда"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Колдонмолор төмөнкүлөрдү пайдаланып жатышат: <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" жана "</string>
@@ -804,7 +814,7 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Дагы көрүү үчүн экранды сүрүп коюңуз"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Сунуштар жүктөлүүдө"</string>
<string name="controls_media_title" msgid="1746947284862928133">"Медиа"</string>
- <string name="controls_media_close_session" msgid="4780485355795635052">"<xliff:g id="APP_NAME">%1$s</xliff:g> үчүн бул медиафайлдарды башкаруу жашырылсынбы?"</string>
+ <string name="controls_media_close_session" msgid="4780485355795635052">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосунда ушул нерсени жашырасызбы?"</string>
<string name="controls_media_active_session" msgid="3146882316024153337">"Учурдагы медиа сеансын жашыруу мүмкүн эмес."</string>
<string name="controls_media_dismiss_button" msgid="4485675693008031646">"Жашыруу"</string>
<string name="controls_media_resume" msgid="1933520684481586053">"Улантуу"</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g> түзмөгүндө ойнотуу үчүн жакыныраак жылдырыңыз"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Бул жерде ойнотуу үчүн <xliff:g id="DEVICENAME">%1$s</xliff:g> түзмөгүнө жакындатыңыз"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> аркылуу ойнотулууда"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Ушул телефондо ойнотулууда"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Бир жерден ката кетти. Кайра аракет кылыңыз."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Жигерсиз. Колдонмону текшериңиз"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Табылган жок"</string>
@@ -853,6 +862,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"Сактоо"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"Кабарлап баштады…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"Кабарлоого болбойт"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Сакталган жок. Кайталап көрүңүз."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Сакталган жок."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Курама номери"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Курама номери алмашуу буферине көчүрүлдү."</string>
<string name="basic_status" msgid="2315371112182658176">"Ачык сүйлөшүү"</string>
@@ -927,7 +938,7 @@
</plurals>
<string name="fgs_dot_content_description" msgid="2865071539464777240">"Жаңы маалымат"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Жигердүү колдонмолор"</string>
- <string name="fgs_manager_dialog_message" msgid="6839542063522121108">"Бул колдонмолорду пайдаланбасаңыз да, алар иштеп, батареянын кубатынын мөөнөтүн азайтып жатышы мүмкүн"</string>
+ <string name="fgs_manager_dialog_message" msgid="6839542063522121108">"Бул колдонмолорду колдонбосоңуз да, алар иштей берип, батареяны тез отургузуп салышы мүмкүн"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Токтотуу"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Токтотулду"</string>
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Бүттү"</string>
@@ -937,6 +948,13 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Көчүрүлгөн текстти түзөтүү"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Көчүрүлгөн сүрөттү түзөтүү"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Жакын жердеги түзмөккө жөнөтүү"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"Көрүү үчүн таптаңыз"</string>
+ <!-- no translation found for clipboard_text_copied (5100836834278976679) -->
+ <skip />
+ <!-- no translation found for clipboard_image_copied (3793365360174328722) -->
+ <skip />
+ <!-- no translation found for clipboard_content_copied (144452398567828145) -->
+ <skip />
<string name="add" msgid="81036585205287996">"Кошуу"</string>
<string name="manage_users" msgid="1823875311934643849">"Колдонуучуларды башкаруу"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"Бул билдирмени бөлүнгөн экранда сүйрөөгө болбойт."</string>
@@ -945,4 +963,12 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Ойготкуч коюлду"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Камера жана микрофон өчүк"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# билдирме}other{# билдирме}}"</string>
+ <!-- no translation found for broadcasting_description_is_broadcasting (765627502786404290) -->
+ <skip />
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосунда кабарлоо токтотулсунбу?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Эгер <xliff:g id="SWITCHAPP">%1$s</xliff:g> колдонмосунда кабарласаңыз же аудионун чыгуусун өзгөртсөңүз, учурдагы кабарлоо токтотулат"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> колдонмосунда кабарлоо"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Аудионун чыгуусун өзгөртүү"</string>
+ <!-- no translation found for bt_le_audio_broadcast_dialog_unknown_name (3791472237793443044) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ky/tiles_states_strings.xml b/packages/SystemUI/res/values-ky/tiles_states_strings.xml
index 5518fcc..f872926 100644
--- a/packages/SystemUI/res/values-ky/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ky/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Өчүк"</item>
<item msgid="460891964396502657">"Күйүк"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Жеткиликсиз"</item>
+ <item msgid="8014986104355098744">"Өчүк"</item>
+ <item msgid="5966994759929723339">"Күйүк"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 89aa96dc..875bdd7 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"ກະລຸນາລອງຖ່າຍຮູບໜ້າຈໍອີກຄັ້ງ"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"ບໍ່ສາມາດບັນທຶກຮູບໜ້າຈໍໄດ້"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"ແອັບ ຫຼື ອົງກອນຂອງທ່ານບໍ່ອະນຸຍາດໃຫ້ຖ່າຍຮູບໜ້າຈໍ"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"ຜູ້ເບິ່ງແຍງໄອທີຂອງທ່ານບລັອກການຖ່າຍຮູບໜ້າຈໍໄວ້."</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"ແກ້ໄຂ"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"ແກ້ໄຂຮູບໜ້າຈໍ"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"ແບ່ງປັນຮູບໜ້າຈໍ"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"ໝຸນອັດຕະໂນມັດ"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"ໝຸນໜ້າຈໍອັດຕະໂນມັດ"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"ສະຖານທີ່"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"ພາບພັກໜ້າຈໍ"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"ການເຂົ້າເຖິງກ້ອງຖ່າຍຮູບ"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"ການເຂົ້າເຖິງໄມ"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"ສາມາດໃຊ້ໄດ້"</string>
@@ -318,6 +320,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"ປົດລັອກດ້ວຍໜ້າແລ້ວ. ກົດເພື່ອເປີດ."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"ຈຳແນກໜ້າໄດ້ແລ້ວ. ກົດເພື່ອເປີດ."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"ຈຳແນກໜ້າໄດ້ແລ້ວ. ກົດໄອຄອນປົດລັອກເພື່ອເປີດ."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"ປັດຂຶ້ນເພື່ອລອງໃໝ່"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"ປົດລັອກເພື່ອໃຊ້ NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"ອຸປະກອນນີ້ເປັນຂອງອົງການທ່ານ"</string>
@@ -346,7 +352,7 @@
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"ຕົກລົງ, ດຳເນີນການຕໍ່"</string>
<string name="guest_notification_app_name" msgid="2110425506754205509">"ໂໝດແຂກ"</string>
<string name="guest_notification_session_active" msgid="5567273684713471450">"ທ່ານກຳລັງຢູ່ໃນໂໝດແຂກ"</string>
- <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"ການເພີ່ມຜູ້ໃຊ້ໃໝ່ຈະອອກຈາກໂໝດແຂກ ແລະ ລຶບແອັບ ແລະ ຂໍ້ມູນທັງໝົດອອກຈາກໄລຍະເວລາຂອງແຂກປັດຈຸບັນ."</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"ການເພີ່ມຜູ້ໃຊ້ໃໝ່ຈະອອກຈາກໂໝດແຂກ ແລະ ລຶບແອັບ ແລະ ຂໍ້ມູນທັງໝົດອອກຈາກເຊດຊັນແຂກປັດຈຸບັນ."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"ຮອດຂີດຈຳກັດຜູ້ໃຊ້ແລ້ວ"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="other">ທ່ານສາມາດເພີ່ມໄດ້ສູງສຸດ <xliff:g id="COUNT">%d</xliff:g> ຄົນ.</item>
@@ -467,7 +473,7 @@
<string name="wallet_title" msgid="5369767670735827105">"ກະເປົາ"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"ຕັ້ງຄ່າເພື່ອຊື້ດ້ວຍໂທລະສັບຂອງທ່ານໄດ້ໄວຂຶ້ນ ແລະ ປອດໄພຂຶ້ນ"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"ສະແດງທັງໝົດ"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"ເພີ່ມບັດ"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"ແຕະເພື່ອເປີດ"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"ກຳລັງອັບເດດ"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ປົດລັອກເພື່ອໃຊ້"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"ເກີດບັນຫາໃນການໂຫຼດບັດຂອງທ່ານ, ກະລຸນາລອງໃໝ່ໃນພາຍຫຼັງ"</string>
@@ -693,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"ການແຈ້ງເຕືອນ"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"ແບັດເຕີຣີ"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"ຮູບຖ່າຍໜ້າຈໍ"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"ຂໍ້ຄວາມທົ່ວໄປ"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"ບ່ອນເກັບຂໍ້ມູນ"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"ຄຳໃບ້"</string>
<string name="instant_apps" msgid="8337185853050247304">"ອິນສະແຕນແອັບ"</string>
@@ -727,6 +736,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"ເປີດໃຊ້ເມື່ອແບັດເຕີຣີໜ້າຈະໃກ້ໝົດ"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"ບໍ່, ຂອບໃຈ"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"ກຳລັງນຳໃຊ້ຢູ່"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"ແອັບພລິເຄຊັນກຳລັງໃຊ້ <xliff:g id="TYPES_LIST">%s</xliff:g> ຂອງທ່ານ."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" ແລະ "</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"ຍ້າຍໄປໃກ້ຂຶ້ນເພື່ອຫຼິ້ນຢູ່ <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"ກະລຸນາຍ້າຍເຂົ້າໃກ້ <xliff:g id="DEVICENAME">%1$s</xliff:g> ເພື່ອຫຼິ້ນຢູ່ບ່ອນນີ້"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"ກຳລັງຫຼິ້ນຢູ່ <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"ກຳລັງຫຼິ້ນຢູ່ໂທລະສັບນີ້"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"ມີບາງຢ່າງຜິດພາດເກີດຂຶ້ນ. ກະລຸນາລອງໃໝ່."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"ບໍ່ເຮັດວຽກ, ກະລຸນາກວດສອບແອັບ"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"ບໍ່ພົບ"</string>
@@ -853,6 +862,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"ບັນທຶກ"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"ກໍາລັງເລີ່ມ…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"ບໍ່ສາມາດອອກອາກາດໄດ້"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"ບໍ່ສາມາດບັນທຶກໄດ້. ກະລຸນາລອງໃໝ່."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"ບໍ່ສາມາດບັນທຶກໄດ້."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"ໝາຍເລກສ້າງ"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"ສຳເນົາໝາຍເລກສ້າງໄປໃສ່ຄລິບບອດແລ້ວ."</string>
<string name="basic_status" msgid="2315371112182658176">"ເປີດການສົນທະນາ"</string>
@@ -937,6 +948,13 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"ແກ້ໄຂຂໍ້ຄວາມທີ່ສຳເນົາແລ້ວ"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"ແກ້ໄຂຮູບທີ່ສຳເນົາແລ້ວ"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"ສົ່ງໄປຫາອຸປະກອນທີ່ຢູ່ໃກ້ຄຽງ"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"ແຕະເພື່ອເບິ່ງ"</string>
+ <!-- no translation found for clipboard_text_copied (5100836834278976679) -->
+ <skip />
+ <!-- no translation found for clipboard_image_copied (3793365360174328722) -->
+ <skip />
+ <!-- no translation found for clipboard_content_copied (144452398567828145) -->
+ <skip />
<string name="add" msgid="81036585205287996">"ເພີ່ມ"</string>
<string name="manage_users" msgid="1823875311934643849">"ຈັດການຜູ້ໃຊ້"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"ການແຈ້ງເຕືອນນີ້ບໍ່ຮອງຮັບການລາກໄປໃສ່ Splitscreen."</string>
@@ -945,4 +963,12 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"ຕັ້ງໂມງປຸກແລ້ວ"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"ປິດກ້ອງຖ່າຍຮູບ ແລະ ໄມແລ້ວ"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# ການແຈ້ງເຕືອນ}other{# ການແຈ້ງເຕືອນ}}"</string>
+ <!-- no translation found for broadcasting_description_is_broadcasting (765627502786404290) -->
+ <skip />
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"ຢຸດການອອກອາກາດ <xliff:g id="APP_NAME">%1$s</xliff:g> ບໍ?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"ຫາກທ່ານອອກອາກາດ <xliff:g id="SWITCHAPP">%1$s</xliff:g> ຫຼື ປ່ຽນເອົ້າພຸດ, ການອອກອາກາດປັດຈຸບັນຂອງທ່ານຈະຢຸດ"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"ອອກອາກາດ <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"ປ່ຽນເອົ້າພຸດ"</string>
+ <!-- no translation found for bt_le_audio_broadcast_dialog_unknown_name (3791472237793443044) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-lo/tiles_states_strings.xml b/packages/SystemUI/res/values-lo/tiles_states_strings.xml
index c6b7e6c..6ae37e4 100644
--- a/packages/SystemUI/res/values-lo/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-lo/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"ປິດ"</item>
<item msgid="460891964396502657">"ເປີດ"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"ບໍ່ສາມາດໃຊ້ໄດ້"</item>
+ <item msgid="8014986104355098744">"ປິດ"</item>
+ <item msgid="5966994759929723339">"ເປີດ"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 6f33d3f..6107492 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Pabandykite padaryti ekrano kopiją dar kartą"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"Ekrano kopijos išsaugoti nepavyko"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Jūsų organizacijoje arba naudojant šią programą neleidžiama daryti ekrano kopijų"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Jūsų IT administratorius užblokavo galimybę daryti ekrano kopijas."</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Redaguoti"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Redaguoti ekrano kopiją"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"Bendrinti ekrano kopiją"</string>
@@ -227,6 +228,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automatinis pasukimas"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Automatiškai sukti ekraną"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Vietovė"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Ekrano užsklanda"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Prieiga prie fotoaparato"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Prieiga prie mikrofono"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Pasiekiama"</string>
@@ -322,6 +324,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Atrakinta pagal veidą. Paspauskite, kad atidarytumėte."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Veidas atpažintas. Paspauskite, kad atidarytumėte."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Veidas atpažintas. Atidarykite paspaudę atrakin. piktogramą."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"Jei norite bandyti dar kartą, perbraukite aukštyn"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Norėdami naudoti NFC, atrakinkite"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Šis įrenginys priklauso jūsų organizacijai"</string>
@@ -473,7 +479,7 @@
<string name="wallet_title" msgid="5369767670735827105">"Piniginė"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"Nustatykite, kad galėtumėte greičiau ir saugiau pirkti telefonu"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"Rodyti viską"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"Pridėti kortelę"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"Palieskite, kad atidarytumėte"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"Atnaujinama"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Atrakinti, kad būtų galima naudoti"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Gaunant korteles kilo problema, bandykite dar kartą vėliau"</string>
@@ -703,7 +709,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Įspėjimai"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Akumuliatorius"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Ekrano kopijos"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Bendrieji pranešimai"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"Saugykla"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Užuominos"</string>
<string name="instant_apps" msgid="8337185853050247304">"Akimirksniu įkeliamos programos"</string>
@@ -737,6 +746,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"Įjunkite, jei akumuliatorius gali greitai išsekti"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"Ne, ačiū"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Pat. „SysUI“ krūvą"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"Naudojama"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Programos naudoja: <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" ir "</string>
@@ -836,7 +846,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Prieikite arčiau, kad galėtumėte leisti įrenginyje „<xliff:g id="DEVICENAME">%1$s</xliff:g>“"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Perkelkite arčiau „<xliff:g id="DEVICENAME">%1$s</xliff:g>“, kad būtų galima leisti čia"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Leidžiama įrenginyje „<xliff:g id="DEVICENAME">%1$s</xliff:g>“"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Leidžiama šiame telefone"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Kažkas ne taip. Bandykite dar kartą."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Neaktyvu, patikrinkite progr."</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Nerasta"</string>
@@ -865,6 +874,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"Išsaugoti"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"Pradedama…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"Nepavyko transliuoti"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Nepavyko išsaugoti. Bandykite dar kartą."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Nepavyko išsaugoti."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Versijos numeris"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Versijos numeris nukopijuotas į iškarpinę."</string>
<string name="basic_status" msgid="2315371112182658176">"Atidaryti pokalbį"</string>
@@ -951,6 +962,13 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Redaguoti nukopijuotą tekstą"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Redaguoti nukopijuotą vaizdą"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Siųsti į įrenginį netoliese"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"Palieskite ir peržiūrėkite"</string>
+ <!-- no translation found for clipboard_text_copied (5100836834278976679) -->
+ <skip />
+ <!-- no translation found for clipboard_image_copied (3793365360174328722) -->
+ <skip />
+ <!-- no translation found for clipboard_content_copied (144452398567828145) -->
+ <skip />
<string name="add" msgid="81036585205287996">"Pridėti"</string>
<string name="manage_users" msgid="1823875311934643849">"Tvarkyti naudotojus"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"Šio pranešimo vilkimas išskaidyto ekrano režimu nepalaikomas."</string>
@@ -959,4 +977,12 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Signalas nustatytas"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Vaizdo kamera ir mikrofonas išjungti"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# pranešimas}one{# pranešimas}few{# pranešimai}many{# pranešimo}other{# pranešimų}}"</string>
+ <!-- no translation found for broadcasting_description_is_broadcasting (765627502786404290) -->
+ <skip />
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Sustabdyti „<xliff:g id="APP_NAME">%1$s</xliff:g>“ transliaciją?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Jei transliuosite „<xliff:g id="SWITCHAPP">%1$s</xliff:g>“ arba pakeisite išvestį, dabartinė transliacija bus sustabdyta"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Transliuoti „<xliff:g id="SWITCHAPP">%1$s</xliff:g>“"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Keisti išvestį"</string>
+ <!-- no translation found for bt_le_audio_broadcast_dialog_unknown_name (3791472237793443044) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-lt/tiles_states_strings.xml b/packages/SystemUI/res/values-lt/tiles_states_strings.xml
index 3e289e1..03d98c4 100644
--- a/packages/SystemUI/res/values-lt/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-lt/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Išjungta"</item>
<item msgid="460891964396502657">"Įjungta"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Nepasiekiama"</item>
+ <item msgid="8014986104355098744">"Išjungta"</item>
+ <item msgid="5966994759929723339">"Įjungta"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 5bb3b56..a44c2a5 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Mēģiniet izveidot jaunu ekrānuzņēmumu."</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"Nevar saglabāt ekrānuzņēmumu"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Lietotne vai jūsu organizācija neatļauj veikt ekrānuzņēmumus."</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Jūsu IT administrators ir bloķējis ekrānuzņēmumu izveidi"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Rediģēt"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Rediģēt ekrānuzņēmumu"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"Kopīgot ekrānuzņēmumu"</string>
@@ -226,6 +227,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automātiska pagriešana"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Automātiska ekrāna pagriešana"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Atrašanās vieta"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Ekrānsaudzētājs"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Kamera"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Mikrofons"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Piekļuve atļauta"</string>
@@ -320,6 +322,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Ierīce atbloķēta ar seju. Nospiediet, lai atvērtu."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Seja atpazīta. Nospiediet, lai atvērtu."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Seja atpazīta. Lai atvērtu, nospiediet atbloķēšanas ikonu."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"Velciet augšup, lai mēģinātu vēlreiz"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Atbloķējiet ierīci, lai izmantotu NFC."</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Šī ierīce pieder jūsu organizācijai."</string>
@@ -470,7 +476,7 @@
<string name="wallet_title" msgid="5369767670735827105">"Maks"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"Iestatiet, lai ātrāk un drošāk veiktu pirkumus, izmantojot tālruni"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"Rādīt visu"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"Pievienojiet karti"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"Pieskarieties, lai atvērtu"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"Notiek atjaunināšana"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Lai izmantotu, atbloķējiet ekrānu"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Ienesot jūsu kartes, radās problēma. Lūdzu, vēlāk mēģiniet vēlreiz."</string>
@@ -698,7 +704,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Brīdinājumi"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Akumulators"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Ekrānuzņēmumi"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Vispārīgi ziņojumi"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"Krātuve"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Padomi"</string>
<string name="instant_apps" msgid="8337185853050247304">"Tūlītējās lietotnes"</string>
@@ -732,6 +741,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"Ieslēgt, ja akumulators var izlādēties"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"Nē, paldies"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"Pašlaik izmanto"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Lietojumprogrammas izmanto šādas funkcijas: <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" un "</string>
@@ -830,7 +840,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Pārvietojiet savu ierīci tuvāk, lai atskaņotu mūziku ierīcē “<xliff:g id="DEVICENAME">%1$s</xliff:g>”."</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Pārvietojieties tuvāk ierīcei “<xliff:g id="DEVICENAME">%1$s</xliff:g>”, lai atskaņotu šeit"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Notiek atskaņošana ierīcē <xliff:g id="DEVICENAME">%1$s</xliff:g>."</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Notiek atskaņošana šajā tālrunī"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Radās kļūda. Mēģiniet vēlreiz."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Neaktīva, pārbaudiet lietotni"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Netika atrasta"</string>
@@ -859,6 +868,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"Saglabāt"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"Notiek palaišana…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"Nevar apraidīt"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Nevar saglabāt. Mēģiniet vēlreiz."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Nevar saglabāt."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Versijas numurs"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Versijas numurs ir kopēts starpliktuvē."</string>
<string name="basic_status" msgid="2315371112182658176">"Atvērt sarunu"</string>
@@ -944,6 +955,13 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Rediģēt nokopēto tekstu"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Rediģēt nokopēto attēlu"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Sūtīt uz tuvumā esošu ierīci"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"Pieskarieties, lai skatītu"</string>
+ <!-- no translation found for clipboard_text_copied (5100836834278976679) -->
+ <skip />
+ <!-- no translation found for clipboard_image_copied (3793365360174328722) -->
+ <skip />
+ <!-- no translation found for clipboard_content_copied (144452398567828145) -->
+ <skip />
<string name="add" msgid="81036585205287996">"Pievienot"</string>
<string name="manage_users" msgid="1823875311934643849">"Pārvaldīt lietotājus"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"Šis paziņojums neatbalsta vilkšanu uz dalīto ekrānu."</string>
@@ -952,4 +970,12 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Signāls ir iestatīts"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera un mikrofons ir izslēgti"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# paziņojums}zero{# paziņojumu}one{# paziņojums}other{# paziņojumi}}"</string>
+ <!-- no translation found for broadcasting_description_is_broadcasting (765627502786404290) -->
+ <skip />
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Vai apturēt lietotnes <xliff:g id="APP_NAME">%1$s</xliff:g> apraidīšanu?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Ja sāksiet lietotnes <xliff:g id="SWITCHAPP">%1$s</xliff:g> apraidīšanu vai mainīsiet izvadi, pašreizējā apraide tiks apturēta"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Lietotnes <xliff:g id="SWITCHAPP">%1$s</xliff:g> apraide"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Izvades maiņa"</string>
+ <!-- no translation found for bt_le_audio_broadcast_dialog_unknown_name (3791472237793443044) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-lv/tiles_states_strings.xml b/packages/SystemUI/res/values-lv/tiles_states_strings.xml
index eb210c2..6e9264d 100644
--- a/packages/SystemUI/res/values-lv/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-lv/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Izslēgts"</item>
<item msgid="460891964396502657">"Ieslēgts"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Nav pieejams"</item>
+ <item msgid="8014986104355098744">"Izslēgts"</item>
+ <item msgid="5966994759929723339">"Ieslēgts"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 4f5da0b..0716ad7 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Повторно обидете се да направите слика од екранот"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"Не може да се зачува слика од екранот"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Апликацијата или вашата организација не дозволува снимање слики од екранот"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Зачувувањето слики од екранот е блокирано од IT-администраторот"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Измени"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Изменете ја сликата од екранот"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"Споделете слика од екранот"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Автоматско ротирање"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Автоматско ротирање на екранот"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Локација"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Заштитник на екран"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Пристап до камерата"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Пристап до микрофонот"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Дозволен"</string>
@@ -318,6 +320,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Отклучено со лице. Притиснете за да отворите."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Лицето е препознаено. Притиснете за да отворите."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Лицето е препознаено. Притиснете ја иконата за отклучување за да отворите."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"Повлечете нагоре за да се обидете повторно"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Отклучете за да користите NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Уредов е во сопственост на организацијата"</string>
@@ -467,7 +473,7 @@
<string name="wallet_title" msgid="5369767670735827105">"Паричник"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"Поставете за да купувате побрзо и побезбедно преку вашиот телефон"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"Прикажи ги сите"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"Додајте картичка"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"Допрете за да отворите"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"Се ажурира"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Отклучете за да користите"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Имаше проблем при преземањето на картичките. Обидете се повторно подоцна"</string>
@@ -693,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Известувања"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Батерија"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Слики од екранот"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Општи пораки"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"Капацитет"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Совети"</string>
<string name="instant_apps" msgid="8337185853050247304">"Инстант апликации"</string>
@@ -727,6 +736,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"Вклучи ако е веројатно дека батеријата ќе се испразни"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"Не, фала"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Извади SysUI-слика"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"Во употреба"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Апликациите користат <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" и "</string>
@@ -804,7 +814,7 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Повлечете за да видите повеќе"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Се вчитуваат препораки"</string>
<string name="controls_media_title" msgid="1746947284862928133">"Аудиовизуелни содржини"</string>
- <string name="controls_media_close_session" msgid="4780485355795635052">"Да се сокрие контролоров за аудиовизуелни содржини за <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="controls_media_close_session" msgid="4780485355795635052">"Да се сокријат контролите за <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="controls_media_active_session" msgid="3146882316024153337">"Аудиовизуелнава сесија не може да се сокрие."</string>
<string name="controls_media_dismiss_button" msgid="4485675693008031646">"Сокриј"</string>
<string name="controls_media_resume" msgid="1933520684481586053">"Продолжи"</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Приближете се за да пуштите на <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Приближете се до <xliff:g id="DEVICENAME">%1$s</xliff:g> за да пуштите тука"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Пуштено на <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Пуштено на овој телефон"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Нешто не е во ред. Обидете се повторно."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Неактивна, провери апликација"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Не е најдено"</string>
@@ -853,6 +862,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"Зачувај"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"Се стартува…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"Не може да се емитува"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Не може да се зачува. Обидете се повторно."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Не може да се зачува."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Број на верзија"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Бројот на верзијата е копиран во привремената меморија."</string>
<string name="basic_status" msgid="2315371112182658176">"Започни разговор"</string>
@@ -937,6 +948,10 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Изменете го копираниот текст"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Изменете ја копираната слика"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Испратете до уред во близина"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"Допрете за да прегледате"</string>
+ <string name="clipboard_text_copied" msgid="5100836834278976679">"Текстот е копиран"</string>
+ <string name="clipboard_image_copied" msgid="3793365360174328722">"Сликата е копирана"</string>
+ <string name="clipboard_content_copied" msgid="144452398567828145">"Содржините се копирани"</string>
<string name="add" msgid="81036585205287996">"Додај"</string>
<string name="manage_users" msgid="1823875311934643849">"Управувајте со корисниците"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"Известувањево не поддржува влечење на поделен екран."</string>
@@ -945,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Алармот е наместен"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Камерата и микрофонот се исклучени"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# известување}one{# известување}other{# известувања}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Емитување"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Да се прекине емитувањето на <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Ако емитувате на <xliff:g id="SWITCHAPP">%1$s</xliff:g> или го промените излезот, тековното емитување ќе запре"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Емитување на <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Променете излез"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Непознато"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mk/tiles_states_strings.xml b/packages/SystemUI/res/values-mk/tiles_states_strings.xml
index 78be6dd..96c8a49 100644
--- a/packages/SystemUI/res/values-mk/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-mk/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Исклучен"</item>
<item msgid="460891964396502657">"Вклучен"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Недостапно"</item>
+ <item msgid="8014986104355098744">"Исклучено"</item>
+ <item msgid="5966994759929723339">"Вклучено"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 2ebb8f2..4463cce 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"സ്ക്രീൻഷോട്ട് എടുക്കാൻ വീണ്ടും ശ്രമിക്കുക"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"സ്ക്രീൻഷോട്ട് സംരക്ഷിക്കാനാകുന്നില്ല"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"സ്ക്രീൻഷോട്ടുകൾ എടുക്കുന്നത് ആപ്പോ നിങ്ങളുടെ സ്ഥാപനമോ അനുവദിക്കുന്നില്ല"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"സ്ക്രീൻഷോട്ടുകൾ എടുക്കുന്നത് നിങ്ങളുടെ ഐടി അഡ്മിൻ ബ്ലോക്ക് ചെയ്തിരിക്കുന്നു"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"എഡിറ്റ് ചെയ്യുക"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"സ്ക്രീൻഷോട്ട് എഡിറ്റ് ചെയ്യുക"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"സ്ക്രീൻഷോട്ട് പങ്കിടുക"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"സ്ക്രീൻ സ്വയമേവ തിരിയൽ"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"സ്ക്രീൻ സ്വയമേവ തിരിക്കുക"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"ലൊക്കേഷൻ"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"സ്ക്രീൻ സേവർ"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"ക്യാമറ ആക്സസ്"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"മൈക്ക് ആക്സസ്"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"ലഭ്യമാണ്"</string>
@@ -318,6 +320,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"മുഖം ഉപയോഗിച്ച് അൺലോക്ക് ചെയ്തു. തുറക്കാൻ അമർത്തുക."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"മുഖം തിരിച്ചറിഞ്ഞു. തുറക്കാൻ അമർത്തുക."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"മുഖം തിരിച്ചറിഞ്ഞു. തുറക്കാൻ അൺലോക്ക് ഐക്കൺ അമർത്തുക."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"വീണ്ടും ശ്രമിക്കാൻ മുകളിലേക്ക് സ്വൈപ്പ് ചെയ്യുക"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC ഉപയോഗിക്കാൻ അൺലോക്ക് ചെയ്യുക"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"ഈ ഉപകരണം നിങ്ങളുടെ സ്ഥാപനത്തിന്റേതാണ്"</string>
@@ -467,7 +473,7 @@
<string name="wallet_title" msgid="5369767670735827105">"വാലറ്റ്"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"നിങ്ങളുടെ ഫോൺ ഉപയോഗിച്ച് വാങ്ങലുകൾ വേഗത്തിലും സുരക്ഷിതമായും നടത്താനുള്ള സജ്ജീകരണം നടത്തുക"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"എല്ലാം കാണിക്കുക"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"കാർഡ് ചേർക്കുക"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"തുറക്കാൻ ടാപ്പ് ചെയ്യുക"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"അപ്ഡേറ്റ് ചെയ്യുന്നു"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ഉപയോഗിക്കാൻ അൺലോക്ക് ചെയ്യുക"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"നിങ്ങളുടെ കാർഡുകൾ ലഭ്യമാക്കുന്നതിൽ ഒരു പ്രശ്നമുണ്ടായി, പിന്നീട് വീണ്ടും ശ്രമിക്കുക"</string>
@@ -693,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"മുന്നറിയിപ്പുകൾ"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"ബാറ്ററി"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"സ്ക്രീൻഷോട്ടുകൾ"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"പൊതുവായ സന്ദേശങ്ങൾ"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"സ്റ്റോറേജ്"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"സൂചനകൾ"</string>
<string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string>
@@ -727,6 +736,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"ബാറ്ററി ചാർജ് തീരാൻ സാധ്യതയുണ്ടെങ്കിൽ ഓണാക്കുക"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"വേണ്ട"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"SysUI ഹീപ്പ് ഡമ്പ് ചെയ്യുക"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"ഉപയോഗത്തിലാണ്"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"ആപ്പുകൾ നിങ്ങളുടെ <xliff:g id="TYPES_LIST">%s</xliff:g> ഉപയോഗിക്കുന്നു."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" കൂടാതെ "</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g> എന്നതിൽ പ്ലേ ചെയ്യാൻ അടുത്തേക്ക് നീക്കുക"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"ഇവിടെ പ്ലേ ചെയ്യാൻ <xliff:g id="DEVICENAME">%1$s</xliff:g> എന്നതിന് അടുത്തേക്ക് നീക്കുക"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> എന്നതിൽ പ്ലേ ചെയ്യുന്നു"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"ഈ ഫോണിൽ പ്ലേ ചെയ്യുന്നു"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"എന്തോ കുഴപ്പമുണ്ടായി. വീണ്ടും ശ്രമിക്കുക."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"നിഷ്ക്രിയം, ആപ്പ് പരിശോധിക്കൂ"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"കണ്ടെത്തിയില്ല"</string>
@@ -853,6 +862,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"സംരക്ഷിക്കുക"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"ആരംഭിക്കുന്നു…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"ബ്രോഡ്കാസ്റ്റ് ചെയ്യാനാകുന്നില്ല"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"സംരക്ഷിക്കാൻ കഴിയില്ല. വീണ്ടും ശ്രമിക്കുക."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"സംരക്ഷിക്കാൻ കഴിയില്ല."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"ബിൽഡ് നമ്പർ"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"ക്ലിപ്പ്ബോർഡിലേക്ക് ബിൽഡ് നമ്പർ പകർത്തി."</string>
<string name="basic_status" msgid="2315371112182658176">"സംഭാഷണം തുറക്കുക"</string>
@@ -903,7 +914,7 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"മൊബൈൽ ഡാറ്റ"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"കണക്റ്റ് ചെയ്തു"</string>
- <string name="mobile_data_off_summary" msgid="3663995422004150567">"മൊബൈൽ ഡാറ്റ സ്വയമേവ കണക്റ്റ് ചെയ്യില്ല"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"മൊബൈൽ ഡാറ്റ സ്വയം കണക്റ്റ് ചെയ്യില്ല"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"കണക്ഷനില്ല"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"മറ്റ് നെറ്റ്വർക്കുകളൊന്നും ലഭ്യമല്ല"</string>
<string name="all_network_unavailable" msgid="4112774339909373349">"നെറ്റ്വർക്കുകളൊന്നും ലഭ്യമല്ല"</string>
@@ -937,6 +948,10 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"പകർത്തിയ ടെക്സ്റ്റ് എഡിറ്റ് ചെയ്യുക"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"പകർത്തിയ ചിത്രം എഡിറ്റ് ചെയ്യുക"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"സമീപത്തുള്ള ഉപകരണത്തിലേക്ക് അയയ്ക്കുക"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"കാണാൻ ടാപ്പ് ചെയ്യുക"</string>
+ <string name="clipboard_text_copied" msgid="5100836834278976679">"ടെക്സ്റ്റ് പകർത്തി"</string>
+ <string name="clipboard_image_copied" msgid="3793365360174328722">"ചിത്രം പകർത്തി"</string>
+ <string name="clipboard_content_copied" msgid="144452398567828145">"ഉള്ളടക്കം പകർത്തി"</string>
<string name="add" msgid="81036585205287996">"ചേർക്കുക"</string>
<string name="manage_users" msgid="1823875311934643849">"ഉപയോക്താക്കളെ മാനേജ് ചെയ്യുക"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"സ്പ്ലിറ്റ് സ്ക്രീനിലേക്ക് വലിച്ചിടുന്നതിനെ ഈ അറിയിപ്പ് പിന്തുണയ്ക്കുന്നില്ല."</string>
@@ -945,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"അലാറം സജ്ജീകരിച്ചു"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"ക്യാമറയും മൈക്കും ഓഫാണ്"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# അറിയിപ്പ്}other{# അറിയിപ്പുകൾ}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"പ്രക്ഷേപണം ചെയ്യുന്നു"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> ബ്രോഡ്കാസ്റ്റ് ചെയ്യുന്നത് അവസാനിപ്പിക്കണോ?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"നിങ്ങൾ <xliff:g id="SWITCHAPP">%1$s</xliff:g> ബ്രോഡ്കാസ്റ്റ് ചെയ്യുകയോ ഔട്ട്പുട്ട് മാറ്റുകയോ ചെയ്താൽ നിങ്ങളുടെ നിലവിലുള്ള ബ്രോഡ്കാസ്റ്റ് അവസാനിക്കും"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> ബ്രോഡ്കാസ്റ്റ് ചെയ്യുക"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"ഔട്ട്പുട്ട് മാറ്റുക"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"അജ്ഞാതം"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ml/tiles_states_strings.xml b/packages/SystemUI/res/values-ml/tiles_states_strings.xml
index 1208928..7a07873 100644
--- a/packages/SystemUI/res/values-ml/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ml/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"ഓഫാണ്"</item>
<item msgid="460891964396502657">"ഓണാണ്"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"ലഭ്യമല്ല"</item>
+ <item msgid="8014986104355098744">"ഓഫാണ്"</item>
+ <item msgid="5966994759929723339">"ഓണാണ്"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index c32565a..1bdc738 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Дэлгэцийн зургийг дахин дарж үзнэ үү"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"Дэлгэцийн агшныг хадгалах боломжгүй"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Таны апп, байгууллагад дэлгэцийн зураг авахыг зөвшөөрдөггүй"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Таны IT админ дэлгэцийн агшин авахыг блоклосон байна"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Засах"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Дэлгэцийн агшныг засах"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"Дэлгэцийн агшныг хуваалцах"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Автоматаар эргэх"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Дэлгэцийг автоматаар эргүүлэх"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Байршил"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Дэлгэц амраагч"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Камерын хандалт"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Микрофоны хандалт"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Боломжтой"</string>
@@ -318,6 +320,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Царайгаар түгжээг тайлсан. Нээхийн тулд дарна уу."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Царайг таньсан. Нээхийн тулд дарна уу."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Царайг таньсан. Нээх бол түгжээг тайлах дүрсийг дарна уу."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"Дахин оролдохын тулд дээш шударна уу"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC-г ашиглахын тулд түгжээг тайлна уу"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Энэ төхөөрөмж танай байгууллагад харьяалагддаг"</string>
@@ -467,7 +473,7 @@
<string name="wallet_title" msgid="5369767670735827105">"Түрийвч"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"Утсаараа илүү хурдан, аюулгүй худалдан авалт хийхийн тулд тохируулгыг авна уу"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"Бүгдийг харуулах"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"Карт нэмэх"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"Нээх бол товшино уу"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"Шинэчилж байна"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Ашиглахын тулд түгжээг тайлах"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Таны картыг авахад асуудал гарлаа. Дараа дахин оролдоно уу"</string>
@@ -693,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Сэрэмжлүүлэг"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Батарей"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Дэлгэцийн зураг дарах"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Энгийн мессеж"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"Хадгалах сан"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Заавар"</string>
<string name="instant_apps" msgid="8337185853050247304">"Шуурхай апп"</string>
@@ -727,6 +736,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"Батарей дуусах гэж байгаа үед асаана уу"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"Үгүй, баярлалаа"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"Ашиглаж байгаа"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Аппууд таны <xliff:g id="TYPES_LIST">%s</xliff:g>-г ашиглаж байна."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" болон "</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g> дээр тоглуулахын тулд төхөөрөмжөө ойртуулна уу"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Энд тоглуулахын тулд <xliff:g id="DEVICENAME">%1$s</xliff:g>-д ойртоно уу"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> дээр тоглуулж байна"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Энэ утсан дээр тоглуулж байна"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Алдаа гарлаа. Дахин оролдоно уу."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Идэвхгүй байна, аппыг шалгана уу"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Олдсонгүй"</string>
@@ -853,6 +862,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"Хадгалах"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"Эхлүүлж байна…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"Нэвтрүүлэх боломжгүй"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Хадгалах боломжгүй. Дахин оролдоно уу."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Хадгалах боломжгүй."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Хийцийн дугаар"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Хийцийн дугаарыг түр санах ойд хуулсан."</string>
<string name="basic_status" msgid="2315371112182658176">"Харилцан яриаг нээх"</string>
@@ -937,6 +948,10 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Хуулсан текстийг засах"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Хуулсан зургийг засах"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Ойролцоох төхөөрөмж рүү илгээх"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"Харахын тулд товшино уу"</string>
+ <string name="clipboard_text_copied" msgid="5100836834278976679">"Текстийг хуулсан"</string>
+ <string name="clipboard_image_copied" msgid="3793365360174328722">"Зургийг хуулсан"</string>
+ <string name="clipboard_content_copied" msgid="144452398567828145">"Контентыг хуулсан"</string>
<string name="add" msgid="81036585205287996">"Нэмэх"</string>
<string name="manage_users" msgid="1823875311934643849">"Хэрэглэгчдийг удирдах"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"Энэ мэдэгдэл нь Дэлгэцийг хуваах горим руу чирэхийг дэмждэггүй."</string>
@@ -945,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Сэрүүлгийг тохируулсан"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Камер болон микрофон унтраалттай байна"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# мэдэгдэл}other{# мэдэгдэл}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Нэвтрүүлэлт"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g>-г нэвтрүүлэхээ зогсоох уу?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Хэрэв та <xliff:g id="SWITCHAPP">%1$s</xliff:g>-г нэвтрүүлсэн эсвэл гаралтыг өөрчилсөн бол таны одоогийн нэвтрүүлэлтийг зогсооно"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g>-г нэвтрүүлэх"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Гаралтыг өөрчлөх"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Тодорхойгүй"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mn/tiles_states_strings.xml b/packages/SystemUI/res/values-mn/tiles_states_strings.xml
index 3748440..776c487 100644
--- a/packages/SystemUI/res/values-mn/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-mn/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Унтраалттай"</item>
<item msgid="460891964396502657">"Асаалттай"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Боломжгүй"</item>
+ <item msgid="8014986104355098744">"Унтраалттай"</item>
+ <item msgid="5966994759929723339">"Асаалттай"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 32f9316..ec3646a 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"स्क्रीनशॉट पुन्हा घेण्याचा प्रयत्न करा"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"स्क्रीनशॉट सेव्ह करू शकत नाही"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"अॅप किंवा आपल्या संस्थेद्वारे स्क्रीनशॉट घेण्याची अनुमती नाही"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"तुमच्या आयटी ॲडमिनने स्क्रीनशॉट घेणे ब्लॉक केले आहे"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"संपादित करा"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"स्क्रीनशॉट संपादित करा"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"स्क्रीनशॉट शेअर करा"</string>
@@ -95,7 +96,7 @@
<string name="screenrecord_description" msgid="1123231719680353736">"रेकॉर्डिंग करताना, Android सिस्टीम तुमच्या स्क्रीनवर दिसणारी किंवा तुमच्या डिव्हाइसवर प्ले केलेली कोणतीही संवेदनशील माहिती कॅप्चर करू शकते. यात पासवर्ड, पेमेंट माहिती, फोटो, मेसेज आणि ऑडिओचा समावेश आहे."</string>
<string name="screenrecord_audio_label" msgid="6183558856175159629">"ऑडिओ रेकॉर्ड करा"</string>
<string name="screenrecord_device_audio_label" msgid="9016927171280567791">"डिव्हाइस ऑडिओ"</string>
- <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"तुमच्या डिव्हाइसवरील आवाज जसे की, संगीत, कॉल आणि रिंगटोन"</string>
+ <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"तुमच्या डिव्हाइसवरील आवाज, जसे की संगीत, कॉल आणि रिंगटोन"</string>
<string name="screenrecord_mic_label" msgid="2111264835791332350">"मायक्रोफोन"</string>
<string name="screenrecord_device_audio_and_mic_label" msgid="1831323771978646841">"डिव्हाइस ऑडिओ आणि मायक्रोफोन"</string>
<string name="screenrecord_start" msgid="330991441575775004">"सुरू"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"ऑटो-रोटेट"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"ऑटो-रोटेट स्क्रीन"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"स्थान"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"स्क्रीन सेव्हर"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"कॅमेराचा अॅक्सेस"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"माइकचा ॲक्सेस"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"उपलब्ध आहे"</string>
@@ -318,6 +320,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"चेहऱ्याने अनलॉक केले आहे. उघडण्यासाठी दाबा."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"चेहरा ओळखला आहे. उघडण्यासाठी दाबा."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"चेहरा ओळखला आहे. उघडण्यासाठी अनलॉक करा आयकन दाबा."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"पुन्हा प्रयत्न करण्यासाठी वर स्वाइप करा"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC वापरण्यासाठी स्क्रीन अनलॉक करा"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"हे डिव्हाइस तुमच्या संस्थेचे आहे"</string>
@@ -346,7 +352,7 @@
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"होय, सुरू ठेवा"</string>
<string name="guest_notification_app_name" msgid="2110425506754205509">"अतिथी मोड"</string>
<string name="guest_notification_session_active" msgid="5567273684713471450">"तुम्ही अतिथी मोडमध्ये आहात"</string>
- <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"नवीन वापरकर्ता जोडल्याने अतिथी मोडमधून बाहेर पडेल आणि सध्याच्या अतिथी सत्रातील सर्व अॅप्स व डेटा हटवला जाईल."</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"नवीन वापरकर्ता जोडल्याने अतिथी मोडमधून बाहेर पडाल आणि सध्याच्या अतिथी सत्रातील सर्व अॅप्स व डेटा हटवला जाईल."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"वापरकर्ता मर्यादा गाठली"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="other">तुम्ही <xliff:g id="COUNT">%d</xliff:g> वापरकर्त्यांपर्यंत जोडू शकता.</item>
@@ -467,7 +473,7 @@
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"तुमचा फोन वापरून जलदरीत्या, अधिक सुरक्षित खरेदी करण्यासाठी सेट करा"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"सर्व दाखवा"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"कार्ड जोडा"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"उघडण्यासाठी टॅप करा"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"अपडेट करत आहे"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"वापरण्यासाठी अनलॉक करा"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"तुमची कार्ड मिळवताना समस्या आली, कृपया नंतर पुन्हा प्रयत्न करा"</string>
@@ -527,7 +533,7 @@
<string name="feedback_prompt" msgid="3656728972307896379">"डेव्हलपरला तुमचा फीडबॅक कळवा. हे बरोबर होते का?"</string>
<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_more_settings" msgid="4936228656989201793">"आणखी सेटिंग्ज"</string>
<string name="notification_app_settings" msgid="8963648463858039377">"कस्टमाइझ करा"</string>
<string name="notification_conversation_bubble" msgid="2242180995373949022">"बबल दाखवा"</string>
<string name="notification_conversation_unbubble" msgid="6908427185031099868">"बबल काढून टाका"</string>
@@ -585,7 +591,7 @@
<string name="keyboard_shortcut_group_applications_browser" msgid="2776211137869809251">"ब्राउझर"</string>
<string name="keyboard_shortcut_group_applications_contacts" msgid="2807268086386201060">"संपर्क"</string>
<string name="keyboard_shortcut_group_applications_email" msgid="7852376788894975192">"ईमेल"</string>
- <string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string>
+ <string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"एसएमएस"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"संगीत"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"कॅलेंडर"</string>
<string name="volume_and_do_not_disturb" msgid="502044092739382832">"व्यत्यय आणू नका"</string>
@@ -693,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"सूचना"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"बॅटरी"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"स्क्रीनशॉट"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"सर्वसाधारण मेसेज"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"स्टोरेज"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"सूचना"</string>
<string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string>
@@ -727,6 +736,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"बॅटरी संपण्याची शक्यता असल्यास सुरू करा"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"नाही नको"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"SysUI हीप डंप करा"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"वापरात आहे"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"ॲप्लिकेशन्स तुमचे <xliff:g id="TYPES_LIST">%s</xliff:g> वापरत आहे."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" आणि "</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g> वर प्ले करण्यासाठी जवळ जा"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"येथे प्ले करण्यासाठी <xliff:g id="DEVICENAME">%1$s</xliff:g> च्या जवळ जा"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> वर प्ले केला जात आहे"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"या फोनवर प्ले होत आहे"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"काहीतरी चूक झाली. पुन्हा प्रयत्न करा."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"निष्क्रिय, ॲप तपासा"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"आढळले नाही"</string>
@@ -853,6 +862,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"सेव्ह करा"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"सुरू करत आहे…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"ब्रॉडकास्ट करू शकत नाही"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"सेव्ह करू शकत नाही. पुन्हा प्रयत्न करा."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"सेव्ह करू शकत नाही."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"बिल्ड नंबर"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"बिल्ड नंबर क्लिपबोर्डवर कॉपी केला."</string>
<string name="basic_status" msgid="2315371112182658176">"संभाषण उघडा"</string>
@@ -927,7 +938,7 @@
</plurals>
<string name="fgs_dot_content_description" msgid="2865071539464777240">"नवीन माहिती"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"अॅक्टिव्ह ॲप्स"</string>
- <string name="fgs_manager_dialog_message" msgid="6839542063522121108">"तुम्ही ही अॅप्स वापरत नसलात तरीही, ती अॅक्टिव्ह असतात आणि बॅटरी लाइफवर त्याचा परिणाम होऊ शकतो"</string>
+ <string name="fgs_manager_dialog_message" msgid="6839542063522121108">"तुम्ही ही अॅप्स वापरत नसलात, तरीही ती अॅक्टिव्ह असतात आणि बॅटरी लाइफवर त्याचा परिणाम होऊ शकतो"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"थांबवा"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"थांबवले"</string>
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"पूर्ण झाले"</string>
@@ -937,6 +948,10 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"कॉपी केलेला मजकूर संपादित करा"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"कॉपी केलेली इमेज संपादित करा"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"जवळपासच्या डिव्हाइसवर पाठवा"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"पाहण्यासाठी टॅप करा"</string>
+ <string name="clipboard_text_copied" msgid="5100836834278976679">"मजकूर कॉपी केला"</string>
+ <string name="clipboard_image_copied" msgid="3793365360174328722">"इमेज कॉपी केली"</string>
+ <string name="clipboard_content_copied" msgid="144452398567828145">"आशय कॉपी केला"</string>
<string name="add" msgid="81036585205287996">"जोडा"</string>
<string name="manage_users" msgid="1823875311934643849">"वापरकर्ते व्यवस्थापित करा"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"ही सूचना स्प्लिटस्क्रीनवर ड्रॅग करण्याला सपोर्ट करत नाही."</string>
@@ -945,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"अलार्म सेट केला"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"कॅमेरा आणि माइक बंद आहेत"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# सूचना}other{# सूचना}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"ब्रॉडकास्ट करत आहे"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> चे प्रसारण थांबवायचे आहे का?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"तुम्ही <xliff:g id="SWITCHAPP">%1$s</xliff:g> चे प्रसारण केल्यास किंवा आउटपुट बदलल्यास, तुमचे सध्याचे प्रसारण बंद होईल"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> चे प्रसारण करा"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"आउटपूट बदला"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"अज्ञात"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mr/tiles_states_strings.xml b/packages/SystemUI/res/values-mr/tiles_states_strings.xml
index a6a3873..f75f0d0 100644
--- a/packages/SystemUI/res/values-mr/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-mr/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"बंद आहे"</item>
<item msgid="460891964396502657">"सुरू आहे"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"उपलब्ध नाही"</item>
+ <item msgid="8014986104355098744">"बंद आहे"</item>
+ <item msgid="5966994759929723339">"सुरू आहे"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 2ed77be..c68f0bf 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Cuba ambil tangkapan skrin sekali lagi"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"Tidak dapat menyimpan tangkapan skrin"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Pengambilan tangkapan skrin tidak dibenarkan oleh apl atau organisasi anda"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Pengambilan tangkapan skrin disekat oleh pentadbir IT anda"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Edit"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Edit tangkapan skrin"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"Kongsi tangkapan skrin"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Autoputar"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Autoputar skrin"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Lokasi"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Penyelamat skrin"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Akses kamera"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Akses mikrofon"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Tersedia"</string>
@@ -318,6 +320,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Dibuka kunci dengan wajah. Tekan untuk membuka."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Wajah dicam. Tekan untuk membuka."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Wajah dicam. Tekan ikon buka kunci untuk membuka."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"Leret ke atas untuk mencuba lagi"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Buka kunci untuk menggunakan NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Peranti ini milik organisasi anda"</string>
@@ -467,7 +473,7 @@
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"Buat persediaan untuk membuat pembelian yang lebih pantas dan selamat dengan telefon anda"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"Tunjukkan semua"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"Tambahkan kad"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"Ketik untuk buka"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"Mengemas kini"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Buka kunci untuk menggunakan"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Terdapat masalah sewaktu mendapatkan kad anda. Sila cuba sebentar lagi"</string>
@@ -693,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Makluman"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Bateri"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Tangkapan skrin"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Mesej Am"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"Storan"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Pembayang"</string>
<string name="instant_apps" msgid="8337185853050247304">"Apl Segera"</string>
@@ -727,6 +736,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"Hidupkan apabila bateri berkemungkinan habis"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"Tidak perlu"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"DumpSys"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"Sedang digunakan"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Aplikasi sedang menggunakan <xliff:g id="TYPES_LIST">%s</xliff:g> anda."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" dan "</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Alihkan lebih dekat untuk bermain pada<xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Dekatkan dengan <xliff:g id="DEVICENAME">%1$s</xliff:g> untuk bermain di sini"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Dimainkan pada <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Dimainkan pada telefon ini"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Kesilapan telah berlaku. Cuba lagi."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Tidak aktif, semak apl"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Tidak ditemukan"</string>
@@ -853,6 +862,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"Simpan"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"Memulakan…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"Tidak dapat disiarkan"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Tidak dapat disimpan. Cuba lagi."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Tidak dapat disimpan."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Nombor binaan"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Nombor binaan disalin ke papan keratan."</string>
<string name="basic_status" msgid="2315371112182658176">"Buka perbualan"</string>
@@ -937,6 +948,13 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Edit teks yang disalin"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Edit imej yang disalin"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Hantar ke peranti berdekatan"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"Ketik untuk lihat"</string>
+ <!-- no translation found for clipboard_text_copied (5100836834278976679) -->
+ <skip />
+ <!-- no translation found for clipboard_image_copied (3793365360174328722) -->
+ <skip />
+ <!-- no translation found for clipboard_content_copied (144452398567828145) -->
+ <skip />
<string name="add" msgid="81036585205287996">"Tambah"</string>
<string name="manage_users" msgid="1823875311934643849">"Urus pengguna"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"Pemberitahuan ini tidak menyokong penyeretan ke Skrin pisah."</string>
@@ -945,4 +963,12 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Penggera ditetapkan"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera dan mikrofon dimatikan"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# pemberitahuan}other{# pemberitahuan}}"</string>
+ <!-- no translation found for broadcasting_description_is_broadcasting (765627502786404290) -->
+ <skip />
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Hentikan siaran <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Jika anda siarkan <xliff:g id="SWITCHAPP">%1$s</xliff:g> atau tukarkan output, siaran semasa anda akan berhenti"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Siarkan <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Tukar output"</string>
+ <!-- no translation found for bt_le_audio_broadcast_dialog_unknown_name (3791472237793443044) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ms/tiles_states_strings.xml b/packages/SystemUI/res/values-ms/tiles_states_strings.xml
index cfd831a..9fa7ab5 100644
--- a/packages/SystemUI/res/values-ms/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ms/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Mati"</item>
<item msgid="460891964396502657">"Hidup"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Tidak tersedia"</item>
+ <item msgid="8014986104355098744">"Mati"</item>
+ <item msgid="5966994759929723339">"Hidup"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 66a0922..1540656 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"မျက်နှာပြင်ပုံကို ထပ်ရိုက်ကြည့်ပါ"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"ဖန်သားပြင်ဓာတ်ပုံကို သိမ်း၍မရပါ"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"ဖန်သားပြင်ဓာတ်ပုံရိုက်ကူးခြင်းကို ဤအက်ပ် သို့မဟုတ် သင်၏အဖွဲ့အစည်းက ခွင့်မပြုပါ"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"ဖန်သားပြင်ဓာတ်ပုံရိုက်ခြင်းကို သင့် IT စီမံခန့်ခွဲသူက ပိတ်ထားသည်"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"တည်းဖြတ်ရန်"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"ဖန်သားပြင်ဓာတ်ပုံကို တည်းဖြတ်သည်"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"ဖန်သားပြင်ဓာတ်ပုံကို မျှဝေနိုင်သည်"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"အော်တို-လည်"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"မျက်နှာပြင်အား အလိုအလျောက်လှည့်ခြင်း"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"တည်နေရာ"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"စကရင်ချွေတာစနစ်"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"ကင်မရာသုံးခွင့်"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"မိုက်သုံးခွင့်"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"ရနိုင်သည်"</string>
@@ -318,6 +320,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"မျက်နှာဖြင့် ဖွင့်ထားသည်။ ဖွင့်ရန် နှိပ်ပါ။"</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"မျက်နှာ မှတ်မိသည်။ ဖွင့်ရန် နှိပ်ပါ။"</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"မျက်နှာ မှတ်မိသည်။ ဖွင့်ရန် လော့ခ်ဖွင့်သင်္ကေတကို နှိပ်ပါ။"</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"ထပ်စမ်းကြည့်ရန် အပေါ်သို့ပွတ်ဆွဲပါ"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC ကို အသုံးပြုရန် လော့ခ်ဖွင့်ပါ"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"ဤစက်ကို သင့်အဖွဲ့အစည်းက ပိုင်ဆိုင်သည်"</string>
@@ -467,7 +473,7 @@
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"သင့်ဖုန်းဖြင့် ပိုမိုမြန်ဆန်၊ ပိုမိုစိတ်ချရသော ဝယ်ယူမှုများ ပြုလုပ်ရန် စတင်သတ်မှတ်ပါ"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"အားလုံးပြရန်"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"ကတ်ထည့်ရန်"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"တို့၍ ဖွင့်ရန်"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"အပ်ဒိတ်လုပ်နေပါသည်"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"သုံးရန် လော့ခ်ဖွင့်ပါ"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"သင်၏ကတ်များ ရယူရာတွင် ပြဿနာရှိနေသည်၊ နောက်မှ ထပ်စမ်းကြည့်ပါ"</string>
@@ -693,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"သတိပေးချက်များ"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"ဘက်ထရီ"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"မျက်နှာပြင်ဓာတ်ပုံများ"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"အထွေထွေ မက်ဆေ့ဂျ်များ"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"သိုလှောင်ခန်း"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"အရိပ်အမြွက်များ"</string>
<string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string>
@@ -727,6 +736,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"ဘက်ထရီကုန်ခါနီးတွင် ဖွင့်ပါ"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"မလိုပါ"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"အသုံးပြုနေသည်"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"အပလီကေးရှင်းများက သင်၏ <xliff:g id="TYPES_LIST">%s</xliff:g> ကို အသုံးပြုနေသည်။"</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">"၊ "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" နှင့် "</string>
@@ -804,7 +814,7 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"ပိုကြည့်ရန် ပွတ်ဆွဲပါ"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"အကြံပြုချက်များ ဖွင့်နေသည်"</string>
<string name="controls_media_title" msgid="1746947284862928133">"မီဒီယာ"</string>
- <string name="controls_media_close_session" msgid="4780485355795635052">"<xliff:g id="APP_NAME">%1$s</xliff:g> ၏ ဤမီဒီယာ ထိန်းချုပ်ကိရိယာကို ဖျောက်ထားမလား။"</string>
+ <string name="controls_media_close_session" msgid="4780485355795635052">"<xliff:g id="APP_NAME">%1$s</xliff:g> အတွက် ဤမီဒီယာထိန်းချုပ်မှု ဖျောက်ထားမလား။"</string>
<string name="controls_media_active_session" msgid="3146882316024153337">"လက်ရှိ မီဒီယာစက်ရှင်ကို ဝှက်၍မရပါ။"</string>
<string name="controls_media_dismiss_button" msgid="4485675693008031646">"ဖျောက်ထားမည်"</string>
<string name="controls_media_resume" msgid="1933520684481586053">"ဆက်လုပ်ရန်"</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g> တွင်ဖွင့်ရန် အနီးသို့ရွှေ့ပါ"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"ဤနေရာတွင်ဖွင့်ရန် <xliff:g id="DEVICENAME">%1$s</xliff:g> အနီးသို့တိုးပါ"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> တွင် ဖွင့်နေသည်"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"ဤဖုန်းတွင် ဖွင့်နေသည်"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"တစ်ခုခုမှားသွားသည်။ ထပ်စမ်းကြည့်ပါ။"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"ရပ်နေသည်၊ အက်ပ်ကို စစ်ဆေးပါ"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"မတွေ့ပါ"</string>
@@ -853,6 +862,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"သိမ်းရန်"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"စတင်နေသည်…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"ထုတ်လွှင့်၍ မရပါ"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"သိမ်း၍မရပါ။ ထပ်စမ်းကြည့်ပါ။"</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"သိမ်း၍မရပါ။"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"တည်ဆောက်မှုနံပါတ်"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"တည်ဆောက်မှုနံပါတ်ကို ကလစ်ဘုတ်သို့ မိတ္တူကူးပြီးပါပြီ။"</string>
<string name="basic_status" msgid="2315371112182658176">"စကားဝိုင်းကို ဖွင့်ရန်"</string>
@@ -903,7 +914,7 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"မိုဘိုင်းဒေတာ"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"ချိတ်ဆက်ထားသည်"</string>
- <string name="mobile_data_off_summary" msgid="3663995422004150567">"မိုဘိုင်းဒေတာက အလိုအလျောက် ချိတ်ဆက်မည်မဟုတ်ပါ"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"မိုဘိုင်းဒေတာ အော်တိုမချိတ်ပါ"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"ချိတ်ဆက်မှုမရှိပါ"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"အခြားကွန်ရက်များ မရှိပါ"</string>
<string name="all_network_unavailable" msgid="4112774339909373349">"ကွန်ရက်များ မရှိပါ"</string>
@@ -937,6 +948,10 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"ကူးထားသည့်စာသားကို တည်းဖြတ်ရန်"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"ကူးထားသည့်ပုံကို ပြင်ဆင်ရန်"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"အနီးတစ်ဝိုက်ရှိ စက်များသို့ ပို့ရန်"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"ကြည့်ရှုရန် တို့ပါ"</string>
+ <string name="clipboard_text_copied" msgid="5100836834278976679">"စာသားကို မိတ္တူကူးပြီးပြီ"</string>
+ <string name="clipboard_image_copied" msgid="3793365360174328722">"ပုံ ကူးပြီးပြီ"</string>
+ <string name="clipboard_content_copied" msgid="144452398567828145">"အကြောင်းအရာများကို ကူးယူပြီးပါပြီ"</string>
<string name="add" msgid="81036585205287996">"ထည့်ရန်"</string>
<string name="manage_users" msgid="1823875311934643849">"အသုံးပြုသူများ စီမံရန်"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"ဤအကြောင်းကြားချက်သည် ‘မျက်နှာပြင်ခွဲ၍ပြသမှု’ သို့ ဖိဆွဲခြင်းကို မပံ့ပိုးပါ။"</string>
@@ -945,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"နိုးစက် သတ်မှတ်ထားသည်"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"ကင်မရာနှင့် မိုက် ပိတ်ထားသည်"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{အကြောင်းကြားချက် # ခု}other{အကြောင်းကြားချက် # ခု}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"ထုတ်လွှင့်ခြင်း"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> ထုတ်လွှင့်ခြင်းကို ရပ်မလား။"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> ကို ထုတ်လွှင့်သောအခါ (သို့) အထွက်ကို ပြောင်းသောအခါ သင့်လက်ရှိထုတ်လွှင့်ခြင်း ရပ်သွားမည်"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> ထုတ်လွှင့်ခြင်း"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"အထွက်ကို ပြောင်းခြင်း"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"မသိ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-my/tiles_states_strings.xml b/packages/SystemUI/res/values-my/tiles_states_strings.xml
index 665af20..493a7f0 100644
--- a/packages/SystemUI/res/values-my/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-my/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"ပိတ်"</item>
<item msgid="460891964396502657">"ဖွင့်"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"မရနိုင်ပါ"</item>
+ <item msgid="8014986104355098744">"ပိတ်"</item>
+ <item msgid="5966994759929723339">"ဖွင့်"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 3599b01..a2cd9c8 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Prøv å ta skjermdump på nytt"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"Kan ikke lagre skjermdumpen"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Appen eller organisasjonen din tillater ikke at du tar skjermdumper"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Funksjonen for å ta skjermdumper er blokkert av IT-administratoren din"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Rediger"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Rediger skjermdumpen"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"Del skjermdumpen"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Rotér automatisk"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Rotér skjermen automatisk"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Sted"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Skjermsparer"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Kameratilgang"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Mikrofontilgang"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Tilgjengelig"</string>
@@ -318,6 +320,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Låst opp med ansiktet. Trykk for å åpne."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Ansiktet er gjenkjent. Trykk for å åpne."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Ansiktet er gjenkjent. Trykk på lås opp-ikon for å fortsette"</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"Sveip opp for å prøve igjen"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Lås opp for å bruke NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Denne enheten tilhører organisasjonen din"</string>
@@ -467,7 +473,7 @@
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"Legg til en betalingsmåte for å gjennomføre kjøp raskere og sikrere med telefonen"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"Vis alle"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"Legg til et kort"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"Trykk for å åpne"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"Oppdaterer"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Lås opp for å bruke"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Det oppsto et problem med henting av kortene. Prøv på nytt senere"</string>
@@ -693,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Varsler"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Batteri"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Skjermdumper"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Generelle meldinger"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"Lagring"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Hint"</string>
<string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string>
@@ -727,6 +736,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"Slå på når det er sannsynlig at du går tom for batteri"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"Nei takk"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI-heap"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"I bruk"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Apper bruker <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" og "</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Flytt nærmere for å spille av på <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Flytt deg nærmere <xliff:g id="DEVICENAME">%1$s</xliff:g> for å spille av her"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Spilles av på <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Spilles av på denne telefonen"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Noe gikk galt. Prøv på nytt."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inaktiv. Sjekk appen"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Ikke funnet"</string>
@@ -853,6 +862,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"Lagre"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"Starter …"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"Kan ikke kringkaste"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Kan ikke lagre. Prøv på nytt."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Kan ikke lagre."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Delversjonsnummer"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Delversjonsnummeret er kopiert til utklippstavlen."</string>
<string name="basic_status" msgid="2315371112182658176">"Åpen samtale"</string>
@@ -915,7 +926,7 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi kobles ikke til automatisk inntil videre"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Se alle"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"For å bytte nettverk, koble fra Ethernet"</string>
- <string name="wifi_scan_notify_message" msgid="3753839537448621794">"For å forbedre brukeropplevelsen på enheten kan apper og tjenester søke etter Wi-Fi-nettverk når som helst – også når Wi-Fi er slått av. Du kan endre dette i innstillingene for Wi-Fi-skanning. "<annotation id="link">"Bytt"</annotation></string>
+ <string name="wifi_scan_notify_message" msgid="3753839537448621794">"For å forbedre brukeropplevelsen på enheten kan apper og tjenester søke etter Wi-Fi-nettverk når som helst – også når Wi-Fi er slått av. Du kan endre dette i innstillingene for Wi-Fi-skanning. "<annotation id="link">"Endre"</annotation></string>
<string name="turn_off_airplane_mode" msgid="8425587763226548579">"Slå av flymodus"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> vil legge til denne brikken i Hurtiginnstillinger"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Legg til brikke"</string>
@@ -937,6 +948,13 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Rediger den kopierte teksten"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Rediger det kopierte bildet"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Send til en enhet i nærheten"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"Trykk for å se"</string>
+ <!-- no translation found for clipboard_text_copied (5100836834278976679) -->
+ <skip />
+ <!-- no translation found for clipboard_image_copied (3793365360174328722) -->
+ <skip />
+ <!-- no translation found for clipboard_content_copied (144452398567828145) -->
+ <skip />
<string name="add" msgid="81036585205287996">"Legg til"</string>
<string name="manage_users" msgid="1823875311934643849">"Administrer brukere"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"Dette varselet støtter ikke at du drar det til en delt skjerm."</string>
@@ -945,4 +963,12 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarmen er stilt inn"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera og mikrofon er av"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# varsel}other{# varsler}}"</string>
+ <!-- no translation found for broadcasting_description_is_broadcasting (765627502786404290) -->
+ <skip />
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Vil du stoppe kringkastingen av <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Hvis du kringkaster <xliff:g id="SWITCHAPP">%1$s</xliff:g> eller endrer utgangen, stopper den nåværende kringkastingen din"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Kringkast <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Endre utgang"</string>
+ <!-- no translation found for bt_le_audio_broadcast_dialog_unknown_name (3791472237793443044) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-nb/tiles_states_strings.xml b/packages/SystemUI/res/values-nb/tiles_states_strings.xml
index a28b817..6fa902a 100644
--- a/packages/SystemUI/res/values-nb/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-nb/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Av"</item>
<item msgid="460891964396502657">"På"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Utilgjengelig"</item>
+ <item msgid="8014986104355098744">"Av"</item>
+ <item msgid="5966994759929723339">"På"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 8be2660..5346cfe 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"स्क्रिनसट फेरि लिएर हेर्नुहोस्"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"स्क्रिनसट सुरक्षित गर्न सकिएन"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"उक्त एप वा तपाईंको संगठनले स्क्रिनसटहरू लिन दिँदैन"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"तपाईंको सूचना प्रविधि व्यवस्थापकले स्क्रिनसट लिने सुविधा ब्लक गर्नुभएको छ"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"सम्पादन गर्नुहोस्"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"स्क्रिनसट सम्पादन गर्नुहोस्"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"स्क्रिनसट सेयर गर्नुहोस्"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"अटो रोटेट"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"स्क्रिन स्वतःघुम्ने"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"लोकेसन"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"स्क्रिन सेभर"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"क्यामेरा प्रयोग गर्ने अनुमति"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"माइक प्रयोग गर्ने अनुमति"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"उपलब्ध छ"</string>
@@ -244,7 +246,7 @@
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi-Fi जडान गरिएको छैन"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"उज्यालपन"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"कलर इन्भर्सन"</string>
- <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"रङ सच्याउने कार्य"</string>
+ <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"कलर करेक्सन"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"प्रयोगकर्तासम्बन्धी सेटिङ"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"भयो"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"बन्द गर्नुहोस्"</string>
@@ -318,6 +320,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"अनुहार प्रयोग गरी अनलक गरियो। डिभाइस खोल्न थिच्नुहोस्।"</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"अनुहार पहिचान गरियो। डिभाइस खोल्न थिच्नुहोस्।"</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"अनुहार पहिचान गरियो। डिभाइस खोल्न अनलक आइकनमा थिच्नुहोस्।"</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"फेरि प्रयास गर्न माथितिर स्वाइप गर्नुहोस्"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC प्रयोग गर्न स्क्रिन अनलक गर्नुहोस्"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"यो डिभाइस तपाईंको सङ्गठनको स्वामित्वमा छ"</string>
@@ -467,7 +473,7 @@
<string name="wallet_title" msgid="5369767670735827105">"वालेट"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"फोनमार्फत अझ छिटो र थप सुरक्षित तरिकाले खरिद गर्न भुक्तानी विधि सेटअप गर्नुहोस्"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"सबै देखाइयोस्"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"कार्ड हाल्नुहोस्"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"खोल्न ट्याप गर्नुहोस्"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"अपडेट गरिँदै छ"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"यो वालेट प्रयोग गर्न डिभाइस अनलक गर्नुहोस्"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"तपाईंका कार्डहरू प्राप्त गर्ने क्रममा समस्या भयो, कृपया पछि फेरि प्रयास गर्नुहोस्"</string>
@@ -693,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"सतर्कताहरू"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"ब्याट्री"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"स्क्रिनशटहरू"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"सामान्य सन्देशहरू"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"भण्डारण"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"सङ्केतहरू"</string>
<string name="instant_apps" msgid="8337185853050247304">"तात्कालिक एपहरू"</string>
@@ -725,8 +734,9 @@
<string name="slice_permission_deny" msgid="6870256451658176895">"अस्वीकार गर्नु…"</string>
<string name="auto_saver_title" msgid="6873691178754086596">"ब्याट्री सेभरको समयतालिका बनाउन ट्याप गर्नुहोस्"</string>
<string name="auto_saver_text" msgid="3214960308353838764">"ब्याट्री सकिने सम्भावना भएमा अन गर्नुहोस्"</string>
- <string name="no_auto_saver_action" msgid="7467924389609773835">"पर्दैन धन्यवाद"</string>
+ <string name="no_auto_saver_action" msgid="7467924389609773835">"पर्दैन, धन्यवाद"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"प्रयोगमा छ"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"एपहरूले तपाईंको <xliff:g id="TYPES_LIST">%s</xliff:g> प्रयोग गर्दै छन्।"</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" र "</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g> मा प्ले गर्न आफ्नो डिभाइस नजिकै लैजानुहोस्"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"तपाईं यहाँ प्ले गर्न चाहनुहुन्छ भने आफ्नो डिभाइसलाई <xliff:g id="DEVICENAME">%1$s</xliff:g> नजिकै लैजानुहोस्"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> मा प्ले गरिँदै छ"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"यो फोनमा प्ले गरिँदै छ"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"केही चिज गडबड भयो। फेरि प्रयास गर्नुहोस्।"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"निष्क्रिय छ, एप जाँच गर्नु…"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"फेला परेन"</string>
@@ -853,6 +862,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"सेभ गर्नुहोस्"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"सुरु गरिँदै छ…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"प्रसारण गर्न सकिएन"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"सेभ गर्न सकिएन। फेरि प्रयास गर्नुहोस्।"</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"सेभ गर्न सकिएन।"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"बिल्ड नम्बर"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"बिल्ड नम्बर कपी गरी क्लिपबोर्डमा सारियो।"</string>
<string name="basic_status" msgid="2315371112182658176">"वार्तालाप खोल्नुहोस्"</string>
@@ -937,6 +948,13 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"कपी गरिएको टेक्स्ट सम्पादन गर्नुहोस्"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"कपी गरिएको फोटो सम्पादन गर्नुहोस्"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"नजिकैको डिभाइसमा पठाउनुहोस्"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"हेर्न ट्याप गर्नुहोस्"</string>
+ <!-- no translation found for clipboard_text_copied (5100836834278976679) -->
+ <skip />
+ <!-- no translation found for clipboard_image_copied (3793365360174328722) -->
+ <skip />
+ <!-- no translation found for clipboard_content_copied (144452398567828145) -->
+ <skip />
<string name="add" msgid="81036585205287996">"हाल्नुहोस्"</string>
<string name="manage_users" msgid="1823875311934643849">"प्रयोगकर्ताहरूको व्यवस्थापन गर्नुहोस्"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"यो सूचना ड्र्याग गरेर स्प्लिटस्क्रिनमा लैजान मिल्दैन।"</string>
@@ -945,4 +963,12 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"अलार्म सेट गरिएको छ"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"क्यामेरा र माइक अफ छन्"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# वटा सूचना}other{# वटा सूचनाहरू}}"</string>
+ <!-- no translation found for broadcasting_description_is_broadcasting (765627502786404290) -->
+ <skip />
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> ब्रोडकास्ट गर्न छाड्ने हो?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"तपाईंले <xliff:g id="SWITCHAPP">%1$s</xliff:g> ब्रोडकास्ट गर्नुभयो वा आउटपुट परिवर्तन गर्नुभयो भने तपाईंको हालको ब्रोडकास्ट रोकिने छ"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> ब्रोडकास्ट गर्नुहोस्"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"आउटपुट परिवर्तन गर्नुहोस्"</string>
+ <!-- no translation found for bt_le_audio_broadcast_dialog_unknown_name (3791472237793443044) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ne/tiles_states_strings.xml b/packages/SystemUI/res/values-ne/tiles_states_strings.xml
index 80edf29..17193ba 100644
--- a/packages/SystemUI/res/values-ne/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ne/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"अफ छ"</item>
<item msgid="460891964396502657">"अन छ"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"अनुपलब्ध"</item>
+ <item msgid="8014986104355098744">"अफ"</item>
+ <item msgid="5966994759929723339">"अन"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 0777958..4789637 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Probeer opnieuw een screenshot te maken"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"Kan screenshot niet opslaan"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Het maken van screenshots wordt niet toegestaan door de app of je organisatie"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Screenshots maken is geblokkeerd door je IT-beheerder"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Bewerken"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Screenshot bewerken"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"Screenshot delen"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automatisch draaien"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Scherm automatisch draaien"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Locatie"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Screensaver"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Cameratoegang"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Microfoontoegang"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Beschikbaar"</string>
@@ -318,6 +320,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Ontgrendeld via gezicht. Druk om te openen."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Gezicht herkend. Druk om te openen."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Gezicht herkend. Druk op het ontgrendelicoon."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"Swipe omhoog om het opnieuw te proberen"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Ontgrendel het apparaat om NFC te gebruiken"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Dit apparaat is eigendom van je organisatie"</string>
@@ -425,7 +431,7 @@
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Zo blijft het scherm zichtbaar totdat je het losmaakt. Swipe omhoog en houd vast om los te maken."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Het scherm blijft zichtbaar totdat je het losmaakt. Tik op Overzicht en houd dit vast om het scherm los te maken."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Het scherm blijft zichtbaar totdat je het losmaakt. Tik op Home en houd dit vast om het scherm los te maken."</string>
- <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Persoonlijke informatie kan toegankelijk zijn (zoals contacten en e-mailcontent)."</string>
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Persoonsgegevens kunnen toegankelijk zijn (zoals contacten en e-mails)."</string>
<string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"De vastgezette app kan andere apps openen."</string>
<string name="screen_pinning_toast" msgid="8177286912533744328">"Tik op Terug en Overzicht en houd de knoppen vast om deze app los te maken"</string>
<string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Tik op Terug en Home en houd de knoppen vast om deze app los te maken"</string>
@@ -467,7 +473,7 @@
<string name="wallet_title" msgid="5369767670735827105">"Portemonnee"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"Zorg dat je sneller en beter beveiligd aankopen kunt doen met je telefoon"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"Alles tonen"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"Kaart toevoegen"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"Tik om te openen"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"Updaten"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Ontgrendelen om te gebruiken"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Er is een probleem opgetreden bij het ophalen van je kaarten. Probeer het later opnieuw."</string>
@@ -693,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Meldingen"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Batterij"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Screenshots"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Algemene berichten"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"Opslag"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Hints"</string>
<string name="instant_apps" msgid="8337185853050247304">"Instant-apps"</string>
@@ -727,6 +736,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"Aanzetten als de batterij waarschijnlijk leeg raakt"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"Nee, bedankt"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"In gebruik"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Apps gebruiken je <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" en "</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Ga dichter naar <xliff:g id="DEVICENAME">%1$s</xliff:g> toe om af te spelen"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Ga dichter bij <xliff:g id="DEVICENAME">%1$s</xliff:g> staan om hier af te spelen"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Afspelen op <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Afspelen op deze telefoon"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Er is iets misgegaan. Probeer het opnieuw."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inactief, check de app"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Niet gevonden"</string>
@@ -853,6 +862,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"Opslaan"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"Starten…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"Kan niet uitzenden"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Kan niet opslaan. Probeer het opnieuw."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Kan niet opslaan."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Buildnummer"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Buildnummer naar klembord gekopieerd."</string>
<string name="basic_status" msgid="2315371112182658176">"Gesprek openen"</string>
@@ -937,6 +948,10 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Gekopieerde tekst bewerken"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Gekopieerde afbeelding bewerken"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Naar apparaat in de buurt sturen"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"Tik om te bekijken"</string>
+ <string name="clipboard_text_copied" msgid="5100836834278976679">"Tekst gekopieerd"</string>
+ <string name="clipboard_image_copied" msgid="3793365360174328722">"Afbeelding gekopieerd"</string>
+ <string name="clipboard_content_copied" msgid="144452398567828145">"Content gekopieerd"</string>
<string name="add" msgid="81036585205287996">"Toevoegen"</string>
<string name="manage_users" msgid="1823875311934643849">"Gebruikers beheren"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"Deze melding biedt geen ondersteuning voor slepen naar het gesplitste scherm."</string>
@@ -945,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Wekker gezet"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Camera en microfoon staan uit"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# melding}other{# meldingen}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Uitzending"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Uitzending van <xliff:g id="APP_NAME">%1$s</xliff:g> stopzetten?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Als je <xliff:g id="SWITCHAPP">%1$s</xliff:g> uitzendt of de uitvoer wijzigt, wordt je huidige uitzending gestopt"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> uitzenden"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Uitvoer wijzigen"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Onbekend"</string>
</resources>
diff --git a/packages/SystemUI/res/values-nl/tiles_states_strings.xml b/packages/SystemUI/res/values-nl/tiles_states_strings.xml
index c4603b2..fbccd78 100644
--- a/packages/SystemUI/res/values-nl/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-nl/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Uit"</item>
<item msgid="460891964396502657">"Aan"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Niet beschikbaar"</item>
+ <item msgid="8014986104355098744">"Uit"</item>
+ <item msgid="5966994759929723339">"Aan"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index e9793b7..1dcf0c7 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -36,7 +36,7 @@
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> ଆକ୍ସେସ୍ କରିବାକୁ <xliff:g id="APPLICATION">%1$s</xliff:g>କୁ ଅନୁମତି ଦେବେ କି?\nଏହି ଆପ୍କୁ ରେକର୍ଡ କରିବାକୁ ଅନୁମତି ଦିଆଯାଇ ନାହିଁ କିନ୍ତୁ ଏହି USB ଡିଭାଇସ୍ ଜରିଆରେ ଅଡିଓ କ୍ୟାପ୍ଟର୍ କରିପାରିବ।"</string>
<string name="usb_audio_device_permission_prompt_title" msgid="4221351137250093451">"<xliff:g id="USB_DEVICE">%2$s</xliff:g>କୁ ଆକ୍ସେସ କରିବା ପାଇଁ <xliff:g id="APPLICATION">%1$s</xliff:g>କୁ ଅନୁମତି ଦେବେ?"</string>
<string name="usb_audio_device_confirm_prompt_title" msgid="8828406516732985696">"<xliff:g id="USB_DEVICE">%2$s</xliff:g>କୁ ନିୟନ୍ତ୍ରଣ କରିବା ପାଇଁ <xliff:g id="APPLICATION">%1$s</xliff:g>କୁ ଖୋଲିବେ?"</string>
- <string name="usb_audio_device_prompt_warn" msgid="2504972133361130335">"ଏହି ଆପକୁ ରେକର୍ଡ କରିବା ପାଇଁ ଅନୁମତି ଦିଆଯାଇନାହିଁ, କିନ୍ତୁ ଏହି USB ଡିଭାଇସ ମାଧ୍ୟମରେ ଏହା ଅଡିଓକୁ କ୍ୟାପଚର କରିପାରିବ। ଏହି ଡିଭାଇସରେ <xliff:g id="APPLICATION">%1$s</xliff:g> ବ୍ୟବହାର କରିବା କଲ, ବିଜ୍ଞପ୍ତି ଏବଂ ଆଲାରାମଗୁଡ଼ିକୁ ଶୁଣିବାରୁ ପ୍ରତିରୋଧ କରିପାରେ।"</string>
+ <string name="usb_audio_device_prompt_warn" msgid="2504972133361130335">"ଏହି ଆପକୁ ରେକର୍ଡ କରିବା ପାଇଁ ଅନୁମତି ଦିଆଯାଇନାହିଁ, କିନ୍ତୁ ଏହି USB ଡିଭାଇସ ମାଧ୍ୟମରେ ଏହା ଅଡିଓକୁ କ୍ୟାପଚର କରିପାରିବ। ଏହି ଡିଭାଇସରେ <xliff:g id="APPLICATION">%1$s</xliff:g> ବ୍ୟବହାର କଲେ କଲ, ବିଜ୍ଞପ୍ତି ଏବଂ ଆଲାରାମଗୁଡ଼ିକୁ ଶୁଣିବାରୁ ପ୍ରତିରୋଧ କରାଯାଇପାରେ।"</string>
<string name="usb_audio_device_prompt" msgid="7944987408206252949">"ଏହି ଡିଭାଇସରେ <xliff:g id="APPLICATION">%1$s</xliff:g> ବ୍ୟବହାର କରିବା କଲ, ବିଜ୍ଞପ୍ତି ଏବଂ ଆଲାରାମଗୁଡ଼ିକୁ ଶୁଣିବାରୁ ପ୍ରତିରୋଧ କରିପାରେ।"</string>
<string name="usb_accessory_permission_prompt" msgid="717963550388312123">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g> ଆକ୍ସେସ୍ କରିବାକୁ <xliff:g id="APPLICATION">%1$s</xliff:g>କୁ ଅନୁମତି ଦେବେ?"</string>
<string name="usb_device_confirm_prompt" msgid="4091711472439910809">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> ନିୟନ୍ତ୍ରଣ କରିବାକୁ <xliff:g id="APPLICATION">%1$s</xliff:g> ଖୋଲିବେ?"</string>
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"ପୁଣିଥରେ ସ୍କ୍ରୀନ୍ଶଟ୍ ନେବାକୁ ଚେଷ୍ଟା କରନ୍ତୁ"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"ସ୍କ୍ରିନସଟକୁ ସେଭ୍ କରାଯାଇପାରିବ ନାହିଁ"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"ଆପ୍ କିମ୍ବା ସଂସ୍ଥା ଦ୍ୱାରା ସ୍କ୍ରୀନଶଟ୍ ନେବାକୁ ଅନୁମତି ଦିଆଯାଇ ନାହିଁ"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"ସ୍କ୍ରିନସଟଗୁଡ଼ିକ ନେବା ଆପଣଙ୍କ IT ଆଡମିନଙ୍କ ଦ୍ୱାରା ବ୍ଲକ କରାଯାଇଛି"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"ଏଡିଟ୍ କରନ୍ତୁ"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"ସ୍କ୍ରିନସଟ୍ ଏଡିଟ୍ କରନ୍ତୁ"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"ସ୍କ୍ରିନସଟ ସେୟାର କରନ୍ତୁ"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"ଅଟୋ-ରୋଟେଟ୍"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"ଅଟୋ-ରୋଟେଟ୍ ସ୍କ୍ରିନ୍"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"ଲୋକେସନ୍"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"ସ୍କ୍ରିନ ସେଭର"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"କ୍ୟାମେରା ଆକ୍ସେସ୍"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"ମାଇକ୍ ଆକ୍ସେସ୍"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"ଉପଲବ୍ଧ"</string>
@@ -318,6 +320,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"ଫେସ ମାଧ୍ୟମରେ ଅନଲକ କରାଯାଇଛି। ଖୋଲିବାକୁ ଦବାନ୍ତୁ।"</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"ଫେସ ଚିହ୍ନଟ କରାଯାଇଛି। ଖୋଲିବାକୁ ଦବାନ୍ତୁ।"</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"ଫେସ ଚିହ୍ନଟ କରାଯାଇଛି। ଖୋଲିବାକୁ ଅନଲକ ଆଇକନ ଦବାନ୍ତୁ।"</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"ପୁଣି ଚେଷ୍ଟା କରିବା ପାଇଁ ଉପରକୁ ସ୍ୱାଇପ୍ କରନ୍ତୁ"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC ବ୍ୟବହାର କରିବାକୁ ଅନଲକ୍ କରନ୍ତୁ"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"ଏହି ଡିଭାଇସଟି ଆପଣଙ୍କ ସଂସ୍ଥାର ଅଟେ"</string>
@@ -467,7 +473,7 @@
<string name="wallet_title" msgid="5369767670735827105">"ୱାଲେଟ୍"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"ଆପଣଙ୍କ ଫୋନ୍ ମାଧ୍ୟମରେ ଆହୁରି ଶୀଘ୍ର, ଅଧିକ ସୁରକ୍ଷିତ କ୍ରୟ କରିବା ପାଇଁ ସେଟ୍ ଅପ୍ କରନ୍ତୁ"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"ସବୁ ଦେଖାନ୍ତୁ"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"ଏକ କାର୍ଡ ଯୋଗ କରନ୍ତୁ"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"ଖୋଲିବାକୁ ଟାପ କରନ୍ତୁ"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"ଅପଡେଟ୍ ହେଉଛି"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ବ୍ୟବହାର କରିବାକୁ ଅନଲକ୍ କରନ୍ତୁ"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"ଆପଣଙ୍କ କାର୍ଡଗୁଡ଼ିକ ପାଇବାରେ ଏକ ସମସ୍ୟା ହୋଇଥିଲା। ଦୟାକରି ପରେ ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ"</string>
@@ -693,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"ଆଲର୍ଟଗୁଡ଼ିକ"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"ବ୍ୟାଟେରୀ"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"ସ୍କ୍ରୀନଶଟ୍"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"ସାଧାରଣ ମେସେଜ୍"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"ଷ୍ଟୋରେଜ୍"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"ହିଣ୍ଟ"</string>
<string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string>
@@ -727,6 +736,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"ବ୍ୟାଟେରୀ ସରିବାକୁ ଥିବା ସମୟରେ ଚାଲୁ କରନ୍ତୁ"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"ନାହିଁ, ଥାଉ"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"SysUI ହିପ୍ ଡମ୍ପ୍ କରନ୍ତୁ"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"ବ୍ୟବହାର ହେଉଛି"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"ଆପ୍ଲିକେସନ୍ଗୁଡିକ ଆପଣଙ୍କ <xliff:g id="TYPES_LIST">%s</xliff:g> ବ୍ୟବହାର କରୁଛନ୍ତି।"</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" ଏବଂ "</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g>ରେ ଚଲାଇବା ପାଇଁ ପାଖକୁ ମୁଭ କରନ୍ତୁ"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"ଏଠାରେ ଚଲାଇବା ପାଇଁ <xliff:g id="DEVICENAME">%1$s</xliff:g>ର ପାଖକୁ ମୁଭ କରନ୍ତୁ"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g>ରେ ଚାଲୁଛି"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"ଏହି ଫୋନରେ ଚାଲୁଛି"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"କିଛି ତ୍ରୁଟି ହୋଇଛି। ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"ନିଷ୍କ୍ରିୟ ଅଛି, ଆପ ଯାଞ୍ଚ କରନ୍ତୁ"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"ମିଳିଲା ନାହିଁ"</string>
@@ -853,6 +862,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"ସେଭ କରନ୍ତୁ"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"ଆରମ୍ଭ ହେଉଛି…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"ବ୍ରଡକାଷ୍ଟ କରାଯାଇପାରିବ ନାହିଁ"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"ସେଭ କରାଯାଇପାରିଲା ନାହିଁ। ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"ସେଭ କରାଯାଇପାରିଲା ନାହିଁ।"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"ବିଲ୍ଡ ନମ୍ୱର"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"କ୍ଲିପବୋର୍ଡକୁ କପି କରାଯାଇଥିବା ବିଲ୍ଡ ନମ୍ୱର।"</string>
<string name="basic_status" msgid="2315371112182658176">"ବାର୍ତ୍ତାଳାପ ଖୋଲନ୍ତୁ"</string>
@@ -937,6 +948,13 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"କପି କରାଯାଇଥିବା ଟେକ୍ସଟକୁ ଏଡିଟ କରନ୍ତୁ"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"କପି କରାଯାଇଥିବା ଇମେଜକୁ ଏଡିଟ କରନ୍ତୁ"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"ନିକଟସ୍ଥ ଡିଭାଇସକୁ ପଠାନ୍ତୁ"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"ଦେଖିବାକୁ ଟାପ କରନ୍ତୁ"</string>
+ <!-- no translation found for clipboard_text_copied (5100836834278976679) -->
+ <skip />
+ <!-- no translation found for clipboard_image_copied (3793365360174328722) -->
+ <skip />
+ <!-- no translation found for clipboard_content_copied (144452398567828145) -->
+ <skip />
<string name="add" msgid="81036585205287996">"ଯୋଗ କରନ୍ତୁ"</string>
<string name="manage_users" msgid="1823875311934643849">"ଉପଯୋଗକର୍ତ୍ତାମାନଙ୍କୁ ପରିଚାଳନା କରନ୍ତୁ"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"ଏହି ବିଜ୍ଞପ୍ତି ସ୍ପ୍ଲିଟସ୍କ୍ରିନକୁ ଡ୍ରାଗ କରିବାକୁ ସମର୍ଥନ କରେ ନାହିଁ।"</string>
@@ -945,4 +963,12 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"ଆଲାରାମ ସେଟ"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"କ୍ୟାମେରା ଏବଂ ମାଇକ ବନ୍ଦ ଅଛି"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{#ଟି ବିଜ୍ଞପ୍ତି}other{#ଟି ବିଜ୍ଞପ୍ତି}}"</string>
+ <!-- no translation found for broadcasting_description_is_broadcasting (765627502786404290) -->
+ <skip />
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> ବ୍ରଡକାଷ୍ଟ କରିବା ବନ୍ଦ କରିବେ?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"ଯଦି ଆପଣ <xliff:g id="SWITCHAPP">%1$s</xliff:g> ବ୍ରଡକାଷ୍ଟ କରନ୍ତି କିମ୍ବା ଆଉଟପୁଟ ବଦଳାନ୍ତି, ତେବେ ଆପଣଙ୍କ ବର୍ତ୍ତମାନର ବ୍ରଡକାଷ୍ଟ ବନ୍ଦ ହୋଇଯିବ"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> ବ୍ରଡକାଷ୍ଟ କରନ୍ତୁ"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"ଆଉଟପୁଟ ବଦଳାନ୍ତୁ"</string>
+ <!-- no translation found for bt_le_audio_broadcast_dialog_unknown_name (3791472237793443044) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-or/tiles_states_strings.xml b/packages/SystemUI/res/values-or/tiles_states_strings.xml
index 2d9fb84..acaa3fb 100644
--- a/packages/SystemUI/res/values-or/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-or/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"ବନ୍ଦ ଅଛି"</item>
<item msgid="460891964396502657">"ଚାଲୁ ଅଛି"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"ଉପଲବ୍ଧ ନାହିଁ"</item>
+ <item msgid="8014986104355098744">"ବନ୍ଦ ଅଛି"</item>
+ <item msgid="5966994759929723339">"ଚାଲୁ ଅଛି"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 34b1cd5..ff08abc 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਦੁਬਾਰਾ ਲੈ ਕੇ ਦੇਖੋ"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਨੂੰ ਰੱਖਿਅਤ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"ਐਪ ਜਾਂ ਤੁਹਾਡੀ ਸੰਸਥਾ ਵੱਲੋਂ ਸਕ੍ਰੀਨਸ਼ਾਟ ਲੈਣ ਦੀ ਇਜਾਜ਼ਤ ਨਹੀਂ ਦਿੱਤੀ ਗਈ ਹੈ"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"ਤੁਹਾਡੇ ਆਈ.ਟੀ. ਪ੍ਰਸ਼ਾਸਕ ਵੱਲੋਂ ਸਕ੍ਰੀਨਸ਼ਾਟ ਲੈਣ ਦੀ ਸੁਵਿਧਾ ਨੂੰ ਬਲਾਕ ਕੀਤਾ ਗਿਆ ਹੈ"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"ਸੰਪਾਦਨ ਕਰੋ"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਦਾ ਸੰਪਾਦਨ ਕਰੋ"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਸਾਂਝਾ ਕਰੋ"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"ਸਵੈ-ਘੁਮਾਓ"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"ਸਕ੍ਰੀਨ ਨੂੰ ਆਪਣੇ ਆਪ ਘੁੰਮਾਓ"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"ਟਿਕਾਣਾ"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"ਸਕ੍ਰੀਨ ਸੇਵਰ"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"ਕੈਮਰਾ ਪਹੁੰਚ"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"ਮਾਈਕ ਪਹੁੰਚ"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"ਉਪਲਬਧ"</string>
@@ -318,6 +320,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"ਚਿਹਰੇ ਰਾਹੀਂ ਅਣਲਾਕ ਕੀਤਾ ਗਿਆ। ਖੋਲ੍ਹਣ ਲਈ ਦਬਾਓ।"</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"ਚਿਹਰੇ ਦੀ ਪਛਾਣ ਹੋਈ। ਖੋਲ੍ਹਣ ਲਈ ਦਬਾਓ।"</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"ਚਿਹਰੇ ਦੀ ਪਛਾਣ ਹੋਈ। ਖੋਲ੍ਹਣ ਲਈ \'ਅਣਲਾਕ ਕਰੋ\' ਪ੍ਰਤੀਕ ਨੂੰ ਦਬਾਓ।"</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰਨ ਲਈ ਉੱਤੇ ਵੱਲ ਸਵਾਈਪ ਕਰੋ"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC ਵਰਤਣ ਲਈ ਅਣਲਾਕ ਕਰੋ"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"ਇਹ ਡੀਵਾਈਸ ਤੁਹਾਡੀ ਸੰਸਥਾ ਨਾਲ ਸੰਬੰਧਿਤ ਹੈ"</string>
@@ -422,9 +428,9 @@
<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>
- <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"ਤੁਹਾਡੇ ਵੱਲੋਂ ਅਨਪਿੰਨ ਕੀਤੇ ਜਾਣ ਤੱਕ ਇਸਨੂੰ ਦਿਖਾਇਆ ਜਾਂਦਾ ਹੈ। ਅਨਪਿੰਨ ਕਰਨ ਲਈ ਉੱਪਰ ਵੱਲ ਸਵਾਈਪ ਕਰਕੇ ਰੱਖੋ।"</string>
+ <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"ਤੁਹਾਡੇ ਵੱਲੋਂ ਅਣਪਿੰਨ ਕੀਤੇ ਜਾਣ ਤੱਕ ਇਸਨੂੰ ਦਿਖਾਇਆ ਜਾਂਦਾ ਹੈ। ਅਣਪਿੰਨ ਕਰਨ ਲਈ ਉੱਪਰ ਵੱਲ ਸਵਾਈਪ ਕਰਕੇ ਰੱਖੋ।"</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"ਇਹ ਇਸ ਨੂੰ ਤਦ ਤੱਕ ਦ੍ਰਿਸ਼ ਵਿੱਚ ਰੱਖਦਾ ਹੈ ਜਦ ਤੱਕ ਤੁਸੀਂ ਅਨਪਿੰਨ ਨਹੀਂ ਕਰਦੇ। ਅਨਪਿੰਨ ਕਰਨ ਲਈ \'ਰੂਪ-ਰੇਖਾ\' ਨੂੰ ਸਪੱਰਸ਼ ਕਰੋ ਅਤੇ ਦਬਾ ਕੇ ਰੱਖੋ।"</string>
- <string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"ਤੁਹਾਡੇ ਵੱਲੋਂ ਅਨਪਿੰਨ ਨਾ ਕੀਤੇ ਜਾਣ ਤੱਕ ਇਸਨੂੰ ਦਿਖਾਇਆ ਜਾਂਦਾ ਹੈ। ਅਨਪਿੰਨ ਕਰਨ ਲਈ \'ਹੋਮ\' ਨੂੰ ਸਪੱਰਸ਼ ਕਰਕੇ ਦਬਾਈ ਰੱਖੋ।"</string>
+ <string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"ਤੁਹਾਡੇ ਵੱਲੋਂ ਅਣਪਿੰਨ ਨਾ ਕੀਤੇ ਜਾਣ ਤੱਕ ਇਸਨੂੰ ਦਿਖਾਇਆ ਜਾਂਦਾ ਹੈ। ਅਣਪਿੰਨ ਕਰਨ ਲਈ \'ਹੋਮ\' ਨੂੰ ਸਪਰਸ਼ ਕਰਕੇ ਰੱਖੋ।"</string>
<string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"ਨਿੱਜੀ ਡਾਟੇ ਤੱਕ ਪਹੁੰਚ ਕੀਤੀ ਜਾ ਸਕਦੀ ਹੈ (ਜਿਵੇਂ ਕਿ ਸੰਪਰਕ ਅਤੇ ਈਮੇਲ ਸਮੱਗਰੀ)।"</string>
<string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"ਪਿੰਨ ਕੀਤੀ ਐਪ ਹੋਰ ਐਪਾਂ ਨੂੰ ਖੋਲ੍ਹ ਸਕਦੀ ਹੈ।"</string>
<string name="screen_pinning_toast" msgid="8177286912533744328">"ਇਸ ਐਪ ਨੂੰ ਅਨਪਿੰਨ ਕਰਨ ਲਈ, \'ਪਿੱਛੇ\' ਅਤੇ \'ਰੂਪ-ਰੇਖਾ\' ਬਟਨਾਂ ਨੂੰ ਸਪਰਸ਼ ਕਰਕੇ ਦਬਾਈ ਰੱਖੋ"</string>
@@ -467,7 +473,7 @@
<string name="wallet_title" msgid="5369767670735827105">"ਵਾਲੇਟ"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"ਆਪਣੇ ਫ਼ੋਨ ਨਾਲ ਜ਼ਿਆਦਾ ਤੇਜ਼ ਅਤੇ ਜ਼ਿਆਦਾ ਸੁਰੱਖਿਅਤ ਖਰੀਦਾਂ ਕਰਨ ਲਈ ਸੈੱਟਅੱਪ ਕਰੋ"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"ਸਭ ਦਿਖਾਓ"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"ਕੋਈ ਕਾਰਡ ਸ਼ਾਮਲ ਕਰੋ"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"ਖੋਲ੍ਹਣ ਲਈ ਟੈਪ ਕਰੋ"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"ਅੱਪਡੇਟ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ਵਰਤਣ ਲਈ ਅਣਲਾਕ ਕਰੋ"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"ਤੁਹਾਡੇ ਕਾਰਡ ਪ੍ਰਾਪਤ ਕਰਨ ਵਿੱਚ ਕੋਈ ਸਮੱਸਿਆ ਆਈ, ਕਿਰਪਾ ਕਰਕੇ ਬਾਅਦ ਵਿੱਚ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ"</string>
@@ -693,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"ਸੁਚੇਤਨਾਵਾਂ"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"ਬੈਟਰੀ"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"ਸਕ੍ਰੀਨਸ਼ਾਟ"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"ਆਮ ਸੁਨੇਹੇ"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"ਸਟੋਰੇਜ"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"ਸੰਕੇਤ"</string>
<string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string>
@@ -727,6 +736,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"ਬੈਟਰੀ ਖਤਮ ਹੋਣ ਦੀ ਸੰਭਾਵਨਾ \'ਤੇ ਚਾਲੂ ਹੁੰਦਾ ਹੈ"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"ਨਹੀਂ ਧੰਨਵਾਦ"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"SysUI ਹੀਪ ਡੰਪ ਕਰੋ"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"ਵਰਤੋਂ ਵਿੱਚ"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"ਐਪਲੀਕੇਸ਼ਨਾਂ ਤੁਹਾਡੇ <xliff:g id="TYPES_LIST">%s</xliff:g> ਦੀ ਵਰਤੋਂ ਕਰ ਰਹੀਆਂ ਹਨ।"</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" ਅਤੇ "</string>
@@ -804,7 +814,7 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"ਹੋਰ ਦੇਖਣ ਲਈ ਸਵਾਈਪ ਕਰੋ"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"ਸਿਫ਼ਾਰਸ਼ਾਂ ਲੋਡ ਹੋ ਰਹੀਆਂ ਹਨ"</string>
<string name="controls_media_title" msgid="1746947284862928133">"ਮੀਡੀਆ"</string>
- <string name="controls_media_close_session" msgid="4780485355795635052">"ਕੀ <xliff:g id="APP_NAME">%1$s</xliff:g> ਲਈ ਇਸ ਮੀਡੀਆ ਕੰਟਰੋਲ ਲੁਕਾਉਣਾ ਹੈ?"</string>
+ <string name="controls_media_close_session" msgid="4780485355795635052">"ਕੀ <xliff:g id="APP_NAME">%1$s</xliff:g> ਲਈ ਇਹ ਮੀਡੀਆ ਕੰਟਰੋਲ ਲੁਕਾਉਣਾ ਹੈ?"</string>
<string name="controls_media_active_session" msgid="3146882316024153337">"ਮੌਜੂਦਾ ਮੀਡੀਆ ਸੈਸ਼ਨ ਲੁਕਾਇਆ ਨਹੀਂ ਜਾ ਸਕਦਾ।"</string>
<string name="controls_media_dismiss_button" msgid="4485675693008031646">"ਲੁਕਾਓ"</string>
<string name="controls_media_resume" msgid="1933520684481586053">"ਮੁੜ-ਚਾਲੂ ਕਰੋ"</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g> \'ਤੇ ਚਲਾਉਣ ਲਈ ਨੇੜੇ ਲਿਜਾਓ"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"ਇੱਥੇ ਚਲਾਉਣ ਲਈ <xliff:g id="DEVICENAME">%1$s</xliff:g> ਦੇ ਨੇੜੇ ਜਾਓ"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> \'ਤੇ ਚਲਾਇਆ ਜਾ ਰਿਹਾ ਹੈ"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"ਇਸ ਫ਼ੋਨ \'ਤੇ ਚਲਾਇਆ ਜਾ ਰਿਹਾ ਹੈ"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"ਕੋਈ ਗੜਬੜ ਹੋ ਗਈ। ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"ਅਕਿਰਿਆਸ਼ੀਲ, ਐਪ ਦੀ ਜਾਂਚ ਕਰੋ"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"ਨਹੀਂ ਮਿਲਿਆ"</string>
@@ -853,6 +862,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"ਰੱਖਿਅਤ ਕਰੋ"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"ਸ਼ੁਰੂ ਹੋ ਰਿਹਾ ਹੈ…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"ਪ੍ਰਸਾਰਨ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"ਰੱਖਿਅਤ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ। ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"ਰੱਖਿਅਤ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ।"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"ਬਿਲਡ ਨੰਬਰ"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"ਬਿਲਡ ਨੰਬਰ ਨੂੰ ਕਲਿੱਪਬੋਰਡ \'ਤੇ ਕਾਪੀ ਕੀਤਾ ਗਿਆ।"</string>
<string name="basic_status" msgid="2315371112182658176">"ਗੱਲਬਾਤ ਖੋਲ੍ਹੋ"</string>
@@ -937,6 +948,13 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"ਕਾਪੀ ਕੀਤੀ ਲਿਖਤ ਦਾ ਸੰਪਾਦਨ ਕਰੋ"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"ਕਾਪੀ ਕੀਤੇ ਗਏ ਚਿੱਤਰ ਦਾ ਸੰਪਾਦਨ ਕਰੋ"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"ਨਜ਼ਦੀਕੀ ਡੀਵਾਈਸ \'ਤੇ ਭੇਜੋ"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"ਦੇਖਣ ਲਈ ਟੈਪ ਕਰੋ"</string>
+ <!-- no translation found for clipboard_text_copied (5100836834278976679) -->
+ <skip />
+ <!-- no translation found for clipboard_image_copied (3793365360174328722) -->
+ <skip />
+ <!-- no translation found for clipboard_content_copied (144452398567828145) -->
+ <skip />
<string name="add" msgid="81036585205287996">"ਸ਼ਾਮਲ ਕਰੋ"</string>
<string name="manage_users" msgid="1823875311934643849">"ਵਰਤੋਂਕਾਰਾਂ ਦਾ ਪ੍ਰਬੰਧਨ ਕਰੋ"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"ਇਹ ਸੂਚਨਾ ਸਪਲਿਟ ਸਕ੍ਰੀਨ \'ਤੇ ਘਸੀਟਣ ਦਾ ਸਮਰਥਨ ਨਹੀਂ ਕਰਦੀ ਹੈ।"</string>
@@ -945,4 +963,12 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"ਅਲਾਰਮ ਸੈੱਟ ਹੈ"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"ਕੈਮਰਾ ਅਤੇ ਮਾਈਕ ਬੰਦ ਹਨ"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# ਸੂਚਨਾ}one{# ਸੂਚਨਾ}other{# ਸੂਚਨਾਵਾਂ}}"</string>
+ <!-- no translation found for broadcasting_description_is_broadcasting (765627502786404290) -->
+ <skip />
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"ਕੀ <xliff:g id="APP_NAME">%1$s</xliff:g> ਦੇ ਪ੍ਰਸਾਰਨ ਨੂੰ ਰੋਕਣਾ ਹੈ?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"ਜੇ ਤੁਸੀਂ <xliff:g id="SWITCHAPP">%1$s</xliff:g> ਦਾ ਪ੍ਰਸਾਰਨ ਕਰਦੇ ਹੋ ਜਾਂ ਆਊਟਪੁੱਟ ਬਦਲਦੇ ਹੋ, ਤਾਂ ਤੁਹਾਡਾ ਮੌਜੂਦਾ ਪ੍ਰਸਾਰਨ ਰੁਕ ਜਾਵੇਗਾ"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> ਦਾ ਪ੍ਰਸਾਰਨ ਕਰੋ"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"ਆਊਟਪੁੱਟ ਬਦਲੋ"</string>
+ <!-- no translation found for bt_le_audio_broadcast_dialog_unknown_name (3791472237793443044) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-pa/tiles_states_strings.xml b/packages/SystemUI/res/values-pa/tiles_states_strings.xml
index 737b2b6..9653b92 100644
--- a/packages/SystemUI/res/values-pa/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-pa/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"ਬੰਦ"</item>
<item msgid="460891964396502657">"ਚਾਲੂ"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"ਉਪਲਬਧ ਨਹੀਂ"</item>
+ <item msgid="8014986104355098744">"ਬੰਦ"</item>
+ <item msgid="5966994759929723339">"ਚਾਲੂ"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 0a4479f..3ba112c 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Spróbuj jeszcze raz wykonać zrzut ekranu"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"Nie można zapisać zrzutu ekranu."</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Nie możesz wykonać zrzutu ekranu, bo nie zezwala na to aplikacja lub Twoja organizacja."</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Robienie zrzutów ekranu zostało zablokowane przez administratora IT"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Edytuj"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Edytuj zrzut ekranu"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"Udostępnij zrzut ekranu"</string>
@@ -227,6 +228,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Autoobracanie"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Autoobracanie ekranu"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Lokalizacja"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Wygaszacz ekranu"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Dostęp do aparatu"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Dostęp do mikrofonu"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Odblokowany"</string>
@@ -322,6 +324,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Odblokowano rozpoznawaniem twarzy. Naciśnij, by otworzyć."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Twarz rozpoznana. Naciśnij, by otworzyć."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Twarz rozpoznana. Aby otworzyć, kliknij ikonę odblokowywania."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"Przesuń w górę, by spróbować ponownie"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Odblokuj, by użyć komunikacji NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"To urządzenie należy do Twojej organizacji"</string>
@@ -473,7 +479,7 @@
<string name="wallet_title" msgid="5369767670735827105">"Portfel"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"Skonfiguruj formę płatności, aby szybciej i bezpieczniej płacić telefonem za zakupy"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"Pokaż wszystko"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"Dodaj kartę"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"Kliknij, aby otworzyć"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"Aktualizuję"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Odblokuj, aby użyć"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Podczas pobierania kart wystąpił problem. Spróbuj ponownie później."</string>
@@ -703,7 +709,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Alerty"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Bateria"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Zrzuty ekranu"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Wiadomości"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"Pamięć wewnętrzna"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Wskazówki"</string>
<string name="instant_apps" msgid="8337185853050247304">"Aplikacje błyskawiczne"</string>
@@ -737,6 +746,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"Oszczędzanie baterii włącza się, jeśli bateria jest prawie wyczerpana"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"Nie, dziękuję"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Zrzut stosu SysUI"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"W użyciu"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Aplikacje używają: <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" i "</string>
@@ -816,7 +826,7 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Przesuń palcem, by zobaczyć więcej"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Wczytuję rekomendacje"</string>
<string name="controls_media_title" msgid="1746947284862928133">"Multimedia"</string>
- <string name="controls_media_close_session" msgid="4780485355795635052">"Ukryć tę opcję sterowania multimediami w aplikacji <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="controls_media_close_session" msgid="4780485355795635052">"Ukryć sterowanie multimediami w aplikacji <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="controls_media_active_session" msgid="3146882316024153337">"Nie można ukryć tej sesji multimediów."</string>
<string name="controls_media_dismiss_button" msgid="4485675693008031646">"Ukryj"</string>
<string name="controls_media_resume" msgid="1933520684481586053">"Wznów"</string>
@@ -836,7 +846,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Przysuń się bliżej, aby odtwarzać na urządzeniu <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Zbliż do urządzenia <xliff:g id="DEVICENAME">%1$s</xliff:g>, aby na nim odtwarzać"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Odtwarzam na ekranie <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Odtwarzam na tym telefonie"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Coś poszło nie tak. Spróbuj ponownie."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Nieaktywny, sprawdź aplikację"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Nie znaleziono"</string>
@@ -865,6 +874,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"Zapisz"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"Uruchamiam…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"Nie można przesyłać"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Nie można zapisać. Spróbuj ponownie."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Nie można zapisać."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Numer kompilacji"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Numer kompilacji został skopiowany do schowka."</string>
<string name="basic_status" msgid="2315371112182658176">"Otwarta rozmowa"</string>
@@ -951,6 +962,13 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Edytuj skopiowany tekst"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Edytuj skopiowany obraz"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Wyślij na urządzenie w pobliżu"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"Kliknij, aby wyświetlić"</string>
+ <!-- no translation found for clipboard_text_copied (5100836834278976679) -->
+ <skip />
+ <!-- no translation found for clipboard_image_copied (3793365360174328722) -->
+ <skip />
+ <!-- no translation found for clipboard_content_copied (144452398567828145) -->
+ <skip />
<string name="add" msgid="81036585205287996">"Dodaj"</string>
<string name="manage_users" msgid="1823875311934643849">"Zarządzaj użytkownikami"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"To powiadomienie nie obsługuje dzielenia ekranu przez przeciąganie."</string>
@@ -959,4 +977,12 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm ustawiony"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Aparat i mikrofon są wyłączone"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# powiadomienie}few{# powiadomienia}many{# powiadomień}other{# powiadomienia}}"</string>
+ <!-- no translation found for broadcasting_description_is_broadcasting (765627502786404290) -->
+ <skip />
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Zatrzymaj transmisję aplikacji <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Jeśli transmitujesz aplikację <xliff:g id="SWITCHAPP">%1$s</xliff:g> lub zmieniasz dane wyjściowe, Twoja obecna transmisja zostanie zakończona"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Transmisja aplikacji <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Zmień dane wyjściowe"</string>
+ <!-- no translation found for bt_le_audio_broadcast_dialog_unknown_name (3791472237793443044) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-pl/tiles_states_strings.xml b/packages/SystemUI/res/values-pl/tiles_states_strings.xml
index f5d8f1f..50650986 100644
--- a/packages/SystemUI/res/values-pl/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-pl/tiles_states_strings.xml
@@ -62,9 +62,9 @@
<item msgid="8527389108867454098">"Włączona"</item>
</string-array>
<string-array name="tile_states_rotation">
- <item msgid="4578491772376121579">"Niedostępny"</item>
- <item msgid="5776427577477729185">"Wyłączony"</item>
- <item msgid="7105052717007227415">"Włączony"</item>
+ <item msgid="4578491772376121579">"Niedostępne"</item>
+ <item msgid="5776427577477729185">"Wyłączone"</item>
+ <item msgid="7105052717007227415">"Włączone"</item>
</string-array>
<string-array name="tile_states_bt">
<item msgid="5330252067413512277">"Niedostępny"</item>
@@ -127,9 +127,9 @@
<item msgid="578444932039713369">"Włączony"</item>
</string-array>
<string-array name="tile_states_reverse">
- <item msgid="3574611556622963971">"Niedostępny"</item>
- <item msgid="8707481475312432575">"Wyłączony"</item>
- <item msgid="8031106212477483874">"Włączony"</item>
+ <item msgid="3574611556622963971">"Niedostępne"</item>
+ <item msgid="8707481475312432575">"Wyłączone"</item>
+ <item msgid="8031106212477483874">"Włączone"</item>
</string-array>
<string-array name="tile_states_reduce_brightness">
<item msgid="1839836132729571766">"Niedostępny"</item>
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Wyłączony"</item>
<item msgid="460891964396502657">"Włączony"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Brak dostępu"</item>
+ <item msgid="8014986104355098744">"Wyłączono"</item>
+ <item msgid="5966994759929723339">"Włączono"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index de30189..bcfa1a1 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Tente fazer a captura de tela novamente"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"Não foi possível salvar a captura de tela"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"O app ou a organização não permitem capturas de tela"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"As capturas de tela foram bloqueadas pelo administrador de TI"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Editar"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Editar captura de tela"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"Compartilhar captura de tela"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Giro automático"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Giro automático da tela"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Localização"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Protetor de tela"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Acesso à câmera"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Acesso ao microfone"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Disponível"</string>
@@ -318,6 +320,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Desbloqueado pelo rosto. Pressione para abrir."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Rosto reconhecido. Pressione para abrir."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Rosto reconhecido. Pressione o ícone de desbloq. para abrir."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"Deslize para cima para tentar novamente"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Desbloqueie para usar a NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Este dispositivo pertence à sua organização"</string>
@@ -467,7 +473,7 @@
<string name="wallet_title" msgid="5369767670735827105">"Carteira"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"Prepare tudo para fazer compras mais rápidas e seguras com seu smartphone"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"Mostrar tudo"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"Adicionar um cartão"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"Toque para abrir"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"Atualizando"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Desbloquear para usar"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Ocorreu um problema ao carregar os cards. Tente novamente mais tarde"</string>
@@ -626,7 +632,7 @@
<string name="left_icon" msgid="5036278531966897006">"Ícone à esquerda"</string>
<string name="right_icon" msgid="1103955040645237425">"Ícone à direita"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"Mantenha pressionado e arraste para adicionar blocos"</string>
- <string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Mantenha o bloco pressionado e arraste para reorganizar"</string>
+ <string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Para reorganizar, toque no bloco sem soltar e arraste."</string>
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Arraste aqui para remover"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"É preciso haver pelo menos <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> blocos"</string>
<string name="qs_edit" msgid="5583565172803472437">"Editar"</string>
@@ -693,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Alertas"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Bateria"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Capturas de tela"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Mensagens gerais"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"Armazenamento"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Dicas"</string>
<string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string>
@@ -727,6 +736,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"Ativada quando há possibilidade de a bateria acabar"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"Não"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Despejar heap SysUI"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"Em uso"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Aplicativos estão usando <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" e "</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Aproxime os dispositivos para tocar a mídia neste: <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Aproxime-se do dispositivo <xliff:g id="DEVICENAME">%1$s</xliff:g> para abrir a mídia aqui"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Mídia aberta no dispositivo <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Mídia aberta neste smartphone"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Algo deu errado. Tente novamente."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inativo, verifique o app"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Não encontrado"</string>
@@ -853,6 +862,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"Salvar"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"Iniciando…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"Não foi possível fazer a transmissão"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Falha ao salvar. Tente de novo."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Falha ao salvar."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Número da versão"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Número da versão copiado para a área de transferência."</string>
<string name="basic_status" msgid="2315371112182658176">"Conversa aberta"</string>
@@ -927,7 +938,7 @@
</plurals>
<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="6839542063522121108">"Mesmo que você não esteja usando esses apps, eles ainda ficam ativos e podem afetar a duração da bateria"</string>
+ <string name="fgs_manager_dialog_message" msgid="6839542063522121108">"Mesmo que você não esteja usando estes apps, eles ainda ficam ativos e podem afetar a duração da bateria"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Parar"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Parado"</string>
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Concluído"</string>
@@ -937,6 +948,13 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Editar texto copiado"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Editar imagem copiada"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Enviar para dispositivo próximo"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"Toque para ver"</string>
+ <!-- no translation found for clipboard_text_copied (5100836834278976679) -->
+ <skip />
+ <!-- no translation found for clipboard_image_copied (3793365360174328722) -->
+ <skip />
+ <!-- no translation found for clipboard_content_copied (144452398567828145) -->
+ <skip />
<string name="add" msgid="81036585205287996">"Adicionar"</string>
<string name="manage_users" msgid="1823875311934643849">"Gerenciar usuários"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"Esta notificação não tem suporte para ser arrastada para a tela dividida."</string>
@@ -945,4 +963,12 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarme definido"</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>
+ <!-- no translation found for broadcasting_description_is_broadcasting (765627502786404290) -->
+ <skip />
+ <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>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Se você transmitir o app <xliff:g id="SWITCHAPP">%1$s</xliff:g> ou mudar a saída, a transmissão atual será interrompida"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Transmitir <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Mudar saída"</string>
+ <!-- no translation found for bt_le_audio_broadcast_dialog_unknown_name (3791472237793443044) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/tiles_states_strings.xml b/packages/SystemUI/res/values-pt-rBR/tiles_states_strings.xml
index abf8749..bc7efe6 100644
--- a/packages/SystemUI/res/values-pt-rBR/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Desativado"</item>
<item msgid="460891964396502657">"Ativado"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Indisponível"</item>
+ <item msgid="8014986104355098744">"Desativado"</item>
+ <item msgid="5966994759929723339">"Ativado"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index c7bead5..6b4cb52 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Experimente voltar a efetuar a captura de ecrã."</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"Não é possível guardar a captura de ecrã."</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"A app ou a sua entidade não permitem tirar capturas de ecrã"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"A capacidade de fazer capturas de ecrã foi bloqueada pelo administrador de TI"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Editar"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Editar captura de ecrã"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"Partilhar captura de ecrã"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Rotação auto."</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Rodar o ecrã automaticamente"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Localização"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Proteção de ecrã"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Acesso câmara"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Ac. microfone"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Disponível"</string>
@@ -318,6 +320,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Desbloqueado com o rosto. Prima para abrir."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Rosto reconhecido. Prima para abrir."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Rosto reconhecido. Prima o ícone de desbloqueio para abrir."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"Deslize rapidamente para cima para tentar novamente."</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Desbloquear para utilizar o NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Este dispositivo pertence à sua entidade."</string>
@@ -425,7 +431,7 @@
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Esta opção mantém o item visível até o soltar. Deslize rapidamente para cima e mantenha pressionado para soltar."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Esta opção mantém o item visível até o soltar. Toque sem soltar em Vista geral para soltar."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Esta opção mantém o item visível até o soltar. Toque sem soltar em Página inicial para soltar."</string>
- <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Os dados pessoais podem ficar acessíveis (tais como contactos e conteúdo do email)."</string>
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Os dados pessoais, tais como contactos e conteúdo do email, podem ficar acessíveis."</string>
<string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Uma app fixada pode abrir outras apps."</string>
<string name="screen_pinning_toast" msgid="8177286912533744328">"Para soltar esta app, toque sem soltar nos botões Anterior e Vista geral."</string>
<string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Para soltar esta app, toque sem soltar nos botões Anterior e Página inicial."</string>
@@ -467,7 +473,7 @@
<string name="wallet_title" msgid="5369767670735827105">"Carteira"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"Configure para efetuar pagamentos mais rápidos e seguros com o seu telemóvel"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"Mostrar tudo"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"Adicionar um cartão"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"Tocar para abrir"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"A atualizar"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Desbloquear para utilizar"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Ocorreu um problema ao obter os seus cartões. Tente novamente mais tarde."</string>
@@ -693,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Alertas"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Bateria"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Capturas de ecrã"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Mensagens gerais"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"Armazenamento"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Sugestões"</string>
<string name="instant_apps" msgid="8337185853050247304">"Apps instantâneas"</string>
@@ -727,6 +736,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"Ativar quando for provável que a bateria se esgote"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"Não"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Despejar pilha SysUI"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"Em utilização"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"As aplicações estão a utilizar o(a) <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" e "</string>
@@ -804,7 +814,7 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Deslize rapidamente para ver mais."</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"A carregar recomendações…"</string>
<string name="controls_media_title" msgid="1746947284862928133">"Multimédia"</string>
- <string name="controls_media_close_session" msgid="4780485355795635052">"Ocultar este controlo de multimédia para a app <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="controls_media_close_session" msgid="4780485355795635052">"Ocultar controlo de multimédia para a app <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="controls_media_active_session" msgid="3146882316024153337">"Não pode ocultar a sessão de multimédia atual."</string>
<string name="controls_media_dismiss_button" msgid="4485675693008031646">"Ocultar"</string>
<string name="controls_media_resume" msgid="1933520684481586053">"Retomar"</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Aproxime-se para reproduzir no dispositivo <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Aproxime-se do dispositivo <xliff:g id="DEVICENAME">%1$s</xliff:g> para reproduzir aqui"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"A reproduzir no dispositivo <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"A reproduzir neste telemóvel"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Algo correu mal. Tente novamente."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inativa. Consulte a app."</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Não encontrado."</string>
@@ -853,6 +862,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"Guardar"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"A iniciar…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"Não é possível transmitir"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Não é possível guardar. Tente novamente."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Não é possível guardar."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Número da compilação"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Número da compilação copiado para a área de transferência."</string>
<string name="basic_status" msgid="2315371112182658176">"Abrir conversa"</string>
@@ -916,7 +927,7 @@
<string name="see_all_networks" msgid="3773666844913168122">"Veja tudo"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Para mudar de rede, desligue a Ethernet"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"Para melhorar a experiência do dispositivo, as apps e os serviços podem continuar a procurar redes Wi-Fi em qualquer altura, mesmo quando o Wi-Fi está desativado. Pode alterar esta opção nas definições de procura de Wi-Fi. "<annotation id="link">"Alterar"</annotation></string>
- <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Desative o modo de avião"</string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Desativar o modo de avião"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"A app <xliff:g id="APPNAME">%1$s</xliff:g> pretende adicionar o seguinte mosaico às Definições rápidas"</string>
<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>
@@ -937,6 +948,13 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Editar texto copiado"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Editar imagem copiada"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Enviar para dispositivo próximo"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"Toque para ver"</string>
+ <!-- no translation found for clipboard_text_copied (5100836834278976679) -->
+ <skip />
+ <!-- no translation found for clipboard_image_copied (3793365360174328722) -->
+ <skip />
+ <!-- no translation found for clipboard_content_copied (144452398567828145) -->
+ <skip />
<string name="add" msgid="81036585205287996">"Adicionar"</string>
<string name="manage_users" msgid="1823875311934643849">"Gerir utilizadores"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"Esta notificação não pode ser arrastada para o ecrã dividido."</string>
@@ -945,4 +963,12 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarme definido"</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>
+ <!-- no translation found for broadcasting_description_is_broadcasting (765627502786404290) -->
+ <skip />
+ <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>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Se transmitir a app <xliff:g id="SWITCHAPP">%1$s</xliff:g> ou alterar a saída, a sua transmissão atual é interrompida"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Transmita a app <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Altere a saída"</string>
+ <!-- no translation found for bt_le_audio_broadcast_dialog_unknown_name (3791472237793443044) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/tiles_states_strings.xml b/packages/SystemUI/res/values-pt-rPT/tiles_states_strings.xml
index 8ffa760..03cafee 100644
--- a/packages/SystemUI/res/values-pt-rPT/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Desativado"</item>
<item msgid="460891964396502657">"Ativado"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Indisponível"</item>
+ <item msgid="8014986104355098744">"Desativado"</item>
+ <item msgid="5966994759929723339">"Ativado"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index de30189..bcfa1a1 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Tente fazer a captura de tela novamente"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"Não foi possível salvar a captura de tela"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"O app ou a organização não permitem capturas de tela"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"As capturas de tela foram bloqueadas pelo administrador de TI"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Editar"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Editar captura de tela"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"Compartilhar captura de tela"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Giro automático"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Giro automático da tela"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Localização"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Protetor de tela"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Acesso à câmera"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Acesso ao microfone"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Disponível"</string>
@@ -318,6 +320,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Desbloqueado pelo rosto. Pressione para abrir."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Rosto reconhecido. Pressione para abrir."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Rosto reconhecido. Pressione o ícone de desbloq. para abrir."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"Deslize para cima para tentar novamente"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Desbloqueie para usar a NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Este dispositivo pertence à sua organização"</string>
@@ -467,7 +473,7 @@
<string name="wallet_title" msgid="5369767670735827105">"Carteira"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"Prepare tudo para fazer compras mais rápidas e seguras com seu smartphone"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"Mostrar tudo"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"Adicionar um cartão"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"Toque para abrir"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"Atualizando"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Desbloquear para usar"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Ocorreu um problema ao carregar os cards. Tente novamente mais tarde"</string>
@@ -626,7 +632,7 @@
<string name="left_icon" msgid="5036278531966897006">"Ícone à esquerda"</string>
<string name="right_icon" msgid="1103955040645237425">"Ícone à direita"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"Mantenha pressionado e arraste para adicionar blocos"</string>
- <string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Mantenha o bloco pressionado e arraste para reorganizar"</string>
+ <string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Para reorganizar, toque no bloco sem soltar e arraste."</string>
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Arraste aqui para remover"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"É preciso haver pelo menos <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> blocos"</string>
<string name="qs_edit" msgid="5583565172803472437">"Editar"</string>
@@ -693,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Alertas"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Bateria"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Capturas de tela"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Mensagens gerais"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"Armazenamento"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Dicas"</string>
<string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string>
@@ -727,6 +736,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"Ativada quando há possibilidade de a bateria acabar"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"Não"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Despejar heap SysUI"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"Em uso"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Aplicativos estão usando <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" e "</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Aproxime os dispositivos para tocar a mídia neste: <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Aproxime-se do dispositivo <xliff:g id="DEVICENAME">%1$s</xliff:g> para abrir a mídia aqui"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Mídia aberta no dispositivo <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Mídia aberta neste smartphone"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Algo deu errado. Tente novamente."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inativo, verifique o app"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Não encontrado"</string>
@@ -853,6 +862,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"Salvar"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"Iniciando…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"Não foi possível fazer a transmissão"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Falha ao salvar. Tente de novo."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Falha ao salvar."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Número da versão"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Número da versão copiado para a área de transferência."</string>
<string name="basic_status" msgid="2315371112182658176">"Conversa aberta"</string>
@@ -927,7 +938,7 @@
</plurals>
<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="6839542063522121108">"Mesmo que você não esteja usando esses apps, eles ainda ficam ativos e podem afetar a duração da bateria"</string>
+ <string name="fgs_manager_dialog_message" msgid="6839542063522121108">"Mesmo que você não esteja usando estes apps, eles ainda ficam ativos e podem afetar a duração da bateria"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Parar"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Parado"</string>
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Concluído"</string>
@@ -937,6 +948,13 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Editar texto copiado"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Editar imagem copiada"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Enviar para dispositivo próximo"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"Toque para ver"</string>
+ <!-- no translation found for clipboard_text_copied (5100836834278976679) -->
+ <skip />
+ <!-- no translation found for clipboard_image_copied (3793365360174328722) -->
+ <skip />
+ <!-- no translation found for clipboard_content_copied (144452398567828145) -->
+ <skip />
<string name="add" msgid="81036585205287996">"Adicionar"</string>
<string name="manage_users" msgid="1823875311934643849">"Gerenciar usuários"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"Esta notificação não tem suporte para ser arrastada para a tela dividida."</string>
@@ -945,4 +963,12 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarme definido"</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>
+ <!-- no translation found for broadcasting_description_is_broadcasting (765627502786404290) -->
+ <skip />
+ <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>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Se você transmitir o app <xliff:g id="SWITCHAPP">%1$s</xliff:g> ou mudar a saída, a transmissão atual será interrompida"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Transmitir <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Mudar saída"</string>
+ <!-- no translation found for bt_le_audio_broadcast_dialog_unknown_name (3791472237793443044) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-pt/tiles_states_strings.xml b/packages/SystemUI/res/values-pt/tiles_states_strings.xml
index abf8749..bc7efe6 100644
--- a/packages/SystemUI/res/values-pt/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-pt/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Desativado"</item>
<item msgid="460891964396502657">"Ativado"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Indisponível"</item>
+ <item msgid="8014986104355098744">"Desativado"</item>
+ <item msgid="5966994759929723339">"Ativado"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 7baf48b..61abfa4 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Încercați să faceți din nou o captură de ecran"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"Nu se poate salva captura de ecran"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Crearea capturilor de ecran nu este permisă de aplicație sau de organizația dvs."</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Administratorul IT a blocat crearea capturilor de ecran"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Editați"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Editați captura de ecran"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"Trimiteți captura de ecran"</string>
@@ -226,6 +227,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Rotire automată"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Rotirea automată a ecranului"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Locație"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Screensaver"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Acces la cameră"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Acces la microfon"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Disponibil"</string>
@@ -320,6 +322,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"S-a deblocat cu ajutorul feței. Apăsați pentru a deschide."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Chipul a fost recunoscut. Apăsați pentru a deschide."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Chip recunoscut. Apăsați pictograma de deblocare pentru a deschide"</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"Glisați pentru a încerca din nou"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Deblocați pentru a folosi NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Dispozitivul aparține organizației dvs."</string>
@@ -470,7 +476,7 @@
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"Configurați pentru a face achiziții mai rapide și mai sigure cu telefonul dvs."</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"Afișați-le pe toate"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"Adăugați un card"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"Atingeți pentru a deschide"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"Se actualizează"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Deblocați pentru a folosi"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"A apărut o problemă la preluarea cardurilor. Încercați din nou mai târziu"</string>
@@ -698,7 +704,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Alerte"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Baterie"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Capturi de ecran"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Mesaje generale"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"Stocare"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Indicii"</string>
<string name="instant_apps" msgid="8337185853050247304">"Aplicații instantanee"</string>
@@ -732,6 +741,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"Porniți dacă este probabil ca bateria să se descarce"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"Nu, mulțumesc"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Extrageți memoria SysUI"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"În uz"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Aplicațiile folosesc <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" și "</string>
@@ -830,7 +840,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Apropiați-vă pentru a reda pe <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Mergeți mai aproape de <xliff:g id="DEVICENAME">%1$s</xliff:g> ca să redați acolo"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Se redă pe <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Se redă pe acest telefon"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"A apărut o eroare. Încercați din nou."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inactiv, verificați aplicația"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Nu s-a găsit"</string>
@@ -859,6 +868,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"Salvați"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"Începe…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"Nu se poate transmite"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Nu se poate salva. Încercați din nou."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Nu se poate salva."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Numărul versiunii"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Numărul versiunii s-a copiat în clipboard."</string>
<string name="basic_status" msgid="2315371112182658176">"Deschideți conversația"</string>
@@ -944,6 +955,10 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Editați textul copiat"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Editați imaginea copiată"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Trimiteți către un dispozitiv din apropiere"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"Atingeți pentru a afișa"</string>
+ <string name="clipboard_text_copied" msgid="5100836834278976679">"Textul a fost copiat"</string>
+ <string name="clipboard_image_copied" msgid="3793365360174328722">"Imaginea a fost copiată"</string>
+ <string name="clipboard_content_copied" msgid="144452398567828145">"Conținutul a fost copiat"</string>
<string name="add" msgid="81036585205287996">"Adăugați"</string>
<string name="manage_users" msgid="1823875311934643849">"Gestionați utilizatorii"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"Notificarea nu acceptă tragerea pe ecranul împărțit."</string>
@@ -952,4 +967,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarmă setată"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Camera și microfonul sunt dezactivate"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notificare}few{# notificări}other{# de notificări}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Se difuzează"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Opriți difuzarea <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Dacă difuzați <xliff:g id="SWITCHAPP">%1$s</xliff:g> sau schimbați rezultatul, difuzarea actuală se va opri"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Difuzați <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Schimbați rezultatul"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Necunoscută"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ro/tiles_states_strings.xml b/packages/SystemUI/res/values-ro/tiles_states_strings.xml
index 1ad0a75..7b7bb3a 100644
--- a/packages/SystemUI/res/values-ro/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ro/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Dezactivat"</item>
<item msgid="460891964396502657">"Activat"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Indisponibil"</item>
+ <item msgid="8014986104355098744">"Dezactivat"</item>
+ <item msgid="5966994759929723339">"Activat"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 6ca5000..81c651d 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Попробуйте сделать скриншот снова."</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"Не удалось сохранить скриншот."</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Не удалось сделать скриншот: нет разрешения от приложения или организации."</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Системный администратор запретил делать скриншоты."</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Изменить"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Изменить скриншот"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"Поделиться скриншотом"</string>
@@ -227,6 +228,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Автоповорот"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Автоповорот экрана"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Геолокация"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Заставка"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Доступ к камере"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Доступ к микрофону"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Доступно"</string>
@@ -322,6 +324,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Разблокировано сканированием лица. Нажмите, чтобы открыть."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Лицо распознано. Нажмите, чтобы открыть."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Лицо распознано. Нажмите на значок разблокировки."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"Чтобы повторить попытку, проведите вверх"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Чтобы использовать NFC, разблокируйте устройство."</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Это устройство принадлежит вашей организации"</string>
@@ -473,7 +479,7 @@
<string name="wallet_title" msgid="5369767670735827105">"Кошелек"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"Расплачивайтесь через телефон быстро и безопасно."</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"Показать все"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"Добавьте карту"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"Нажмите, чтобы открыть"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"Обновление…"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Разблокировать для использования"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Не удалось получить информацию о картах. Повторите попытку позже."</string>
@@ -607,8 +613,8 @@
<string name="accessibility_status_bar_headset" msgid="2699275863720926104">"Гарнитура подключена"</string>
<string name="data_saver" msgid="3484013368530820763">"Экономия трафика"</string>
<string name="accessibility_data_saver_on" msgid="5394743820189757731">"Режим экономии трафика включен"</string>
- <string name="switch_bar_on" msgid="1770868129120096114">"Включено"</string>
- <string name="switch_bar_off" msgid="5669805115416379556">"Отключено"</string>
+ <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="nav_bar" msgid="4642708685386136807">"Панель навигации"</string>
@@ -703,7 +709,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Оповещения"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Батарея"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Скриншоты"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Сообщения"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"Хранилище"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Подсказки"</string>
<string name="instant_apps" msgid="8337185853050247304">"Приложения с мгновенным запуском"</string>
@@ -737,6 +746,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"Включать, если высока вероятность, что батарея скоро разрядится"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"Нет, спасибо"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Передача SysUI"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"Используется"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"В приложениях используется <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" и "</string>
@@ -816,7 +826,7 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Проведите по экрану, чтобы увидеть больше"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Загрузка рекомендаций…"</string>
<string name="controls_media_title" msgid="1746947284862928133">"Медиа"</string>
- <string name="controls_media_close_session" msgid="4780485355795635052">"Скрыть этот элемент управления в приложении \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"?"</string>
+ <string name="controls_media_close_session" msgid="4780485355795635052">"Скрыть этот элемент в приложении \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"?"</string>
<string name="controls_media_active_session" msgid="3146882316024153337">"Этот мультимедийный сеанс невозможно скрыть."</string>
<string name="controls_media_dismiss_button" msgid="4485675693008031646">"Скрыть"</string>
<string name="controls_media_resume" msgid="1933520684481586053">"Возобновить"</string>
@@ -836,7 +846,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Чтобы начать трансляцию на устройстве \"<xliff:g id="DEVICENAME">%1$s</xliff:g>\", подойдите к нему ближе."</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Для воспроизведения на этом устройстве подойдите ближе к другому (<xliff:g id="DEVICENAME">%1$s</xliff:g>)."</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Воспроизводится на устройстве \"<xliff:g id="DEVICENAME">%1$s</xliff:g>\"."</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Воспроизводится на этом телефоне."</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Произошла ошибка. Повторите попытку."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Нет ответа. Проверьте приложение."</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Не найдено."</string>
@@ -865,6 +874,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"Сохранить"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"Запуск…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"Не удалось запустить трансляцию"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Не удалось сохранить. Повторите попытку."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Не удалось сохранить."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Номер сборки"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Номер сборки скопирован в буфер обмена."</string>
<string name="basic_status" msgid="2315371112182658176">"Открытый чат"</string>
@@ -934,10 +945,10 @@
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Не добавлять"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Выберите профиль"</string>
<plurals name="fgs_manager_footer_label" formatted="false" msgid="790443735462280164">
- <item quantity="one"><xliff:g id="COUNT_1">%s</xliff:g> приложение активно</item>
- <item quantity="few"><xliff:g id="COUNT_1">%s</xliff:g> приложения активно</item>
- <item quantity="many"><xliff:g id="COUNT_1">%s</xliff:g> приложений активно</item>
- <item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> приложения активно</item>
+ <item quantity="one">Активно <xliff:g id="COUNT_1">%s</xliff:g> приложение</item>
+ <item quantity="few">Активно <xliff:g id="COUNT_1">%s</xliff:g> приложения</item>
+ <item quantity="many">Активно <xliff:g id="COUNT_1">%s</xliff:g> приложений</item>
+ <item quantity="other">Активно <xliff:g id="COUNT_1">%s</xliff:g> приложения</item>
</plurals>
<string name="fgs_dot_content_description" msgid="2865071539464777240">"Новая информация"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Активные приложения"</string>
@@ -951,6 +962,13 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Изменить скопированный текст"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Изменить скопированное изображение"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Отправить на устройство поблизости"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"Нажмите, чтобы посмотреть"</string>
+ <!-- no translation found for clipboard_text_copied (5100836834278976679) -->
+ <skip />
+ <!-- no translation found for clipboard_image_copied (3793365360174328722) -->
+ <skip />
+ <!-- no translation found for clipboard_content_copied (144452398567828145) -->
+ <skip />
<string name="add" msgid="81036585205287996">"Добавить"</string>
<string name="manage_users" msgid="1823875311934643849">"Управление пользователями"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"Это уведомление нельзя перетаскивать между частями разделенного экрана."</string>
@@ -959,4 +977,12 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Будильник установлен"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Камера и микрофон отключены"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# уведомление}one{# уведомление}few{# уведомления}many{# уведомлений}other{# уведомления}}"</string>
+ <!-- no translation found for broadcasting_description_is_broadcasting (765627502786404290) -->
+ <skip />
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Остановить трансляцию \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Если вы начнете транслировать \"<xliff:g id="SWITCHAPP">%1$s</xliff:g>\" или смените целевое устройство, текущая трансляция прервется."</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Транслировать \"<xliff:g id="SWITCHAPP">%1$s</xliff:g>\""</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Транслировать на другое устройство"</string>
+ <!-- no translation found for bt_le_audio_broadcast_dialog_unknown_name (3791472237793443044) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ru/tiles_states_strings.xml b/packages/SystemUI/res/values-ru/tiles_states_strings.xml
index e1ee39f..6255bd8 100644
--- a/packages/SystemUI/res/values-ru/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ru/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Отключен"</item>
<item msgid="460891964396502657">"Включен"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Недоступно"</item>
+ <item msgid="8014986104355098744">"Отключено"</item>
+ <item msgid="5966994759929723339">"Включено"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 4f297bd..022cf4b 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"තිර රුව නැවත ගැනීමට උත්සාහ කරන්න"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"තිර රුව සුරැකීමට නොහැකිය"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"තිර රූ ගැනීමට යෙදුම හෝ ඔබගේ සංවිධානය ඉඩ නොදේ"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"තිර රූ ගැනීම ඔබගේ IT පරිපාලක විසින් අවහිර කර ඇත"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"සංස්කරණය කරන්න"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"තිර රුව සංස්කරණය කරන්න"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"තිර රුව බෙදා ගන්න"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"ස්වයංක්රීය කරකැවීම"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"ස්වයංක්රීයව-භ්රමණය වන තිරය"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"ස්ථානය"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"තිර සුරැකුම"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"කැමරා ප්රවේශය"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"මයික් ප්රවේශය"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"තිබේ"</string>
@@ -318,6 +320,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"මුහුණ මගින් අගුලු හරින ලදි. විවෘත කිරීමට ඔබන්න."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"මුහුණ හඳුනා ගන්නා ලදි. විවෘත කිරීමට ඔබන්න."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"මුහුණ හඳුනා ගන්නා ලදි. විවෘත කිරීමට අගුලු හැරීමේ නිරූපකය ඔබන්න."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"නැවත උත්සාහ කිරීමට ඉහළට ස්වයිප් කරන්න"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC භාවිත කිරීමට අගුලු හරින්න"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"මෙම උපාංගය ඔබේ සංවිධානයට අයිතිය"</string>
@@ -467,7 +473,7 @@
<string name="wallet_title" msgid="5369767670735827105">"පසුම්බිය"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"ඔබගේ දුරකථනය සමඟ වඩා වේගවත්, වඩා සුරක්ෂිත මිලදී ගැනීම් සිදු කිරීමට සූදානම් වන්න"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"සියල්ල පෙන්වන්න"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"කාඩ්පතක් එක් කරන්න"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"විවෘත කිරීමට තට්ටු කරන්න"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"යාවත්කාලීන වේ"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"භාවිත කිරීමට අගුලු හරින්න"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"ඔබගේ කාඩ්පත ලබා ගැනීමේ ගැටලුවක් විය, කරුණාකර පසුව නැවත උත්සාහ කරන්න"</string>
@@ -693,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"ඇඟවීම්"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"බැටරිය"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"තිර රු"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"පොදු පණිවිඩ"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"ගබඩාව"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"ඉඟි"</string>
<string name="instant_apps" msgid="8337185853050247304">"ක්ෂණික යෙදුම්"</string>
@@ -727,6 +736,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"බැටරිය අවසන් වීමට යන විට සක්රීය කරන්න"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"එපා ස්තූතියි"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"භාවිතයේ ඇත"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"යෙදුම් ඔබේ <xliff:g id="TYPES_LIST">%s</xliff:g> භාවිත කරමින් සිටී."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" සහ "</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g> හි වාදනය කිරීමට වඩාත් ළං වන්න"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"මෙහි ක්රීඩා කිරීමට <xliff:g id="DEVICENAME">%1$s</xliff:g> වෙත වඩා සමීප වන්න"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> හි වාදනය කරමින්"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"මෙම දුරකථනයෙහි වාදනය කරමින්"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"යම් දෙයක් වැරදිණි. නැවත උත්සාහ කරන්න."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"අක්රියයි, යෙදුම පරීක්ෂා කරන්න"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"හමු නොවිණි"</string>
@@ -853,6 +862,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"සුරකින්න"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"ආරම්භ කරමින්…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"විකාශනය කළ නොහැකිය"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"සුරැකිය නොහැකිය. නැවත උත්සාහ කරන්න."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"සුරැකිය නොහැකිය."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"නිමැවුම් අංකය"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"නිමැවුම් අංකය පසුරු පුවරුවට පිටපත් කරන ලදි."</string>
<string name="basic_status" msgid="2315371112182658176">"සංවාදය විවෘත කරන්න"</string>
@@ -937,6 +948,13 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"පිටපත් කළ පෙළ සංස්කරණය කරන්න"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"පිටපත් කළ රූපය සංස්කරණය කරන්න"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"අවට උපාංගය වෙත යවන්න"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"බැලීමට තට්ටු කරන්න"</string>
+ <!-- no translation found for clipboard_text_copied (5100836834278976679) -->
+ <skip />
+ <!-- no translation found for clipboard_image_copied (3793365360174328722) -->
+ <skip />
+ <!-- no translation found for clipboard_content_copied (144452398567828145) -->
+ <skip />
<string name="add" msgid="81036585205287996">"එක් කරන්න"</string>
<string name="manage_users" msgid="1823875311934643849">"පරිශීලකයන් කළමනාකරණය කරන්න"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"මෙම දැනුම්දීම බෙදුම් තිරය වෙත ඇද ගෙන යාමට සහාය නොදක්වයි."</string>
@@ -945,4 +963,12 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"සීනුව සකසන ලදි"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"කැමරාව සහ මයික් ක්රියාවිරහිතයි"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{දැනුම්දීම් #ක්}one{දැනුම්දීම් #ක්}other{දැනුම්දීම් #ක්}}"</string>
+ <!-- no translation found for broadcasting_description_is_broadcasting (765627502786404290) -->
+ <skip />
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> විකාශනය කිරීම නවත්වන්නද?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"ඔබ <xliff:g id="SWITCHAPP">%1$s</xliff:g> විකාශනය කළහොත් හෝ ප්රතිදානය වෙනස් කළහොත්, ඔබගේ වත්මන් විකාශනය නවතිනු ඇත."</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> විකාශනය"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"ප්රතිදානය වෙනස් කරන්න"</string>
+ <!-- no translation found for bt_le_audio_broadcast_dialog_unknown_name (3791472237793443044) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-si/tiles_states_strings.xml b/packages/SystemUI/res/values-si/tiles_states_strings.xml
index 8a16acb..327e0b9 100644
--- a/packages/SystemUI/res/values-si/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-si/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"ක්රියාවිරහිතයි"</item>
<item msgid="460891964396502657">"ක්රියාත්මකයි"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"නොමැත"</item>
+ <item msgid="8014986104355098744">"ක්රියාවිරහිතයි"</item>
+ <item msgid="5966994759929723339">"ක්රියාත්මකයි"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 726f5be..b29f190 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Skúste snímku urobiť znova"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"Snímka obrazovky sa nedá uložiť"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Vytváranie snímok obrazovky je zakázané aplikáciou alebo vašou organizáciou"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Vytváranie snímok obrazovky zablokoval váš správca IT"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Upraviť"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Upraviť snímku obrazovky"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"Zdieľať snímku obrazovky"</string>
@@ -227,6 +228,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automatické otáčanie"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Automatické otáčanie obrazovky"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Poloha"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Šetrič obrazovky"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Prístup ku kamere"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Prístup k mikrofónu"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"K dispozícii"</string>
@@ -322,6 +324,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Odomknuté tvárou. Otvorte stlačením."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Tvár bola rozpoznaná. Otvorte stlačením."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Tvár bola rozpoznaná. Otvorte stlačením ikony odomknutia."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"Potiahnutím nahor to skúste znova"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Ak chcete použiť NFC, odomknite"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Toto zariadenie patrí vašej organizácii"</string>
@@ -473,7 +479,7 @@
<string name="wallet_title" msgid="5369767670735827105">"Peňaženka"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"Nastavte si všetko potrebné na rýchlejšie a bezpečnejšie nákupy telefónom"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"Zobraziť všetko"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"Pridať kartu"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"Otvorte klepnutím"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"Aktualizuje sa"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Odomknúť a použiť"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Pri načítavaní kariet sa vyskytol problém. Skúste to neskôr."</string>
@@ -703,7 +709,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Upozornenia"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Batéria"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Snímky obrazovky"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Všeobecné správy"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"Úložisko"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Tipy"</string>
<string name="instant_apps" msgid="8337185853050247304">"Okamžité aplikácie"</string>
@@ -737,6 +746,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"Zapnite, keď je batéria takmer vybitá"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"Nie, vďaka"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Výpis haldy SysUI"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"Používa sa"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Aplikácie používajú zoznam <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" a "</string>
@@ -836,7 +846,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Ak chcete prehrávať v zariadení <xliff:g id="DEVICENAME">%1$s</xliff:g>, priblížte sa"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Ak chcete prehrávať v zariadení <xliff:g id="DEVICENAME">%1$s</xliff:g>, priblížte sa k nemu"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Prehráva sa v zariadení <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Prehráva sa v tomto telefóne"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Niečo sa pokazilo. Skúste to znova."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Neaktívne, preverte aplikáciu"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Nenájdené"</string>
@@ -865,6 +874,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"Uložiť"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"Spúšťa sa…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"Nedá sa vysielať"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Nedá sa uložiť. Skúste to znova."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Nedá sa uložiť."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Číslo zostavy"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Číslo zostavy bolo skopírované do schránky."</string>
<string name="basic_status" msgid="2315371112182658176">"Otvorená konverzácia"</string>
@@ -942,7 +953,7 @@
<string name="fgs_dot_content_description" msgid="2865071539464777240">"Nové informácie"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Aktívne aplikácie"</string>
<string name="fgs_manager_dialog_message" msgid="6839542063522121108">"Aj keď tieto aplikácie nepoužívate, stále sú aktívne a môžu ovplyvňovať výdrž batérie"</string>
- <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Ukončiť"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Zastaviť"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Zastavená"</string>
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Hotovo"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Skopírované"</string>
@@ -951,6 +962,13 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Upraviť skopírovaný text"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Upraviť skopírovaný obrázok"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Odoslať do zariadenia v okolí"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"Zobrazíte klepnutím"</string>
+ <!-- no translation found for clipboard_text_copied (5100836834278976679) -->
+ <skip />
+ <!-- no translation found for clipboard_image_copied (3793365360174328722) -->
+ <skip />
+ <!-- no translation found for clipboard_content_copied (144452398567828145) -->
+ <skip />
<string name="add" msgid="81036585205287996">"Pridať"</string>
<string name="manage_users" msgid="1823875311934643849">"Spravovať používateľov"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"Toto upozornenie nepodporuje presun na rozdelenú obrazovku."</string>
@@ -959,4 +977,12 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Budík je nastavený"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera a mikrofón sú vypnuté"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# upozornenie}few{# upozornenia}many{# notifications}other{# upozornení}}"</string>
+ <!-- no translation found for broadcasting_description_is_broadcasting (765627502786404290) -->
+ <skip />
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Chcete zastaviť vysielanie aplikácie <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Ak vysielate aplikáciu <xliff:g id="SWITCHAPP">%1$s</xliff:g> alebo zmeníte výstup, aktuálne vysielanie bude zastavené"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Vysielanie aplikácie <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Zmena výstupu"</string>
+ <!-- no translation found for bt_le_audio_broadcast_dialog_unknown_name (3791472237793443044) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-sk/tiles_states_strings.xml b/packages/SystemUI/res/values-sk/tiles_states_strings.xml
index dcdfb3a..3cbde1c 100644
--- a/packages/SystemUI/res/values-sk/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-sk/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Vypnuté"</item>
<item msgid="460891964396502657">"Zapnuté"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Nedostupné"</item>
+ <item msgid="8014986104355098744">"Vypnuté"</item>
+ <item msgid="5966994759929723339">"Zapnuté"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index bb0338e..7ab9552 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Poskusite znova ustvariti posnetek zaslona"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"Posnetka zaslona ni mogoče shraniti"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Aplikacija ali vaša organizacija ne dovoljuje posnetkov zaslona"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Skrbnik za IT je onemogočil zajemanje posnetkov zaslona."</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Uredi"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Urejanje posnetka zaslona"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"Deljenje posnetka zaslona"</string>
@@ -227,6 +228,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Samodejno sukanje"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Samodejno sukanje zaslona"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Lokacija"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Ohranjevalnik zaslona"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Dostop do fotoaparata"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Dostop do mikrofona"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Na voljo"</string>
@@ -322,6 +324,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Odklenjeno z obrazom. Pritisnite za odpiranje."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Obraz je prepoznan. Pritisnite za odpiranje."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Obraz je prepoznan. Za odpiranje pritisnite ikono za odklepanje."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"Povlecite navzgor za vnovičen poskus"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Odklenite napravo, če želite uporabljati NFC."</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Ta naprava pripada vaši organizaciji"</string>
@@ -473,7 +479,7 @@
<string name="wallet_title" msgid="5369767670735827105">"Denarnica"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"Nastavite možnost hitrejšega in varnejšega plačevanja s telefonom."</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"Prikaži vse"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"Dodajte kartico"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"Dotaknite se za odpiranje"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"Posodabljanje"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Odklenite za uporabo"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Pri pridobivanju kartic je prišlo do težave. Poskusite znova pozneje."</string>
@@ -703,7 +709,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Opozorila"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Baterija"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Posnetki zaslona"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Splošna sporočila"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"Shramba"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Namigi"</string>
<string name="instant_apps" msgid="8337185853050247304">"Nenamestljive aplikacije"</string>
@@ -737,6 +746,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"Vklop, če je verjetno, da se bo baterija izpraznila"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"Ne, hvala"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Izvoz kopice SysUI"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"V uporabi"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Aplikacije uporabljajo <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" in "</string>
@@ -816,7 +826,7 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Če si želite ogledati več, povlecite"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Nalaganje priporočil"</string>
<string name="controls_media_title" msgid="1746947284862928133">"Predstavnost"</string>
- <string name="controls_media_close_session" msgid="4780485355795635052">"Želite skriti ta nadzor predstavnosti za apl. <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="controls_media_close_session" msgid="4780485355795635052">"Želite skriti ta nadzor predstavnosti za <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="controls_media_active_session" msgid="3146882316024153337">"Trenutne seje predstavnosti ni mogoče skriti."</string>
<string name="controls_media_dismiss_button" msgid="4485675693008031646">"Skrij"</string>
<string name="controls_media_resume" msgid="1933520684481586053">"Nadaljuj"</string>
@@ -836,7 +846,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Za predvajanje v napravi <xliff:g id="DEVICENAME">%1$s</xliff:g> bolj približajte telefon."</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Približajte napravi <xliff:g id="DEVICENAME">%1$s</xliff:g> za predvajanje v tej napravi"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Predvajanje v napravi <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Predvajanje v tem telefonu"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Prišlo je do napake. Poskusite znova."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Neaktivno, poglejte aplikacijo"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Ni mogoče najti"</string>
@@ -865,6 +874,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"Shrani"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"Začenjanje …"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"Oddajanje ni mogoče"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Ni mogoče shraniti. Poskusite znova."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Ni mogoče shraniti."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Delovna različica"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Delovna različica je bila kopirana v odložišče."</string>
<string name="basic_status" msgid="2315371112182658176">"Odprt pogovor"</string>
@@ -951,6 +962,13 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Uredi kopirano besedilo"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Uredi kopirano sliko"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Pošlji v napravo v bližini"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"Dotaknite se za ogled"</string>
+ <!-- no translation found for clipboard_text_copied (5100836834278976679) -->
+ <skip />
+ <!-- no translation found for clipboard_image_copied (3793365360174328722) -->
+ <skip />
+ <!-- no translation found for clipboard_content_copied (144452398567828145) -->
+ <skip />
<string name="add" msgid="81036585205287996">"Dodaj"</string>
<string name="manage_users" msgid="1823875311934643849">"Upravljanje uporabnikov"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"To obvestilo ne podpira vlečenja v razdeljen zaslon."</string>
@@ -959,4 +977,12 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm je nastavljen."</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Fotoaparat in mikrofon sta izklopljena."</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# obvestilo}one{# obvestilo}two{# obvestili}few{# obvestila}other{# obvestil}}"</string>
+ <!-- no translation found for broadcasting_description_is_broadcasting (765627502786404290) -->
+ <skip />
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Želite ustaviti oddajanje aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Če oddajate aplikacijo <xliff:g id="SWITCHAPP">%1$s</xliff:g> ali spremenite izhod, bo trenutno oddajanje ustavljeno."</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Oddajaj aplikacijo <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Sprememba izhoda"</string>
+ <!-- no translation found for bt_le_audio_broadcast_dialog_unknown_name (3791472237793443044) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-sl/tiles_states_strings.xml b/packages/SystemUI/res/values-sl/tiles_states_strings.xml
index f1ebee4..e720819 100644
--- a/packages/SystemUI/res/values-sl/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-sl/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Izklopljeno"</item>
<item msgid="460891964396502657">"Vklopljeno"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Ni na voljo"</item>
+ <item msgid="8014986104355098744">"Izklopljeno"</item>
+ <item msgid="5966994759929723339">"Vklopljeno"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 1f63552..f8afe48 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Provo ta nxjerrësh përsëri pamjen e ekranit"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"Pamja e ekranit nuk mund të ruhet"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Nxjerrja e pamjeve të ekranit nuk lejohet nga aplikacioni ose organizata jote."</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Shkrepja e pamjeve të ekranit është bllokuar nga administratori i teknologjisë së informacionit"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Modifiko"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Modifiko pamjen e ekranit"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"Ndaj pamjen e ekranit"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Rrotullim automatik"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Rrotullimi automatik i ekranit"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Vendndodhja"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Mbrojtësi i ekranit"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Qasja te kamera"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Qasja te mikrofoni"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"E disponueshme"</string>
@@ -318,6 +320,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"U shkyç me fytyrë. Shtyp për ta hapur."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Fytyra u njoh. Shtyp për ta hapur."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Fytyra u njoh. Shtyp ikonën e shkyçjes për ta hapur."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"Rrëshqit lart për të provuar përsëri"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Shkyçe për të përdorur NFC-në"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Kjo pajisje i përket organizatës sate"</string>
@@ -467,7 +473,7 @@
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"Konfiguro për të kryer pagesa më të shpejta dhe më të sigurta përmes telefonit"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"Shfaqi të gjitha"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"Shto një kartë"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"Trokit për ta hapur"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"Po përditësohet"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Shkyçe për ta përdorur"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Pati një problem me marrjen e kartave të tua. Provo përsëri më vonë"</string>
@@ -693,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Sinjalizimet"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Bateria"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Pamje ekrani"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Mesazhe të përgjithshme"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"Hapësira ruajtëse"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Sugjerimet"</string>
<string name="instant_apps" msgid="8337185853050247304">"Aplikacionet e çastit"</string>
@@ -727,6 +736,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"Aktivizoje kur bateria mund të mbarojë"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"Jo"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Hidh grumbullin SysUI"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"Në përdorim"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Aplikacionet po përdorin <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" dhe "</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Afrohu për të luajtur në <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Afrohu te <xliff:g id="DEVICENAME">%1$s</xliff:g> për ta luajtur këtu"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Po luhet në <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Po luhet në këtë telefon"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Ndodhi një gabim. Provo përsëri."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Joaktive, kontrollo aplikacionin"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Nuk u gjet"</string>
@@ -853,6 +862,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"Ruaj"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"Po fillon…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"Nuk mund të transmetohet"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Nuk mund të ruhet. Provo përsëri."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Nuk mund të ruhet."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Numri i ndërtimit"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Numri i ndërtimit u kopjua te kujtesa e fragmenteve"</string>
<string name="basic_status" msgid="2315371112182658176">"Hap bisedën"</string>
@@ -937,6 +948,13 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Modifiko tekstin e kopjuar"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Modifiko imazhin e kopjuar"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Dërgo te pajisja në afërsi"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"Trokit për të parë"</string>
+ <!-- no translation found for clipboard_text_copied (5100836834278976679) -->
+ <skip />
+ <!-- no translation found for clipboard_image_copied (3793365360174328722) -->
+ <skip />
+ <!-- no translation found for clipboard_content_copied (144452398567828145) -->
+ <skip />
<string name="add" msgid="81036585205287996">"Shto"</string>
<string name="manage_users" msgid="1823875311934643849">"Menaxho përdoruesit"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"Ky njoftim nuk mbështet zvarritjen në \"Ekranin e ndarë\"."</string>
@@ -945,4 +963,12 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarmi është caktuar"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera dhe mikrofoni janë joaktivë"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# njoftim}other{# njoftime}}"</string>
+ <!-- no translation found for broadcasting_description_is_broadcasting (765627502786404290) -->
+ <skip />
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Të ndalohet transmetimi i <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Nëse transmeton <xliff:g id="SWITCHAPP">%1$s</xliff:g> ose ndryshon daljen, transmetimi yt aktual do të ndalojë"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Transmeto <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Ndrysho daljen"</string>
+ <!-- no translation found for bt_le_audio_broadcast_dialog_unknown_name (3791472237793443044) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-sq/tiles_states_strings.xml b/packages/SystemUI/res/values-sq/tiles_states_strings.xml
index e24abf6..7a09f24 100644
--- a/packages/SystemUI/res/values-sq/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-sq/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Joaktiv"</item>
<item msgid="460891964396502657">"Aktiv"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Nuk ofrohet"</item>
+ <item msgid="8014986104355098744">"Joaktiv"</item>
+ <item msgid="5966994759929723339">"Aktiv"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index dc24871..d379d8f 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Пробајте да поново направите снимак екрана"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"Чување снимка екрана није успело"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Апликација или организација не дозвољавају прављење снимака екрана"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"ИТ администратор блокира прављење снимака екрана"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Измени"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Измените снимак екрана"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"Делите снимак екрана"</string>
@@ -226,6 +227,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Аутоматска ротација"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Аутоматско ротирање екрана"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Локација"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Чувар екрана"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Приступ камери"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Приступ микрофону"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Доступно"</string>
@@ -320,6 +322,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Откључано је лицем. Притисните да бисте отворили."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Лице је препознато. Притисните да бисте отворили."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Лице препознато. Притисните икону откључавања за отварање."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"Превуците нагоре да бисте пробали поново"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Откључајте да бисте користили NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Овај уређај припада организацији"</string>
@@ -470,7 +476,7 @@
<string name="wallet_title" msgid="5369767670735827105">"Новчаник"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"Обавите конфигурисање да бисте могли брже и сигурније да купујете помоћу телефона"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"Прикажи све"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"Додајте картицу"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"Додирните и отворите"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"Ажурира се"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Откључај ради коришћења"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Дошло је до проблема при преузимању картица. Пробајте поново касније"</string>
@@ -515,7 +521,7 @@
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"Приказује се у врху обавештења о конверзацијама и као слика профила на закључаном екрану, појављује се као облачић"</string>
<string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"Приказује се у врху обавештења о конверзацијама и као слика профила на закључаном екрану, прекида режим Не узнемиравај"</string>
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Приказује се у врху обавештења о конверзацијама и као слика профила на закључаном екрану, појављује се као облачић, прекида режим Не узнемиравај"</string>
- <string name="notification_priority_title" msgid="2079708866333537093">"Приоритет"</string>
+ <string name="notification_priority_title" msgid="2079708866333537093">"Приоритетно"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> не подржава функције конверзације"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Ова обавештења не могу да се мењају."</string>
<string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Обавештења о позивима не могу да се мењају."</string>
@@ -698,7 +704,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Обавештења"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Батерија"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Снимци екрана"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Опште поруке"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"Меморијски простор"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Савети"</string>
<string name="instant_apps" msgid="8337185853050247304">"Инстант апликације"</string>
@@ -732,6 +741,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"Укључите ако ће батерија вероватно да се испразни"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"Не, хвала"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Издвоји SysUI мем."</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"У употреби"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Апликације користе <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" и "</string>
@@ -830,7 +840,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Приближите да бисте пуштали музику на: <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Приближите се уређају <xliff:g id="DEVICENAME">%1$s</xliff:g> да бисте на њему пуштали"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Пушта се на уређају <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Пушта се на овом телефону"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Дошло је до грешке. Пробајте поново."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Неактивно. Видите апликацију"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Није пронађено"</string>
@@ -859,6 +868,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"Сачувај"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"Покреће се…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"Емитовање није успело"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Чување није успело. Пробајте поново."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Чување није успело."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Број верзије"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Број верзије је копиран у привремену меморију."</string>
<string name="basic_status" msgid="2315371112182658176">"Отворите конверзацију"</string>
@@ -944,6 +955,13 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Измените копирани текст"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Измените копирану слику"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Пошаљи на уређај у близини"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"Додирните да бисте прегледали"</string>
+ <!-- no translation found for clipboard_text_copied (5100836834278976679) -->
+ <skip />
+ <!-- no translation found for clipboard_image_copied (3793365360174328722) -->
+ <skip />
+ <!-- no translation found for clipboard_content_copied (144452398567828145) -->
+ <skip />
<string name="add" msgid="81036585205287996">"Додај"</string>
<string name="manage_users" msgid="1823875311934643849">"Управљаjте корисницима"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"Ово обавештење не подржава превлачење на подељени екран."</string>
@@ -952,4 +970,12 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Аларм је подешен"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Камера и микрофон су искључени"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# обавештење}one{# обавештење}few{# обавештења}other{# обавештења}}"</string>
+ <!-- no translation found for broadcasting_description_is_broadcasting (765627502786404290) -->
+ <skip />
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Желите да зауставите емитовање апликације <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Ако емитујете апликацију <xliff:g id="SWITCHAPP">%1$s</xliff:g> или промените излаз, актуелно емитовање ће се зауставити"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Емитујте апликацију <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Промените излаз"</string>
+ <!-- no translation found for bt_le_audio_broadcast_dialog_unknown_name (3791472237793443044) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-sr/tiles_states_strings.xml b/packages/SystemUI/res/values-sr/tiles_states_strings.xml
index 0cef5a6..dace491 100644
--- a/packages/SystemUI/res/values-sr/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-sr/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Искључено"</item>
<item msgid="460891964396502657">"Укључено"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Недоступно"</item>
+ <item msgid="8014986104355098744">"Искључено"</item>
+ <item msgid="5966994759929723339">"Укључено"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index eb01599..4e9043a 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Testa att ta en skärmbild igen"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"Det gick inte att spara skärmbilden"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Appen eller organisationen tillåter inte att du tar skärmbilder"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Möjligheten att ta skärmbilder blockeras av IT-administratören"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Redigera"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Redigera skärmbild"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"Dela skärmbild"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Rotera automatiskt"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Rotera skärmen automatiskt"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Plats"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Skärmsläckare"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Kameraåtkomst"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Mikrofonåtkomst"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Tillgänglig"</string>
@@ -318,6 +320,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Upplåst med ansiktslås. Tryck för att öppna."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Ansiktet har identifierats. Tryck för att öppna."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Ansiktet har identifierats. Tryck på ikonen lås upp."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"Svep uppåt om du vill försöka igen"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Lås upp om du vill använda NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Den här enheten tillhör organisationen"</string>
@@ -467,7 +473,7 @@
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"Lägg till en betalningsmetod för att betala snabbare och säkrare med telefonen"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"Visa alla"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"Lägg till ett kort"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"Tryck för att öppna"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"Uppdaterar"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Lås upp för att använda"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Det gick inte att hämta dina kort. Försök igen senare."</string>
@@ -693,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Aviseringar"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Batteri"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Skärmbilder"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Allmänna meddelanden"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"Lagring"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Tips"</string>
<string name="instant_apps" msgid="8337185853050247304">"Snabbappar"</string>
@@ -727,6 +736,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"Aktivera när batteriet håller på att ta slut"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"Nej tack"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI-heap"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"Används"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"<xliff:g id="TYPES_LIST">%s</xliff:g> används av appar."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" och "</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Flytta närmare för att spela upp på <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Flytta dig närmare <xliff:g id="DEVICENAME">%1$s</xliff:g> om du vill spela här"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Spelas upp på <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Spelas upp på denna telefon"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Något gick fel. Försök igen."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inaktiv, kolla appen"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Hittades inte"</string>
@@ -853,6 +862,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"Spara"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"Startar …"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"Det gick inte att sända ut"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Det gick inte att spara. Försök igen."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Det gick inte att spara."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Versionsnummer"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Versionsnumret har kopierats till urklipp."</string>
<string name="basic_status" msgid="2315371112182658176">"Öppen konversation"</string>
@@ -937,6 +948,13 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Redigera kopierad text"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Redigera kopierad bild"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Skicka till enhet i närheten"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"Tryck för att visa"</string>
+ <!-- no translation found for clipboard_text_copied (5100836834278976679) -->
+ <skip />
+ <!-- no translation found for clipboard_image_copied (3793365360174328722) -->
+ <skip />
+ <!-- no translation found for clipboard_content_copied (144452398567828145) -->
+ <skip />
<string name="add" msgid="81036585205287996">"Lägg till"</string>
<string name="manage_users" msgid="1823875311934643849">"Hantera användare"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"Det går inte att dra den här aviseringen till delad skärm."</string>
@@ -945,4 +963,12 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarmet är aktiverat"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kameran och mikrofonen är avstängda"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# avisering}other{# aviseringar}}"</string>
+ <!-- no translation found for broadcasting_description_is_broadcasting (765627502786404290) -->
+ <skip />
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Vill du sluta sända från <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Om en utsändning från <xliff:g id="SWITCHAPP">%1$s</xliff:g> pågår eller om du byter ljudutgång avbryts den nuvarande utsändningen"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Sänd från <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Byt ljudutgång"</string>
+ <!-- no translation found for bt_le_audio_broadcast_dialog_unknown_name (3791472237793443044) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-sv/tiles_states_strings.xml b/packages/SystemUI/res/values-sv/tiles_states_strings.xml
index 410a6bc..9e69b00 100644
--- a/packages/SystemUI/res/values-sv/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-sv/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Av"</item>
<item msgid="460891964396502657">"På"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Inte tillgängligt"</item>
+ <item msgid="8014986104355098744">"Av"</item>
+ <item msgid="5966994759929723339">"På"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 1c84c61..a3e456a 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Jaribu kupiga picha ya skrini tena"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"Imeshindwa kuhifadhi picha ya skrini"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Programu au shirika lako halikuruhusu kupiga picha za skrini"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Kupiga picha za skrini kumezuiwa na Msimamizi wako wa TEHAMA"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Badilisha"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Badilisha picha ya skrini"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"Shiriki picha ya skrini"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Zungusha kiotomatiki"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Skrini ijizungushe kiotomatiki"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Mahali"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Taswira ya skrini"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Ufikiaji wa kamera"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Ufikiaji wa maikrofoni"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Unapatikana"</string>
@@ -318,6 +320,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Imefunguliwa kwa kutumia uso wako. Bonyeza ili ufungue."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Uso umetambuliwa. Bonyeza ili ufungue."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Uso umetambuliwa. Bonyeza aikoni ya kufungua ili ufungue."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"Telezesha kidole juu ili ujaribu tena"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Fungua ili utumie NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Kifaa hiki kinamilikiwa na shirika lako"</string>
@@ -467,7 +473,7 @@
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"Weka njia ya kulipa ili uweze kununua kwa njia salama na haraka zaidi ukitumia simu yako"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"Onyesha zote"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"Weka kadi"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"Gusa ili ufungue"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"Inasasisha"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Fungua ili utumie"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Hitilafu imetokea wakati wa kuleta kadi zako, tafadhali jaribu tena baadaye"</string>
@@ -693,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Arifa"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Betri"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Picha za skrini"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Ujumbe wa Jumla"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"Hifadhi"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Vidokezo"</string>
<string name="instant_apps" msgid="8337185853050247304">"Programu Zinazofunguka Papo Hapo"</string>
@@ -727,6 +736,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"Washa wakati betri inakaribia kuisha"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"Hapana"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"Inatumika"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Programu zinatumia <xliff:g id="TYPES_LIST">%s</xliff:g> yako."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" na "</string>
@@ -804,7 +814,7 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Telezesha kidole ili uone zaidi"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Inapakia mapendekezo"</string>
<string name="controls_media_title" msgid="1746947284862928133">"Maudhui"</string>
- <string name="controls_media_close_session" msgid="4780485355795635052">"Ungependa kuficha kidhibiti hiki cha maudhui kwa <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="controls_media_close_session" msgid="4780485355795635052">"Ungependa kuficha kidhibiti hiki kwa <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="controls_media_active_session" msgid="3146882316024153337">"Kipindi cha sasa cha maudhui hakiwezi kufichwa."</string>
<string name="controls_media_dismiss_button" msgid="4485675693008031646">"Ficha"</string>
<string name="controls_media_resume" msgid="1933520684481586053">"Endelea"</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Sogea karibu ili ucheze kwenye <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Sogeza karibu na <xliff:g id="DEVICENAME">%1$s</xliff:g> ili kucheza hapa"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Inacheza kwenye <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Inacheza kwenye simu hii"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Hitilafu fulani imetokea. Jaribu tena."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Haitumiki, angalia programu"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Hakipatikani"</string>
@@ -853,6 +862,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"Hifadhi"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"Inaanza…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"Imeshindwa kutuma arifa"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Imeshindwa kuhifadhi. Jaribu tena."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Imeshindwa kuhifadhi."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Nambari ya muundo"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Nambari ya muundo imewekwa kwenye ubao wa kunakili."</string>
<string name="basic_status" msgid="2315371112182658176">"Fungua mazungumzo"</string>
@@ -927,7 +938,7 @@
</plurals>
<string name="fgs_dot_content_description" msgid="2865071539464777240">"Maelezo mapya"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Programu zinazotumika"</string>
- <string name="fgs_manager_dialog_message" msgid="6839542063522121108">"Hata ikiwa hutumii programu hizi, bado zinatumika na huenda zikaathiri muda wa matumizi ya betri"</string>
+ <string name="fgs_manager_dialog_message" msgid="6839542063522121108">"Hata ikiwa hutumii programu hizi, bado zina shughuli na huenda zikaathiri muda wa matumizi ya betri"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Simamisha"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Imesimamishwa"</string>
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Imemaliza"</string>
@@ -937,6 +948,13 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Badilisha maandishi yaliyonakiliwa"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Badilisha picha iliyonakiliwa"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Tuma kwenye kifaa kilicho karibu"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"Gusa ili uangalie"</string>
+ <!-- no translation found for clipboard_text_copied (5100836834278976679) -->
+ <skip />
+ <!-- no translation found for clipboard_image_copied (3793365360174328722) -->
+ <skip />
+ <!-- no translation found for clipboard_content_copied (144452398567828145) -->
+ <skip />
<string name="add" msgid="81036585205287996">"Weka"</string>
<string name="manage_users" msgid="1823875311934643849">"Dhibiti watumiaji"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"Arifa hii hairuhusu kuburuta kwenye Skrini iliyogawanyika."</string>
@@ -945,4 +963,12 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Kengele imewekwa"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera na maikrofoni zimezimwa"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{Arifa #}other{Arifa #}}"</string>
+ <!-- no translation found for broadcasting_description_is_broadcasting (765627502786404290) -->
+ <skip />
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Ungependa kusimamisha utangazaji kwenye <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Ikiwa unatangaza kwenye <xliff:g id="SWITCHAPP">%1$s</xliff:g> au unabadilisha maudhui, tangazo lako la sasa litasimamishwa"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Tangaza kwenye <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Badilisha maudhui"</string>
+ <!-- no translation found for bt_le_audio_broadcast_dialog_unknown_name (3791472237793443044) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-sw/tiles_states_strings.xml b/packages/SystemUI/res/values-sw/tiles_states_strings.xml
index 79d29ab..2f765ef 100644
--- a/packages/SystemUI/res/values-sw/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-sw/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Imezimwa"</item>
<item msgid="460891964396502657">"Imewashwa"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Haipatikani"</item>
+ <item msgid="8014986104355098744">"Imezimwa"</item>
+ <item msgid="5966994759929723339">"Imewashwa"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-sw600dp-port/dimens.xml b/packages/SystemUI/res/values-sw600dp-port/dimens.xml
index 589d12f..347cf29 100644
--- a/packages/SystemUI/res/values-sw600dp-port/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp-port/dimens.xml
@@ -21,5 +21,10 @@
<dimen name="keyguard_status_view_bottom_margin">40dp</dimen>
<dimen name="bouncer_user_switcher_y_trans">20dp</dimen>
+ <!-- qs_tiles_page_horizontal_margin should be margin / 2, otherwise full space between two
+ pages is margin * 2, and that makes tiles page not appear immediately after user swipes to
+ the side -->
+ <dimen name="qs_tiles_page_horizontal_margin">32dp</dimen>
+
<dimen name="qqs_layout_padding_bottom">16dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values-sw720dp-port/dimens.xml b/packages/SystemUI/res/values-sw720dp-port/dimens.xml
index 2abc9e3..4de7bb7 100644
--- a/packages/SystemUI/res/values-sw720dp-port/dimens.xml
+++ b/packages/SystemUI/res/values-sw720dp-port/dimens.xml
@@ -29,5 +29,11 @@
<dimen name="notification_panel_margin_horizontal">80dp</dimen>
<dimen name="notification_side_paddings">40dp</dimen>
+
+ <!-- qs_tiles_page_horizontal_margin should be margin / 2, otherwise full space between two
+ pages is margin * 2, and that makes tiles page not appear immediately after user swipes to the
+ side -->
+ <dimen name="qs_tiles_page_horizontal_margin">60dp</dimen>
+
<dimen name="notification_section_divider_height">16dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 5e9b3a5..d5d8f63 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"ஸ்கிரீன் ஷாட்டை மீண்டும் எடுக்க முயலவும்"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"ஸ்கிரீன்ஷாட்டைச் சேமிக்க முடியவில்லை"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"ஸ்கிரீன் ஷாட்டுகளை எடுப்பதை, ஆப்ஸ் அல்லது உங்கள் நிறுவனம் அனுமதிக்கவில்லை"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"ஸ்கிரீன்ஷாட்கள் எடுப்பதை உங்கள் IT நிர்வாகி தடைசெய்துள்ளார்"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"திருத்து"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"ஸ்கிரீன்ஷாட்டைத் திருத்தும்"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"ஸ்கிரீன்ஷாட்டைப் பகிர்"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"தானாகச் சுழற்று"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"திரையைத் தானாகச் சுழற்று"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"இருப்பிடம்"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"ஸ்கிரீன் சேவர்"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"கேமரா அணுகல்"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"மைக் அணுகல்"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"கிடைக்கிறது"</string>
@@ -318,6 +320,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"முகம் மூலம் அன்லாக் செய்யப்பட்டது. திறக்க அழுத்தவும்."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"முகம் அங்கீகரிக்கப்பட்டது. திறக்க அழுத்தவும்."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"முகம் அங்கீகரிக்கப்பட்டது. திறக்க அன்லாக் ஐகானை அழுத்தவும்."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"மீண்டும் முயல மேல்நோக்கி ஸ்வைப் செய்யவும்"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFCயைப் பயன்படுத்த அன்லாக் செய்யவும்"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"இந்த சாதனம் உங்கள் நிறுவனத்துக்கு சொந்தமானது"</string>
@@ -467,7 +473,7 @@
<string name="wallet_title" msgid="5369767670735827105">"வாலட்"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"மொபைல் மூலம் விரைவாகவும் பாதுகாப்பாகவும் பர்ச்சேஸ்கள் செய்ய பேமெண்ட் முறையை அமைக்கவும்"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"அனைத்தையும் காட்டு"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"கார்டைச் சேர்"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"திறக்க தட்டவும்"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"புதுப்பிக்கிறது"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"பயன்படுத்துவதற்கு அன்லாக் செய்க"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"உங்கள் கார்டுகளின் விவரங்களைப் பெறுவதில் சிக்கல் ஏற்பட்டது, பிறகு முயலவும்"</string>
@@ -693,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"விழிப்பூட்டல்கள்"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"பேட்டரி"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"ஸ்கிரீன் ஷாட்டுகள்"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"பொதுச் செய்திகள்"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"சேமிப்பிடம்"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"குறிப்புகள்"</string>
<string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string>
@@ -727,6 +736,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"பேட்டரி தீர்ந்துபோகும் நிலையில் இருக்கும் போது ஆன் செய்யப்படும்"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"வேண்டாம்"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"உபயோகத்தில் உள்ளது"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"உங்கள் <xliff:g id="TYPES_LIST">%s</xliff:g> ஆகியவற்றை ஆப்ஸ் பயன்படுத்துகின்றன."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" மற்றும் "</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g> சாதனத்தில் இயக்க உங்கள் சாதனத்தை அருகில் எடுத்துச் செல்லுங்கள்"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"இங்கு பிளே செய்ய உங்கள் சாதனத்தை <xliff:g id="DEVICENAME">%1$s</xliff:g> சாதனத்திற்கு அருகில் நகர்த்துங்கள்"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> சாதனத்தில் பிளே ஆகிறது"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"இந்த மொபைலில் பிளே ஆகிறது"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"ஏதோ தவறாகிவிட்டது. மீண்டும் முயலவும்."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"செயலில் இல்லை , சரிபார்க்கவும்"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"இல்லை"</string>
@@ -853,6 +862,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"சேமி"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"தொடங்குகிறது…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"ஒளிபரப்ப முடியவில்லை"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"சேமிக்க முடியவில்லை. மீண்டும் முயலவும்."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"சேமிக்க முடியவில்லை."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"பதிப்பு எண்"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"பதிப்பு எண் கிளிப்போர்டுக்கு நகலெடுக்கப்பட்டது."</string>
<string name="basic_status" msgid="2315371112182658176">"திறந்தநிலை உரையாடல்"</string>
@@ -937,6 +948,13 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"நகலெடுத்த வார்த்தைகளைத் திருத்து"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"நகலெடுத்த படத்தைத் திருத்து"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"அருகிலுள்ள சாதனத்திற்கு அனுப்பு"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"பார்க்க தட்டுங்கள்"</string>
+ <!-- no translation found for clipboard_text_copied (5100836834278976679) -->
+ <skip />
+ <!-- no translation found for clipboard_image_copied (3793365360174328722) -->
+ <skip />
+ <!-- no translation found for clipboard_content_copied (144452398567828145) -->
+ <skip />
<string name="add" msgid="81036585205287996">"சேர்"</string>
<string name="manage_users" msgid="1823875311934643849">"பயனர்களை நிர்வகித்தல்"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"பிரிக்கப்பட்ட திரைக்குள் இந்த அறிவிப்பை இழுத்துவிட முடியாது."</string>
@@ -945,4 +963,12 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"அலாரம் அமைக்கப்பட்டுள்ளது"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"கேமராவும் மைக்கும் ஆஃப் செய்யப்பட்டுள்ளன"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# அறிவிப்பு}other{# அறிவிப்புகள்}}"</string>
+ <!-- no translation found for broadcasting_description_is_broadcasting (765627502786404290) -->
+ <skip />
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸ் ஒலிபரப்பப்படுவதை நிறுத்தவா?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"நீங்கள் <xliff:g id="SWITCHAPP">%1$s</xliff:g> ஆப்ஸை ஒலிபரப்பினாலோ அவுட்புட்டை மாற்றினாலோ உங்களின் தற்போதைய ஒலிபரப்பு நிறுத்தப்படும்"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> ஆப்ஸை ஒலிபரப்பு"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"அவுட்புட்டை மாற்று"</string>
+ <!-- no translation found for bt_le_audio_broadcast_dialog_unknown_name (3791472237793443044) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ta/tiles_states_strings.xml b/packages/SystemUI/res/values-ta/tiles_states_strings.xml
index 52fca12..41f6412 100644
--- a/packages/SystemUI/res/values-ta/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ta/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"முடக்கப்பட்டுள்ளது"</item>
<item msgid="460891964396502657">"இயக்கப்பட்டுள்ளது"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"கிடைக்கவில்லை"</item>
+ <item msgid="8014986104355098744">"முடக்கப்பட்டுள்ளது"</item>
+ <item msgid="5966994759929723339">"இயக்கப்பட்டுள்ளது"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 067c846..049e49a 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"స్క్రీన్షాట్ తీయడానికి మళ్లీ ప్రయత్నించండి"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"స్క్రీన్షాట్ను సేవ్ చేయడం సాధ్యపడలేదు"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"స్క్రీన్షాట్లు తీయడానికి యాప్ లేదా మీ సంస్థ అనుమతించలేదు"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"స్క్రీన్షాట్లు తీయడాన్ని మీ IT అడ్మిన్ బ్లాక్ చేశారు"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"ఎడిట్ చేయండి"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"స్క్రీన్షాట్ను ఎడిట్ చేయండి"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"స్క్రీన్షాట్ను షేర్ చేయండి"</string>
@@ -92,7 +93,7 @@
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"స్క్రీన్ రికార్డింగ్ అవుతోంది"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"స్క్రీన్ రికార్డ్ సెషన్ కోసం ఆన్గోయింగ్ నోటిఫికేషన్"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"రికార్డింగ్ను ప్రారంభించాలా?"</string>
- <string name="screenrecord_description" msgid="1123231719680353736">"రికార్డ్ చేస్తున్నప్పుడు, Android సిస్టమ్ మీ స్క్రీన్పై ప్రదర్శించబడిన లేదా మీ పరికరం నుండి ప్లే చేయబడిన ఏ సున్నితమైన సమాచారాన్నయినా క్యాప్చర్ చేయగలదు. ఈ సమాచారంలో, పాస్వర్డ్లు, పేమెంట్ వివరాలు, ఫోటోలు, మెసేజ్లు, ఆడియో కూడా ఉంటాయి."</string>
+ <string name="screenrecord_description" msgid="1123231719680353736">"రికార్డ్ చేస్తున్నప్పుడు, Android సిస్టమ్ మీ స్క్రీన్పై ప్రదర్శించబడిన లేదా మీ పరికరం నుండి ప్లే చేయబడిన ఏ సున్నితమైన సమాచారాన్నయినా క్యాప్చర్ చేయగలదు. ఈ సమాచారంలో పాస్వర్డ్లు, పేమెంట్ వివరాలు, ఫోటోలు, మెసేజ్లు, ఆడియో కూడా ఉంటాయి."</string>
<string name="screenrecord_audio_label" msgid="6183558856175159629">"ఆడియోను రికార్డ్ చేయి"</string>
<string name="screenrecord_device_audio_label" msgid="9016927171280567791">"పరికరం ఆడియో"</string>
<string name="screenrecord_device_audio_description" msgid="4922694220572186193">"మీ పరికరం నుండి వచ్చే మ్యూజిక్, కాల్స్, రింగ్టోన్ల వంటి ధ్వనులు"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"ఆటో-రొటేట్"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"స్క్రీన్ ఆటో-రొటేట్"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"లొకేషన్"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"స్క్రీన్ సేవర్"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"కెమెరా యాక్సెస్"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"మైక్ యాక్సెస్"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"అందుబాటులో ఉంది"</string>
@@ -318,6 +320,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"ముఖం ద్వారా అన్లాక్ చేయబడింది. తెరవడానికి నొక్కండి."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"ముఖం గుర్తించబడింది. తెరవడానికి నొక్కండి."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"ముఖం గుర్తించబడింది. తెరవడానికి అన్లాక్ చిహ్నం నొక్కండి."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"మళ్ళీ ప్రయత్నించడానికి పైకి స్వైప్ చేయండి"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFCని ఉపయోగించడానికి అన్లాక్ చేయండి"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"ఈ పరికరం మీ సంస్థకు చెందినది"</string>
@@ -346,7 +352,7 @@
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"అవును, కొనసాగించు"</string>
<string name="guest_notification_app_name" msgid="2110425506754205509">"గెస్ట్ మోడ్"</string>
<string name="guest_notification_session_active" msgid="5567273684713471450">"మీరు గెస్ట్ మోడ్లో ఉన్నారు"</string>
- <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"కొత్త యూజర్ను జోడించడం వలన గెస్ట్ మోడ్ నుండి నిష్క్రమించబడుతుంది, ప్రస్తుత గెస్ట్ సెషన్ నుండి అన్ని యాప్లు, డేటా తొలగించండి."</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"కొత్త యూజర్ను జోడించడం వలన గెస్ట్ మోడ్ నుండి వైదొలుగుతుంది. అలాగే ప్రస్తుత గెస్ట్ సెషన్ నుండి అన్ని యాప్లతో పాటు మొత్తం డేటా తొలగించబడుతుంది."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"వినియోగదారు పరిమితిని చేరుకున్నారు"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="other">మీరు <xliff:g id="COUNT">%d</xliff:g> వినియోగదారుల వరకు జోడించవచ్చు.</item>
@@ -467,7 +473,7 @@
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"మీ ఫోన్తో మరింత వేగంగా, సురక్షితంగా కొనుగోళ్లు చేయడానికి సెటప్ చేయండి"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"అన్నింటినీ చూపు"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"కార్డ్ను జోడించండి"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"తెరవడం కోసం ట్యాప్ చేయండి"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"అప్డేట్ చేస్తోంది"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ఉపయోగించడానికి అన్లాక్ చేయండి"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"మీ కార్డ్లను పొందడంలో సమస్య ఉంది, దయచేసి తర్వాత మళ్లీ ట్రై చేయండి"</string>
@@ -693,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"అలర్ట్లు"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"బ్యాటరీ"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"స్క్రీన్షాట్లు"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"సాధారణ మెసేజ్లు"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"స్టోరేజ్"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"సూచనలు"</string>
<string name="instant_apps" msgid="8337185853050247304">"ఇన్స్టంట్ యాప్లు"</string>
@@ -727,6 +736,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"బ్యాటరీ ఛార్జింగ్ పూర్తిగా అయిపోతున్న తరుణంలో ఆన్ చేస్తుంది"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"వద్దు, ధన్యవాదాలు"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"డంప్ SysUI హీప్"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"వినియోగంలో ఉంది"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"అప్లికేషన్లు మీ <xliff:g id="TYPES_LIST">%s</xliff:g>ని ఉపయోగిస్తున్నాయి."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" మరియు "</string>
@@ -804,9 +814,9 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"మరిన్నింటిని చూడటం కోసం స్వైప్ చేయండి"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"సిఫార్సులు లోడ్ అవుతున్నాయి"</string>
<string name="controls_media_title" msgid="1746947284862928133">"మీడియా"</string>
- <string name="controls_media_close_session" msgid="4780485355795635052">"<xliff:g id="APP_NAME">%1$s</xliff:g> కోసం ఈ మీడియా కంట్రోల్ను దాచాలా?"</string>
+ <string name="controls_media_close_session" msgid="4780485355795635052">"<xliff:g id="APP_NAME">%1$s</xliff:g> కోసమై ఏర్పరిచిన ఈ మీడియా కంట్రోల్ను దాచాలా?"</string>
<string name="controls_media_active_session" msgid="3146882316024153337">"ప్రస్తుత మీడియా సెషన్ను దాచడం సాధ్యం కాదు."</string>
- <string name="controls_media_dismiss_button" msgid="4485675693008031646">"దాచు"</string>
+ <string name="controls_media_dismiss_button" msgid="4485675693008031646">"దాచండి"</string>
<string name="controls_media_resume" msgid="1933520684481586053">"కొనసాగించండి"</string>
<string name="controls_media_settings_button" msgid="5815790345117172504">"సెట్టింగ్లు"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g> పాడిన <xliff:g id="SONG_NAME">%1$s</xliff:g> <xliff:g id="APP_LABEL">%3$s</xliff:g> నుండి ప్లే అవుతోంది"</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g>లో ప్లే చేయడానికి దగ్గరగా వెళ్లండి"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"ఇక్కడ ప్లే చేయడానికి <xliff:g id="DEVICENAME">%1$s</xliff:g>కి దగ్గరగా వెళ్లండి"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g>లో ప్లే అవుతోంది"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"ఈ ఫోన్లో ప్లే అవుతోంది"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"ఏదో తప్పు జరిగింది. మళ్లీ ట్రై చేయండి."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"ఇన్యాక్టివ్, యాప్ చెక్ చేయండి"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"కనుగొనబడలేదు"</string>
@@ -853,6 +862,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"సేవ్ చేయండి"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"ప్రారంభించబడుతోంది…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"ప్రసారం చేయడం సాధ్యపడలేదు"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"సేవ్ చేయడం సాధ్యపడదు. మళ్లీ ట్రై చేయండి."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"సేవ్ చేయడం సాధ్యపడదు."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"బిల్డ్ నంబర్"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"బిల్డ్ నంబర్, క్లిప్బోర్డ్కు కాపీ చేయబడింది."</string>
<string name="basic_status" msgid="2315371112182658176">"సంభాషణను తెరవండి"</string>
@@ -937,6 +948,13 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"కాపీ చేసిన టెక్స్ట్ను ఎడిట్ చేయండి"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"కాపీ చేసిన ఇమేజ్లను ఎడిట్ చేయండి"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"సమీపంలోని పరికరానికి పంపండి"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"చూడటానికి ట్యాప్ చేయండి"</string>
+ <!-- no translation found for clipboard_text_copied (5100836834278976679) -->
+ <skip />
+ <!-- no translation found for clipboard_image_copied (3793365360174328722) -->
+ <skip />
+ <!-- no translation found for clipboard_content_copied (144452398567828145) -->
+ <skip />
<string name="add" msgid="81036585205287996">"జోడించండి"</string>
<string name="manage_users" msgid="1823875311934643849">"యూజర్లను మేనేజ్ చేయండి"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"ఈ నోటిఫికేషన్ స్ప్లిట్స్క్రీన్కు లాగడానికి సపోర్ట్ చేయదు."</string>
@@ -945,4 +963,12 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"అలారం సెట్ చేశాను"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"కెమెరా, మైక్ ఆఫ్లో ఉన్నాయి"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# నోటిఫికేషన్}other{# నోటిఫికేషన్లు}}"</string>
+ <!-- no translation found for broadcasting_description_is_broadcasting (765627502786404290) -->
+ <skip />
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> ప్రసారం చేయడాన్ని ఆపివేయాలా?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"మీరు <xliff:g id="SWITCHAPP">%1$s</xliff:g> ప్రసారం చేస్తే లేదా అవుట్పుట్ను మార్చినట్లయితే, మీ ప్రస్తుత ప్రసారం ఆగిపోతుంది"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> ప్రసారం చేయండి"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"అవుట్పుట్ను మార్చండి"</string>
+ <!-- no translation found for bt_le_audio_broadcast_dialog_unknown_name (3791472237793443044) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-te/tiles_states_strings.xml b/packages/SystemUI/res/values-te/tiles_states_strings.xml
index 6099792..44ba477 100644
--- a/packages/SystemUI/res/values-te/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-te/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"ఆఫ్"</item>
<item msgid="460891964396502657">"ఆన్"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"అందుబాటులో లేరు"</item>
+ <item msgid="8014986104355098744">"ఆఫ్"</item>
+ <item msgid="5966994759929723339">"ఆన్"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 0cc60bd..6098895 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"ลองบันทึกภาพหน้าจออีกครั้ง"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"บันทึกภาพหน้าจอไม่ได้"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"แอปหรือองค์กรของคุณไม่อนุญาตให้จับภาพหน้าจอ"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"การจับภาพหน้าจอถูกบล็อกโดยผู้ดูแลระบบไอทีของคุณ"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"แก้ไข"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"แก้ไขภาพหน้าจอ"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"แชร์ภาพหน้าจอ"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"หมุนอัตโนมัติ"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"หมุนหน้าจออัตโนมัติ"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"ตำแหน่ง"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"โปรแกรมรักษาหน้าจอ"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"สิทธิ์เข้าถึงกล้อง"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"สิทธิ์เข้าถึงไมโครโฟน"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"พร้อมให้ใช้งาน"</string>
@@ -318,6 +320,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"ปลดล็อกด้วยใบหน้าแล้ว กดเพื่อเปิด"</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"จดจำใบหน้าได้ กดเพื่อเปิด"</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"จดจำใบหน้าได้ กดไอคอนปลดล็อกเพื่อเปิด"</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"เลื่อนขึ้นเพื่อลองอีกครั้ง"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"ปลดล็อกเพื่อใช้ NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"องค์กรของคุณเป็นเจ้าของอุปกรณ์นี้"</string>
@@ -344,9 +350,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"คุณต้องการอยู่ในเซสชันต่อไปไหม"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"เริ่มต้นใหม่"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"ใช่ ดำเนินการต่อ"</string>
- <string name="guest_notification_app_name" msgid="2110425506754205509">"โหมดผู้มาเยือน"</string>
- <string name="guest_notification_session_active" msgid="5567273684713471450">"คุณอยู่ในโหมดผู้มาเยือน"</string>
- <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"การเพิ่มผู้ใช้ใหม่จะเป็นการออกจากโหมดผู้มาเยือน และจะลบแอปและข้อมูลจากเซสชันผู้มาเยือนในปัจจุบัน"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"โหมดผู้ใช้ชั่วคราว"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"คุณอยู่ในโหมดผู้ใช้ชั่วคราว"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"การเพิ่มผู้ใช้ใหม่จะเป็นการออกจากโหมดผู้ใช้ชั่วคราว และจะลบแอปและข้อมูลทั้งหมดจากเซสชันผู้ใช้ชั่วคราวในปัจจุบัน"</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"ถึงขีดจำกัดผู้ใช้แล้ว"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="other">คุณเพิ่มผู้ใช้ได้สูงสุด <xliff:g id="COUNT">%d</xliff:g> คน</item>
@@ -420,11 +426,11 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"เปิดใช้"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"ปิดใช้"</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>
+ <string name="screen_pinning_description" msgid="8699395373875667743">"การดำเนินการนี้จะแสดงหน้าจอนี้ไว้เสมอจนกว่าคุณจะเลิกปักหมุด แตะ \"กลับ\" และ \"ภาพรวม\" ค้างไว้เพื่อเลิกปักหมุด"</string>
+ <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"การดำเนินการนี้จะแสดงหน้าจอนี้ไว้เสมอจนกว่าคุณจะเลิกปักหมุด แตะ \"กลับ\" และ \"หน้าแรก\" ค้างไว้เพื่อเลิกปักหมุด"</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"วิธีนี้ช่วยให้เห็นแอปบนหน้าจอตลอดจนกว่าจะเลิกปักหมุด ปัดขึ้นค้างไว้เพื่อเลิกปักหมุด"</string>
- <string name="screen_pinning_description_accessible" msgid="7386449191953535332">"การดำเนินการนี้จะแสดงหน้าจอนี้ไว้เสมอจนกว่าคุณจะเลิกตรึง แตะ \"ภาพรวม\" ค้างไว้เพื่อเลิกตรึง"</string>
- <string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"การดำเนินการนี้จะแสดงหน้าจอนี้ไว้เสมอจนกว่าคุณจะเลิกตรึง แตะ \"หน้าแรก\" ค้างไว้เพื่อเลิกตรึง"</string>
+ <string name="screen_pinning_description_accessible" msgid="7386449191953535332">"การดำเนินการนี้จะแสดงหน้าจอนี้ไว้เสมอจนกว่าคุณจะเลิกปักหมุด แตะ \"ภาพรวม\" ค้างไว้เพื่อเลิกปักหมุด"</string>
+ <string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"การดำเนินการนี้จะแสดงหน้าจอนี้ไว้เสมอจนกว่าคุณจะเลิกปักหมุด แตะ \"หน้าแรก\" ค้างไว้เพื่อเลิกปักหมุด"</string>
<string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"อาจมีการเข้าถึงข้อมูลส่วนตัว (เช่น รายชื่อติดต่อและเนื้อหาในอีเมล)"</string>
<string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"แอปที่ปักหมุดไว้อาจเปิดแอปอื่นๆ"</string>
<string name="screen_pinning_toast" msgid="8177286912533744328">"หากต้องการเลิกปักหมุดแอปนี้ ให้แตะปุ่ม \"กลับ\" และ \"ภาพรวม\" ค้างไว้"</string>
@@ -467,7 +473,7 @@
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"ตั้งค่าเพื่อซื้อสินค้าและบริการด้วยโทรศัพท์ได้อย่างรวดเร็วและปลอดภัยยิ่งขึ้น"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"แสดงทั้งหมด"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"เพิ่มบัตร"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"แตะเพื่อเปิด"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"กำลังอัปเดต"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ปลดล็อกเพื่อใช้"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"เกิดปัญหาในการดึงข้อมูลบัตรของคุณ โปรดลองอีกครั้งในภายหลัง"</string>
@@ -693,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"การแจ้งเตือน"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"แบตเตอรี"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"ภาพหน้าจอ"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"ข้อความทั่วไป"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"พื้นที่เก็บข้อมูล"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"คำแนะนำ"</string>
<string name="instant_apps" msgid="8337185853050247304">"Instant App"</string>
@@ -727,6 +736,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"เปิดเมื่อมีแนวโน้มว่าแบตเตอรี่จะหมด"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"ไม่เป็นไร"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"ใช้งานอยู่"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"หลายแอปพลิเคชันใช้<xliff:g id="TYPES_LIST">%s</xliff:g>ของคุณอยู่"</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" และ "</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"ขยับเข้ามาใกล้ขึ้นเพื่อเล่นใน <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"ขยับไปใกล้ <xliff:g id="DEVICENAME">%1$s</xliff:g> มากขึ้นเพื่อเล่นที่นี่"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"กำลังเล่นใน <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"กำลังเล่นในโทรศัพท์เครื่องนี้"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"เกิดข้อผิดพลาด โปรดลองอีกครั้ง"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"ไม่มีการใช้งาน โปรดตรวจสอบแอป"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"ไม่พบ"</string>
@@ -853,6 +862,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"บันทึก"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"กำลังเริ่มต้น…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"ออกอากาศไม่ได้"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"บันทึกไม่ได้ โปรดลองอีกครั้ง"</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"บันทึกไม่ได้"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"หมายเลขบิลด์"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"คัดลอกหมายเลขบิลด์ไปยังคลิปบอร์ดแล้ว"</string>
<string name="basic_status" msgid="2315371112182658176">"เปิดการสนทนา"</string>
@@ -937,6 +948,13 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"แก้ไขข้อความที่คัดลอก"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"แก้ไขรูปภาพที่คัดลอก"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"ส่งไปยังอุปกรณ์ที่อยู่ใกล้เคียง"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"แตะเพื่อดู"</string>
+ <!-- no translation found for clipboard_text_copied (5100836834278976679) -->
+ <skip />
+ <!-- no translation found for clipboard_image_copied (3793365360174328722) -->
+ <skip />
+ <!-- no translation found for clipboard_content_copied (144452398567828145) -->
+ <skip />
<string name="add" msgid="81036585205287996">"เพิ่ม"</string>
<string name="manage_users" msgid="1823875311934643849">"จัดการผู้ใช้"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"การแจ้งเตือนนี้ไม่รองรับการลากเพื่อแบ่งหน้าจอ"</string>
@@ -945,4 +963,12 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"ตั้งปลุกแล้ว"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"กล้องและไมค์ปิดอยู่"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{การแจ้งเตือน # รายการ}other{การแจ้งเตือน # รายการ}}"</string>
+ <!-- no translation found for broadcasting_description_is_broadcasting (765627502786404290) -->
+ <skip />
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"หยุดการออกอากาศ <xliff:g id="APP_NAME">%1$s</xliff:g> ไหม"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"หากคุณออกอากาศ <xliff:g id="SWITCHAPP">%1$s</xliff:g> หรือเปลี่ยนแปลงเอาต์พุต การออกอากาศในปัจจุบันจะหยุดลง"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"ออกอากาศ <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"เปลี่ยนเอาต์พุต"</string>
+ <!-- no translation found for bt_le_audio_broadcast_dialog_unknown_name (3791472237793443044) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-th/tiles_states_strings.xml b/packages/SystemUI/res/values-th/tiles_states_strings.xml
index 4565f35f..9cd060f 100644
--- a/packages/SystemUI/res/values-th/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-th/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"ปิด"</item>
<item msgid="460891964396502657">"เปิด"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"ไม่พร้อมใช้งาน"</item>
+ <item msgid="8014986104355098744">"ปิด"</item>
+ <item msgid="5966994759929723339">"เปิด"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index cd15015..58203d3 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Subukang kumuhang muli ng screenshot"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"Hindi ma-save ang screenshot"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Hindi pinahihintulutan ng app o ng iyong organisasyon ang pagkuha ng mga screenshot"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Na-block ng iyong IT admin ang pagkuha ng mga screenshot"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"I-edit"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"I-edit ang screenshot"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"Ibahagi ang screenshot"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"I-auto rotate"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Awtomatikong i-rotate ang screen"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Lokasyon"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Screen saver"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Access sa camera"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Access sa mic"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Available"</string>
@@ -318,6 +320,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Na-unlock gamit ang mukha. Pindutin para buksan."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Nakilala ang mukha. Pindutin para buksan."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Nakilala ang mukha. Pindutin ang icon ng unlock para buksan."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"Mag-swipe pataas para subukan ulit"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"I-unlock para magamit ang NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Pagmamay-ari ng iyong organisasyon ang device na ito"</string>
@@ -467,7 +473,7 @@
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"I-set up para makapagsagawa ng mas mabibilis, mas secure na pagbili gamit ang telepono mo"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"Ipakita lahat"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"Magdagdag ng card"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"I-tap para buksan"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"Ina-update"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"I-unlock para magamit"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Nagkaproblema sa pagkuha ng iyong mga card, pakisubukan ulit sa ibang pagkakataon"</string>
@@ -693,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Mga Alerto"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Baterya"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Mga Screenshot"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Mga Pangkalahatang Mensahe"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"Storage"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Mga Hint"</string>
<string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string>
@@ -727,6 +736,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"I-on kapag malamang na maubos ang baterya"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"Hindi, salamat na lang"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"Ginagamit"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Ginagamit ng mga application ang iyong <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" at "</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Lumapit pa para mag-play sa <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Lumapit sa <xliff:g id="DEVICENAME">%1$s</xliff:g> para mag-play rito"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Nagpe-play sa <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Nagpe-play sa teleponong ito"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Nagkaproblema. Subukan ulit."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Hindi aktibo, tingnan ang app"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Hindi nahanap"</string>
@@ -853,6 +862,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"I-save"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"Nagsisimula…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"Hindi makapag-broadcast"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Hindi ma-save. Subukan ulit."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Hindi ma-save."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Numero ng build"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Nakopya sa clipboard ang numero ng build."</string>
<string name="basic_status" msgid="2315371112182658176">"Buksan ang pag-uusap"</string>
@@ -937,6 +948,13 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"I-edit ang kinopyang text"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"I-edit ang kinopyang larawan"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Ipadala sa kalapit na device"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"I-tap para tingnan"</string>
+ <!-- no translation found for clipboard_text_copied (5100836834278976679) -->
+ <skip />
+ <!-- no translation found for clipboard_image_copied (3793365360174328722) -->
+ <skip />
+ <!-- no translation found for clipboard_content_copied (144452398567828145) -->
+ <skip />
<string name="add" msgid="81036585205287996">"Magdagdag"</string>
<string name="manage_users" msgid="1823875311934643849">"Pamahalaan ang mga user"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"Hindi sinusuportahan ng notification na ito ang pag-drag sa Splitscreen."</string>
@@ -945,4 +963,12 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Nakatakda ang alarm"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Naka-off ang camera at mikropono"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notification}one{# notification}other{# na notification}}"</string>
+ <!-- no translation found for broadcasting_description_is_broadcasting (765627502786404290) -->
+ <skip />
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Ihinto ang pag-broadcast ng <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Kung magbo-broadcast ka ng <xliff:g id="SWITCHAPP">%1$s</xliff:g> o babaguhin mo ang output, hihinto ang iyong kasalukuyang broadcast"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"I-broadcast ang <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Baguhin ang output"</string>
+ <!-- no translation found for bt_le_audio_broadcast_dialog_unknown_name (3791472237793443044) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-tl/tiles_states_strings.xml b/packages/SystemUI/res/values-tl/tiles_states_strings.xml
index 59fed0f..cd7dcf5 100644
--- a/packages/SystemUI/res/values-tl/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-tl/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Naka-off"</item>
<item msgid="460891964396502657">"Naka-on"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Hindi available"</item>
+ <item msgid="8014986104355098744">"Naka-off"</item>
+ <item msgid="5966994759929723339">"Naka-on"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index a902476..e1e7f50 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Tekrar ekran görüntüsü almayı deneyin"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"Ekran görüntüsü kaydedilemiyor"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Uygulama veya kuruluşunuz, ekran görüntüsü alınmasına izin vermiyor."</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"BT yöneticiniz ekran görüntüsü almayı engelledi"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Düzenle"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Ekran görüntüsünü düzenle"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"Ekranı paylaş"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Otomatik döndür"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Ekranı otomatik döndür"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Konum"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Ekran koruyucu"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Kamera erişimi"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Mikrofon erişimi"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Kullanılabilir"</string>
@@ -318,6 +320,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Cihazın kilidini yüzünüzle açtınız. Açmak için basın."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Yüzünüz tanındı. Açmak için basın."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Yüzünüz tanındı. Kilit açma simgesine basın."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"Tekrar denemek için yukarı kaydırın"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC\'yi kullanmak için kilidi açın"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Bu cihaz, kuruluşunuza ait"</string>
@@ -467,7 +473,7 @@
<string name="wallet_title" msgid="5369767670735827105">"Cüzdan"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"Telefonunuzla daha hızlı ve güvenli satın alma işlemleri gerçekleştirmek için gerekli ayarları yapın"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"Tümünü göster"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"Kart ekleyin"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"Açmak için dokunun"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"Güncelleniyor"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Kullanmak için kilidi aç"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Kartlarınız alınırken bir sorun oluştu. Lütfen daha sonra tekrar deneyin"</string>
@@ -500,7 +506,7 @@
<string name="notification_alert_title" msgid="3656229781017543655">"Varsayılan"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Otomatik"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Sessiz veya titreşim yok"</string>
- <string name="notification_conversation_summary_low" msgid="1734433426085468009">"Sessizdir veya titreşim yoktur ve görüşme bölümünün altında görünür"</string>
+ <string name="notification_conversation_summary_low" msgid="1734433426085468009">"Ses veya titreşim yok, görüşme bölümünün altında görünür"</string>
<string name="notification_channel_summary_default" msgid="3282930979307248890">"Telefon ayarlarına bağlı olarak zili çalabilir veya titreyebilir"</string>
<string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Telefon ayarlarına bağlı olarak zili çalabilir veya titreyebilir <xliff:g id="APP_NAME">%1$s</xliff:g> adlı uygulamadan görüşmeler varsayılan olarak baloncukla gösterilir."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Bu bildirimin ses çıkarması veya titreşmesi gerekip gerekmediğine sistem karar versin"</string>
@@ -693,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Uyarılar"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Pil"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Ekran görüntüleri"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Genel Mesajlar"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"Depolama alanı"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"İpuçları"</string>
<string name="instant_apps" msgid="8337185853050247304">"Hazır Uygulamalar"</string>
@@ -727,6 +736,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"Piliniz bitecek gibiyse bu özelliği açın"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"Hayır, teşekkürler"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"SysUI Yığın Dökümü"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"Kullanımda"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Uygulamalar şunları kullanıyor: <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" ve "</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g> cihazında çalmak için yaklaşın"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Burada oynatmak için <xliff:g id="DEVICENAME">%1$s</xliff:g> cihazına yaklaşın"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> cihazında oynatılıyor"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Bu telefonda oynatılıyor"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Bir sorun oldu. Tekrar deneyin."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Devre dışı, uygulamaya bakın"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Bulunamadı"</string>
@@ -853,6 +862,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"Kaydet"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"Başlatılıyor…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"Yayınlanamıyor"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Kaydedilemiyor. Tekrar deneyin."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Kaydedilemiyor."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Derleme numarası"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Derleme numarası panoya kopyalandı."</string>
<string name="basic_status" msgid="2315371112182658176">"Görüşmeyi aç"</string>
@@ -937,6 +948,13 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Kopyalanan metni düzenle"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Kopyalanan resmi düzenle"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Yakındaki cihaza gönder"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"Görüntülemek için dokunun"</string>
+ <!-- no translation found for clipboard_text_copied (5100836834278976679) -->
+ <skip />
+ <!-- no translation found for clipboard_image_copied (3793365360174328722) -->
+ <skip />
+ <!-- no translation found for clipboard_content_copied (144452398567828145) -->
+ <skip />
<string name="add" msgid="81036585205287996">"Ekle"</string>
<string name="manage_users" msgid="1823875311934643849">"Kullanıcıları yönet"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"Bu bildirim, bölünmüş ekrana sürüklenmeyi desteklemiyor."</string>
@@ -945,4 +963,12 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm kuruldu"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera ve mikrofon kapalı"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# bildirim}other{# bildirim}}"</string>
+ <!-- no translation found for broadcasting_description_is_broadcasting (765627502786404290) -->
+ <skip />
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> uygulamasında anons durdurulsun mu?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> uygulamasında anons yapar veya çıkışı değiştirirseniz mevcut anonsunuz duraklatılır"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> uygulamasında anons yapın"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Çıkışı değiştirme"</string>
+ <!-- no translation found for bt_le_audio_broadcast_dialog_unknown_name (3791472237793443044) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-tr/tiles_states_strings.xml b/packages/SystemUI/res/values-tr/tiles_states_strings.xml
index d06d727..28ba7dc 100644
--- a/packages/SystemUI/res/values-tr/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-tr/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Kapalı"</item>
<item msgid="460891964396502657">"Açık"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Kullanılamıyor"</item>
+ <item msgid="8014986104355098744">"Kapalı"</item>
+ <item msgid="5966994759929723339">"Açık"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 0a4c5cb..0822d59 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Спробуйте зробити знімок екрана ще раз"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"Не вдалося зберегти знімок екрана"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Додаток або адміністратор вашої організації не дозволяють робити знімки екрана"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Системний адміністратор заблокував можливість робити знімки екрана"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Редагувати"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Редагувати знімок екрана"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"Поділитися знімком екрана"</string>
@@ -227,6 +228,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Автоматичне обертання"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Автоматично обертати екран"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Геодані"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Заставка"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Доступ до камери"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Доступ до мікрофона"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Дозволено"</string>
@@ -322,6 +324,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Розблоковано (фейсконтроль). Натисніть, щоб відкрити."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Обличчя розпізнано. Натисніть, щоб відкрити."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Обличчя розпізнано. Натисніть значок розблокування."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"Проведіть пальцем угору, щоб повторити спробу"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Розблокуйте екран, щоб скористатись NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Цей пристрій належить вашій організації"</string>
@@ -473,7 +479,7 @@
<string name="wallet_title" msgid="5369767670735827105">"Гаманець"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"Швидше й безпечніше сплачуйте за покупки за допомогою телефона"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"Показати все"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"Додати картку"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"Натисніть, щоб відкрити"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"Оновлення"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Розблокувати, щоб використовувати"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Не вдалось отримати ваші картки. Повторіть спробу пізніше."</string>
@@ -533,7 +539,7 @@
<string name="feedback_prompt" msgid="3656728972307896379">"Надішліть розробнику свій відгук. Усе правильно?"</string>
<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_more_settings" msgid="4936228656989201793">"Інші налаштування"</string>
<string name="notification_app_settings" msgid="8963648463858039377">"Налаштувати"</string>
<string name="notification_conversation_bubble" msgid="2242180995373949022">"Показувати як спливаюче сповіщення"</string>
<string name="notification_conversation_unbubble" msgid="6908427185031099868">"Вимкнути спливаючі чати"</string>
@@ -703,7 +709,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Сповіщення"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Акумулятор"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Знімки екрана"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Загальні повідомлення"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"Пам’ять"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Поради"</string>
<string name="instant_apps" msgid="8337185853050247304">"Додатки з миттєвим запуском"</string>
@@ -737,6 +746,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"Вмикати, коли заряд акумулятора закінчується"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"Ні, дякую"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"Використовується"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Додатки використовують <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" і "</string>
@@ -816,7 +826,7 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Гортайте, щоб переглянути інші"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Завантаження рекомендацій"</string>
<string name="controls_media_title" msgid="1746947284862928133">"Медіа"</string>
- <string name="controls_media_close_session" msgid="4780485355795635052">"Приховати цей елемент керування медіасеансом для <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="controls_media_close_session" msgid="4780485355795635052">"Приховати цей елемент керування для <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="controls_media_active_session" msgid="3146882316024153337">"Поточний медіасеанс не можна приховати."</string>
<string name="controls_media_dismiss_button" msgid="4485675693008031646">"Приховати"</string>
<string name="controls_media_resume" msgid="1933520684481586053">"Відновити"</string>
@@ -836,7 +846,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Щоб відтворити контент на пристрої <xliff:g id="DEVICENAME">%1$s</xliff:g>, наблизьтеся до нього"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Наблизьтеся до пристрою <xliff:g id="DEVICENAME">%1$s</xliff:g>, щоб відтворити медіафайли на ньому"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Відтворюється на пристрої <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Відтворюється на цьому телефоні"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Сталася помилка. Повторіть спробу."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Неактивно, перейдіть у додаток"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Не знайдено"</string>
@@ -865,6 +874,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"Зберегти"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"Запуск…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"Неможливо транслювати"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Не вдалося зберегти. Повторіть спробу."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Не вдалося зберегти."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Номер складання"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Номер складання скопійовано в буфер обміну."</string>
<string name="basic_status" msgid="2315371112182658176">"Відкрита розмова"</string>
@@ -951,6 +962,13 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Редагувати скопійований текст"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Редагувати скопійоване зображення"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Надіслати на пристрій поблизу"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"Натисніть, щоб переглянути"</string>
+ <!-- no translation found for clipboard_text_copied (5100836834278976679) -->
+ <skip />
+ <!-- no translation found for clipboard_image_copied (3793365360174328722) -->
+ <skip />
+ <!-- no translation found for clipboard_content_copied (144452398567828145) -->
+ <skip />
<string name="add" msgid="81036585205287996">"Додати"</string>
<string name="manage_users" msgid="1823875311934643849">"Керувати користувачами"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"Це сповіщення не підтримує режим розділеного екрана."</string>
@@ -959,4 +977,12 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Будильник установлено"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Камеру й мікрофон вимкнено"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# сповіщення}one{# сповіщення}few{# сповіщення}many{# сповіщень}other{# сповіщення}}"</string>
+ <!-- no translation found for broadcasting_description_is_broadcasting (765627502786404290) -->
+ <skip />
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Зупинити трансляцію з додатка <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Якщо ви зміните додаток (<xliff:g id="SWITCHAPP">%1$s</xliff:g>) або аудіовихід, поточну трансляцію буде припинено"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Змінити додаток для трансляції на <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Змінити аудіовихід"</string>
+ <!-- no translation found for bt_le_audio_broadcast_dialog_unknown_name (3791472237793443044) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-uk/tiles_states_strings.xml b/packages/SystemUI/res/values-uk/tiles_states_strings.xml
index 040fb4d..3f6ca46 100644
--- a/packages/SystemUI/res/values-uk/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-uk/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Вимкнено"</item>
<item msgid="460891964396502657">"Увімкнено"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Недоступно"</item>
+ <item msgid="8014986104355098744">"Вимкнено"</item>
+ <item msgid="5966994759929723339">"Увімкнено"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index bb66e1c..2934b93 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"دوبارہ اسکرین شاٹ لینے کی کوشش کریں"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"اسکرین شاٹ کو محفوظ نہیں کیا جا سکتا"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"ایپ یا آپ کی تنظیم کی جانب سے اسکرین شاٹس لینے کی اجازت نہیں ہے"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"IT منتظم نے اسکرین شاٹس لینا مسدود کر دیا ہے"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"ترمیم کریں"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"اسکرین شاٹ میں ترمیم کریں"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"اسکرین شاٹ کا اشتراک کریں"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"خود کار طور پر گھمائیں"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"اسکرین کو خود کار طور پر گھمائیں"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"مقام"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"اسکرین سیور"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"کیمرا تک رسائی"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"مائیکروفون تک رسائی"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"دستیاب ہے"</string>
@@ -318,6 +320,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"چہرے سے انلاک کیا گیا۔ کھولنے کے لیے دبائیں۔"</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"چہرے کی شناخت ہو گئی۔ کھولنے کے لیے دبائیں۔"</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"چہرے کی شناخت ہو گئی۔ کھولنے کیلئے انلاک آئیکن دبائیں۔"</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"دوبارہ کوشش کرنے کے لیے اوپر سوائپ کريں"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC استعمال کرنے کیلئے غیر مقفل کریں"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"یہ آلہ آپ کی تنظیم کا ہے"</string>
@@ -467,7 +473,7 @@
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"اپنے فون سے تیز تر مزید محفوظ خریداریاں کرنے کے لیے، سیٹ اپ مکمل کریں"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"سبھی دکھائیں"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"کارڈ شامل کریں"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"کھولنے کیلئے تھپتھپائیں"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"اپ ڈیٹ ہو رہا ہے"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"استعمال کرنے کے لیے غیر مقفل کریں"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"آپ کے کارڈز حاصل کرنے میں ایک مسئلہ درپیش تھا، براہ کرم بعد میں دوبارہ کوشش کریں"</string>
@@ -693,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"الرٹس"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"بیٹری"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"اسکرین شاٹس"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"عمومی پیغامات"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"اسٹوریج"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"اشارات"</string>
<string name="instant_apps" msgid="8337185853050247304">"فوری ایپس"</string>
@@ -727,6 +736,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"جب بیٹری کے ختم ہونے کا امکان ہو تو آن کریں"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"نہیں شکریہ"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"زیر استعمال"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"ایپلیکیشنز آپ کی <xliff:g id="TYPES_LIST">%s</xliff:g> کا استعمال کر رہی ہیں۔"</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">"، "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" اور "</string>
@@ -804,7 +814,7 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"مزید دیکھنے کیلئے سوائپ کریں"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"تجاویز لوڈ ہو رہی ہیں"</string>
<string name="controls_media_title" msgid="1746947284862928133">"میڈیا"</string>
- <string name="controls_media_close_session" msgid="4780485355795635052">"<xliff:g id="APP_NAME">%1$s</xliff:g> کے لیے اس میڈیا کنٹرول کو چھپائیں؟"</string>
+ <string name="controls_media_close_session" msgid="4780485355795635052">"<xliff:g id="APP_NAME">%1$s</xliff:g> کے لیے اس میڈیا کنٹرول کو چھپائیں؟"</string>
<string name="controls_media_active_session" msgid="3146882316024153337">"میڈیا کے موجودہ سیشن کو چھپایا نہیں جا سکتا۔"</string>
<string name="controls_media_dismiss_button" msgid="4485675693008031646">"چھپائیں"</string>
<string name="controls_media_resume" msgid="1933520684481586053">"دوبارہ شروع کریں"</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g> پر چلانے کے لیے قریب کریں"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"یہاں چلانے کے ليے <xliff:g id="DEVICENAME">%1$s</xliff:g> کے قریب جائیں"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> پر چل رہا ہے"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"اس فون پر چل رہا ہے"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"کچھ غلط ہوگیا۔ پھر کوشش کریں۔"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"غیر فعال، ایپ چیک کریں"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"نہیں ملا"</string>
@@ -853,6 +862,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"محفوظ کریں"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"شروع ہو رہا ہے…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"براڈکاسٹ نہیں کیا جا سکتا"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"محفوظ نہیں کیا جا سکا۔ پھر کوشش کریں۔"</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"محفوظ نہیں کیا جا سکا۔"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"بلڈ نمبر"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"بلڈ نمبر کلپ بورڈ میں کاپی ہو گیا۔"</string>
<string name="basic_status" msgid="2315371112182658176">"گفتگو کھولیں"</string>
@@ -937,6 +948,13 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"کاپی کردہ ٹیکسٹ میں ترمیم کریں"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"کاپی کردہ تصویر میں ترمیم کریں"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"قریبی آلے کو بھیجیں"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"دیکھنے کے لیے تھپتھپائیں"</string>
+ <!-- no translation found for clipboard_text_copied (5100836834278976679) -->
+ <skip />
+ <!-- no translation found for clipboard_image_copied (3793365360174328722) -->
+ <skip />
+ <!-- no translation found for clipboard_content_copied (144452398567828145) -->
+ <skip />
<string name="add" msgid="81036585205287996">"شامل کریں"</string>
<string name="manage_users" msgid="1823875311934643849">"صارفین کا نظم کریں"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"یہ اطلاع اسپلٹ اسکرین کو گھسیٹنے کو سپورٹ نہیں کرتا ہے۔"</string>
@@ -945,4 +963,12 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"الارم سیٹ ہوگیا"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"کیمرا اور مائیک آف ہیں"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# اطلاع}other{# اطلاعات}}"</string>
+ <!-- no translation found for broadcasting_description_is_broadcasting (765627502786404290) -->
+ <skip />
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> براڈکاسٹنگ روکیں؟"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"اگر آپ <xliff:g id="SWITCHAPP">%1$s</xliff:g> براڈکاسٹ کرتے ہیں یا آؤٹ پٹ کو تبدیل کرتے ہیں تو آپ کا موجودہ براڈکاسٹ رک جائے گا"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> پر براڈکاسٹ کریں"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"آؤٹ پٹ تبدیل کریں"</string>
+ <!-- no translation found for bt_le_audio_broadcast_dialog_unknown_name (3791472237793443044) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ur/tiles_states_strings.xml b/packages/SystemUI/res/values-ur/tiles_states_strings.xml
index 79d2cf6..05aa4e9 100644
--- a/packages/SystemUI/res/values-ur/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ur/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"آف"</item>
<item msgid="460891964396502657">"آن"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"غیر دستیاب"</item>
+ <item msgid="8014986104355098744">"آف"</item>
+ <item msgid="5966994759929723339">"آن"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 6857a1e..9b30ab3 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Qayta skrinshot olib ko‘ring"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"Skrinshot saqlanmadi"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Ilova yoki tashkilotingiz skrinshot olishni taqiqlagan"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Skrinshot olishni AT administratori taqiqlagan"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Tahrirlash"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Skrinshotni tahrirlash"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"Skrinshot yuborish"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Avto-burilish"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Ekranning avtomatik burilishi"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Joylashuv"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Ekran lavhasi"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Kameraga ruxsat"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Mikrofonga ruxsat"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Mavjud"</string>
@@ -318,6 +320,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Yuz orqali ochildi. Ochish uchun bosing."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Yuz aniqlandi. Ochish uchun bosing."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Yuz aniqlandi. Ochish uchun ochish belgisini bosing."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"Qayta urinish uchun tepaga suring"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC ishlatish uchun qurilma qulfini oching"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Bu qurilma tashkilotingizga tegishli"</string>
@@ -467,7 +473,7 @@
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"Telefonda tezroq va xavfsizroq xarid qilish uchun sozlang"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"Hammasi"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"Karta kiritish"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"Ochish uchun ustiga bosing"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"Yangilanmoqda"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Foydalanish uchun qulfdan chiqarish"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Bildirgilarni yuklashda xatolik yuz berdi, keyinroq qaytadan urining"</string>
@@ -693,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Bildirishnomalar"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Batareya"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Skrinshotlar"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Umumiy xabarlar"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"Xotira"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Maslahatlar"</string>
<string name="instant_apps" msgid="8337185853050247304">"Darhol ochiladigan ilovalar"</string>
@@ -727,6 +736,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"Batareya quvvati kamayishi aniqlanganda yoqilsin"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"Kerak emas"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"Foydalanilmoqda"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Ilovalarda ishlatilmoqda: <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" va "</string>
@@ -804,7 +814,7 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Batafsil axborot olish uchun suring"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Tavsiyalar yuklanmoqda"</string>
<string name="controls_media_title" msgid="1746947284862928133">"Media"</string>
- <string name="controls_media_close_session" msgid="4780485355795635052">"<xliff:g id="APP_NAME">%1$s</xliff:g> uchun media boshqaruvi yashirilsinmi?"</string>
+ <string name="controls_media_close_session" msgid="4780485355795635052">"<xliff:g id="APP_NAME">%1$s</xliff:g> uchun media boshqaruvi berkitilsinmi?"</string>
<string name="controls_media_active_session" msgid="3146882316024153337">"Joriy media seansi berkitilmadi."</string>
<string name="controls_media_dismiss_button" msgid="4485675693008031646">"Berkitish"</string>
<string name="controls_media_resume" msgid="1933520684481586053">"Davom etish"</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g>da ijro etish uchun yaqinroq keling"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Bu yerda ijro qilish uchun <xliff:g id="DEVICENAME">%1$s</xliff:g>qurilmasiga yaqinlashtiring"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> qurilmasida ijro qilinmoqda"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Bu telefonda ijro etilmoqda"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Xatolik yuz berdi. Qayta urining."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Nofaol. Ilovani tekshiring"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Topilmadi"</string>
@@ -853,6 +862,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"Saqlash"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"Ishga tushmoqda…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"Uzatilmadi"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Saqlanmadi. Qayta urining."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Saqlanmadi."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Nashr raqami"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Nashr raqami vaqtinchalik xotiraga nusxalandi."</string>
<string name="basic_status" msgid="2315371112182658176">"Suhbatni ochish"</string>
@@ -937,6 +948,13 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Nusxa olingan matnni tahrirlash"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Nusxa olingan rasmni tahrirlash"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Yaqin-atrofdagi qurilmaga yuborish"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"Koʻrish uchun bosing"</string>
+ <!-- no translation found for clipboard_text_copied (5100836834278976679) -->
+ <skip />
+ <!-- no translation found for clipboard_image_copied (3793365360174328722) -->
+ <skip />
+ <!-- no translation found for clipboard_content_copied (144452398567828145) -->
+ <skip />
<string name="add" msgid="81036585205287996">"Kiritish"</string>
<string name="manage_users" msgid="1823875311934643849">"Foydalanuvchilarni boshqarish"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"Bu bildirishnoma ikkiga ajratilgan ekranda ishlamaydi."</string>
@@ -945,4 +963,12 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Signal oʻrnatildi"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera va mikrofon yoqilmagan"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# ta bildirishnoma}other{# ta bildirishnoma}}"</string>
+ <!-- no translation found for broadcasting_description_is_broadcasting (765627502786404290) -->
+ <skip />
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> ilovasiga translatsiya toʻxtatilsinmi?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Agar <xliff:g id="SWITCHAPP">%1$s</xliff:g> ilovasiga translatsiya qilsangiz yoki ovoz chiqishini oʻzgartirsangiz, joriy translatsiya toʻxtab qoladi"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> ilovasiga translatsiya"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Ovoz chiqishini oʻzgartirish"</string>
+ <!-- no translation found for bt_le_audio_broadcast_dialog_unknown_name (3791472237793443044) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-uz/tiles_states_strings.xml b/packages/SystemUI/res/values-uz/tiles_states_strings.xml
index b687597..a84f769 100644
--- a/packages/SystemUI/res/values-uz/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-uz/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Oʻchiq"</item>
<item msgid="460891964396502657">"Yoniq"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Bandman"</item>
+ <item msgid="8014986104355098744">"Oʻchiq"</item>
+ <item msgid="5966994759929723339">"Yoniq"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 7719837..dcd1d4b 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Hãy thử chụp lại màn hình"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"Không thể lưu ảnh chụp màn hình"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Ứng dụng hoặc tổ chức của bạn không cho phép chụp ảnh màn hình"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Quản trị viên CNTT chặn tính năng chụp ảnh màn hình"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Chỉnh sửa"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Chỉnh sửa ảnh chụp màn hình"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"Chia sẻ ảnh chụp màn hình"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Tự động xoay"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Tự động xoay màn hình"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Vị trí"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Trình bảo vệ màn hình"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Truy cập máy ảnh"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Truy cập micrô"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Được phép"</string>
@@ -318,6 +320,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Đã mở khoá bằng khuôn mặt. Nhấn để mở."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Đã nhận diện khuôn mặt. Nhấn để mở."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Đã nhận diện khuôn mặt. Nhấn biểu tượng mở khoá để mở."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"Vuốt lên để thử lại"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Mở khóa để sử dụng NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Thiết bị này thuộc về tổ chức của bạn"</string>
@@ -467,7 +473,7 @@
<string name="wallet_title" msgid="5369767670735827105">"Ví"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"Thiết lập để mua hàng nhanh hơn và an toàn hơn bằng điện thoại"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"Hiện tất cả"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"Thêm thẻ"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"Nhấn để mở"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"Đang cập nhật"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Mở khóa để sử dụng"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Đã xảy ra sự cố khi tải thẻ của bạn. Vui lòng thử lại sau"</string>
@@ -693,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Cảnh báo"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Pin"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Ảnh chụp màn hình"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Thông báo chung"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"Bộ nhớ"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Gợi ý"</string>
<string name="instant_apps" msgid="8337185853050247304">"Ứng dụng tức thì"</string>
@@ -727,6 +736,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"Bật khi pin sắp hết"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"Không, cảm ơn"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Trích xuất bộ nhớ SysUI"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"Đang được sử dụng"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Các ứng dụng đang dùng <xliff:g id="TYPES_LIST">%s</xliff:g> của bạn."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" và "</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Đưa thiết bị đến gần hơn để phát trên <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Di chuyển đến gần <xliff:g id="DEVICENAME">%1$s</xliff:g> hơn để phát tại đây"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Đang phát trên <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Đang phát trên điện thoại này"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Đã xảy ra lỗi. Hãy thử lại."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Không hoạt động, hãy kiểm tra ứng dụng"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Không tìm thấy"</string>
@@ -853,6 +862,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"Lưu"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"Đang bắt đầu…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"Không thể truyền"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Không lưu được. Hãy thử lại."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Không lưu được."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Số bản dựng"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Đã sao chép số bản dựng vào bảng nhớ tạm."</string>
<string name="basic_status" msgid="2315371112182658176">"Mở cuộc trò chuyện"</string>
@@ -927,7 +938,7 @@
</plurals>
<string name="fgs_dot_content_description" msgid="2865071539464777240">"Thông tin mới"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Ứng dụng đang hoạt động"</string>
- <string name="fgs_manager_dialog_message" msgid="6839542063522121108">"Ngay cả khi bạn không sử dụng, những ứng dụng này vẫn hoạt động và có thể ảnh hưởng đến tuổi thọ pin"</string>
+ <string name="fgs_manager_dialog_message" msgid="6839542063522121108">"Ngay cả khi bạn không sử dụng, những ứng dụng này vẫn hoạt động và có thể ảnh hưởng đến thời lượng pin"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Dừng"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Đã dừng"</string>
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Xong"</string>
@@ -937,6 +948,13 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Chỉnh sửa văn bản đã sao chép"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Chỉnh sửa hình ảnh đã sao chép"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Gửi đến thiết bị ở gần"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"Nhấn để xem"</string>
+ <!-- no translation found for clipboard_text_copied (5100836834278976679) -->
+ <skip />
+ <!-- no translation found for clipboard_image_copied (3793365360174328722) -->
+ <skip />
+ <!-- no translation found for clipboard_content_copied (144452398567828145) -->
+ <skip />
<string name="add" msgid="81036585205287996">"Thêm"</string>
<string name="manage_users" msgid="1823875311934643849">"Quản lý người dùng"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"Thông báo này không hỗ trợ thao tác kéo để Chia đôi màn hình."</string>
@@ -945,4 +963,12 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Đã đặt chuông báo"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Máy ảnh và micrô đang tắt"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# thông báo}other{# thông báo}}"</string>
+ <!-- no translation found for broadcasting_description_is_broadcasting (765627502786404290) -->
+ <skip />
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Dừng phát <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Nếu bạn phát <xliff:g id="SWITCHAPP">%1$s</xliff:g> hoặc thay đổi đầu ra, phiên truyền phát hiện tại sẽ dừng"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Phát <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Thay đổi đầu ra"</string>
+ <!-- no translation found for bt_le_audio_broadcast_dialog_unknown_name (3791472237793443044) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-vi/tiles_states_strings.xml b/packages/SystemUI/res/values-vi/tiles_states_strings.xml
index 827c72a..482a32f 100644
--- a/packages/SystemUI/res/values-vi/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-vi/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Đang tắt"</item>
<item msgid="460891964396502657">"Đang bật"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Không có sẵn"</item>
+ <item msgid="8014986104355098744">"Tắt"</item>
+ <item msgid="5966994759929723339">"Đang bật"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 7f45b1e..7d58df3 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"请再次尝试截屏"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"无法保存屏幕截图"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"此应用或您所在的单位不允许进行屏幕截图"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"您的 IT 管理员已禁止截取屏幕截图"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"编辑"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"编辑屏幕截图"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"分享屏幕截图"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"自动旋转屏幕"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"自动旋转屏幕"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"位置信息"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"屏保"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"摄像头使用权限"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"麦克风使用权限"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"已允许"</string>
@@ -318,6 +320,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"已通过面孔识别解锁。点按即可打开。"</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"识别出面孔。点按即可打开。"</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"识别出面孔。按下解锁图标即可打开。"</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"向上滑动即可重试"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"需要解锁才能使用 NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"此设备归贵单位所有"</string>
@@ -467,7 +473,7 @@
<string name="wallet_title" msgid="5369767670735827105">"电子钱包"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"开始设置,享受更加快捷安全的手机购物体验"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"全部显示"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"添加卡"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"点按即可打开"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"正在更新"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"解锁设备即可使用"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"获取您的卡片时出现问题,请稍后重试"</string>
@@ -693,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"提醒"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"电池"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"屏幕截图"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"常规消息"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"存储空间"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"提示"</string>
<string name="instant_apps" msgid="8337185853050247304">"免安装应用"</string>
@@ -727,6 +736,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"在电池电量可能会耗尽时,系统会开启此模式"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"不用了"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"转储 SysUI 堆"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"正在使用"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"有多个应用正在使用您的<xliff:g id="TYPES_LIST">%s</xliff:g>。"</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">"、 "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" 和 "</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"若要在“<xliff:g id="DEVICENAME">%1$s</xliff:g>”上播放,请靠近这台设备"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"若要在此设备上播放,请靠近“<xliff:g id="DEVICENAME">%1$s</xliff:g>”"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"正在“<xliff:g id="DEVICENAME">%1$s</xliff:g>”上播放"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"正在此手机上播放"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"出了点问题,请重试。"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"无效,请检查应用"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"未找到"</string>
@@ -853,6 +862,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"保存"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"即将开始…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"无法广播"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"无法保存,请重试。"</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"无法保存。"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"版本号"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"已将版本号复制到剪贴板。"</string>
<string name="basic_status" msgid="2315371112182658176">"开放式对话"</string>
@@ -922,11 +933,11 @@
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"不添加图块"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"选择用户"</string>
<plurals name="fgs_manager_footer_label" formatted="false" msgid="790443735462280164">
- <item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> 个应用处于活动状态</item>
- <item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> 个应用处于活动状态</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> 个应用正在运行</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> 个应用正在运行</item>
</plurals>
<string name="fgs_dot_content_description" msgid="2865071539464777240">"新信息"</string>
- <string name="fgs_manager_dialog_title" msgid="5879184257257718677">"使用中的应用"</string>
+ <string name="fgs_manager_dialog_title" msgid="5879184257257718677">"已开启的应用"</string>
<string name="fgs_manager_dialog_message" msgid="6839542063522121108">"即使您未使用这些应用,它们仍会处于活动状态,并可能会影响电池续航时间"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"停止"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"已停止"</string>
@@ -937,6 +948,10 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"修改所复制的文字"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"编辑所复制的图片"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"发送到附近的设备"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"点按即可查看"</string>
+ <string name="clipboard_text_copied" msgid="5100836834278976679">"文本已复制"</string>
+ <string name="clipboard_image_copied" msgid="3793365360174328722">"图片已复制"</string>
+ <string name="clipboard_content_copied" msgid="144452398567828145">"内容已复制"</string>
<string name="add" msgid="81036585205287996">"添加"</string>
<string name="manage_users" msgid="1823875311934643849">"管理用户"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"此通知不支持拖动到分屏中。"</string>
@@ -945,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"闹钟已设置"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"摄像头和麦克风已关闭"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# 条通知}other{# 条通知}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"正在广播"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"要停止广播“<xliff:g id="APP_NAME">%1$s</xliff:g>”的内容吗?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"如果广播“<xliff:g id="SWITCHAPP">%1$s</xliff:g>”的内容或更改输出来源,当前的广播就会停止"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"广播“<xliff:g id="SWITCHAPP">%1$s</xliff:g>”的内容"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"更改输出来源"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"未知"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/tiles_states_strings.xml b/packages/SystemUI/res/values-zh-rCN/tiles_states_strings.xml
index 3c62872..b476255 100644
--- a/packages/SystemUI/res/values-zh-rCN/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"已关闭"</item>
<item msgid="460891964396502657">"已开启"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"不可用"</item>
+ <item msgid="8014986104355098744">"关闭"</item>
+ <item msgid="5966994759929723339">"开启"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index b99be40..5278251 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"請再嘗試拍攝螢幕擷取畫面"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"無法儲存螢幕截圖"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"應用程式或您的機構不允許擷取螢幕畫面"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"您的 IT 管理員已禁止擷取螢幕截圖"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"編輯"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"編輯螢幕截圖"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"分享螢幕截圖"</string>
@@ -141,21 +142,21 @@
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"已識別面孔。按解鎖圖示即可繼續。"</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"驗證咗"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"使用 PIN"</string>
- <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"使用圖形"</string>
+ <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"使用圖案"</string>
<string name="biometric_dialog_use_password" msgid="3445033859393474779">"使用密碼"</string>
<string name="biometric_dialog_wrong_pin" msgid="1878539073972762803">"PIN 錯誤"</string>
- <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"圖形錯誤"</string>
+ <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"圖案錯誤"</string>
<string name="biometric_dialog_wrong_password" msgid="69477929306843790">"密碼錯誤"</string>
<string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"輸入錯誤的次數太多,\n請於 <xliff:g id="NUMBER">%d</xliff:g> 秒後再試。"</string>
<string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"請再試一次。您已嘗試 <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> 次,最多可試 <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g> 次。"</string>
<string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"您的資料將會刪除"</string>
- <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"如果您下次畫出錯誤的上鎖圖形,系統將會刪除此裝置上的資料。"</string>
+ <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"如果您下次畫出錯誤的上鎖圖案,系統將會刪除此裝置上的資料。"</string>
<string name="biometric_dialog_last_pin_attempt_before_wipe_device" msgid="9151756675698215723">"如果您下次輸入錯誤的 PIN,系統將會刪除此裝置上的資料。"</string>
<string name="biometric_dialog_last_password_attempt_before_wipe_device" msgid="2363778585575998317">"如果您下次輸入錯誤的密碼,系統將會刪除此裝置上的資料。"</string>
- <string name="biometric_dialog_last_pattern_attempt_before_wipe_user" msgid="8400180746043407270">"如果您下次畫出錯誤的上鎖圖形,系統將會刪除此使用者。"</string>
+ <string name="biometric_dialog_last_pattern_attempt_before_wipe_user" msgid="8400180746043407270">"如果您下次畫出錯誤的上鎖圖案,系統將會刪除此使用者。"</string>
<string name="biometric_dialog_last_pin_attempt_before_wipe_user" msgid="4159878829962411168">"如果您下次輸入錯誤的 PIN,系統將會刪除此使用者。"</string>
<string name="biometric_dialog_last_password_attempt_before_wipe_user" msgid="4695682515465063885">"如果您下次輸入錯誤的密碼,系統將會刪除此使用者。"</string>
- <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"如果您下次畫出錯誤的上鎖圖形,系統將會刪除工作設定檔和相關資料。"</string>
+ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"如果您下次畫出錯誤的上鎖圖案,系統將會刪除工作設定檔和相關資料。"</string>
<string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"如果您下次輸入錯誤的 PIN,系統將會刪除工作設定檔和相關資料。"</string>
<string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"如果您下次輸入錯誤的密碼,系統將會刪除工作設定檔和相關資料。"</string>
<string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"請輕觸指紋感應器"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"自動旋轉"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"自動旋轉螢幕"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"位置"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"螢幕保護程式"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"相機存取權"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"麥克風存取權"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"允許"</string>
@@ -318,6 +320,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"已使用面孔解鎖。按下即可開啟。"</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"已識別面孔。按下即可開啟。"</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"已識別面孔。按解鎖圖示即可開啟。"</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"請向上滑動以再試一次"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"解鎖方可使用 NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"此裝置屬於您的機構"</string>
@@ -467,7 +473,7 @@
<string name="wallet_title" msgid="5369767670735827105">"電子錢包"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"完成設定後即可透過手機更快速安全地購物"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"顯示全部"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"新增付款卡"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"輕按即可開啟"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"更新中"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"解鎖即可使用"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"擷取資訊卡時發生問題,請稍後再試。"</string>
@@ -693,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"通知"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"電池"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"螢幕擷取畫面"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"一般訊息"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"儲存空間"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"提示"</string>
<string name="instant_apps" msgid="8337185853050247304">"免安裝應用程式"</string>
@@ -727,6 +736,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"在電池電量可能耗盡前啟用「省電模式」"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"不用了,謝謝"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"使用中"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"有多個應用程式正在使用<xliff:g id="TYPES_LIST">%s</xliff:g>。"</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">"、 "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" 和 "</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"如要在「<xliff:g id="DEVICENAME">%1$s</xliff:g>」上播放,請靠近一點"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"如要在此裝置上播放,請靠近「<xliff:g id="DEVICENAME">%1$s</xliff:g>」"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"正在「<xliff:g id="DEVICENAME">%1$s</xliff:g>」上播放"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"正在此手機上播放"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"發生錯誤,請再試一次。"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"已停用,請檢查應用程式"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"找不到"</string>
@@ -853,6 +862,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"儲存"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"啟動中…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"無法廣播"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"無法儲存,請再試一次。"</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"無法儲存。"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"版本號碼"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"版本號碼已複製到剪貼簿。"</string>
<string name="basic_status" msgid="2315371112182658176">"開啟對話"</string>
@@ -937,6 +948,13 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"編輯已複製的文字"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"編輯已複製的圖片"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"傳送至附近的裝置"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"輕按即可查看"</string>
+ <!-- no translation found for clipboard_text_copied (5100836834278976679) -->
+ <skip />
+ <!-- no translation found for clipboard_image_copied (3793365360174328722) -->
+ <skip />
+ <!-- no translation found for clipboard_content_copied (144452398567828145) -->
+ <skip />
<string name="add" msgid="81036585205287996">"新增"</string>
<string name="manage_users" msgid="1823875311934643849">"管理使用者"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"此通知無法拖曳到分割螢幕中。"</string>
@@ -945,4 +963,12 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"已設定鬧鐘"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"相機和麥克風已關閉"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# 則通知}other{# 則通知}}"</string>
+ <!-- no translation found for broadcasting_description_is_broadcasting (765627502786404290) -->
+ <skip />
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"要停止廣播「<xliff:g id="APP_NAME">%1$s</xliff:g>」的內容嗎?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"如要廣播「<xliff:g id="SWITCHAPP">%1$s</xliff:g>」的內容或變更輸出來源,系統就會停止廣播目前的內容"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"廣播「<xliff:g id="SWITCHAPP">%1$s</xliff:g>」的內容"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"變更輸出來源"</string>
+ <!-- no translation found for bt_le_audio_broadcast_dialog_unknown_name (3791472237793443044) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/tiles_states_strings.xml b/packages/SystemUI/res/values-zh-rHK/tiles_states_strings.xml
index ee41066..ab8e961a 100644
--- a/packages/SystemUI/res/values-zh-rHK/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"關閉"</item>
<item msgid="460891964396502657">"開啟"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"無法使用"</item>
+ <item msgid="8014986104355098744">"已關閉"</item>
+ <item msgid="5966994759929723339">"已開啟"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 250070a..16cda00 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"請再次嘗試拍攝螢幕截圖"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"無法儲存螢幕截圖"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"這個應用程式或貴機構不允許擷取螢幕畫面"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"你的 IT 管理員已禁止擷取螢幕畫面"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"編輯"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"編輯螢幕截圖"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"分享螢幕截圖"</string>
@@ -95,7 +96,7 @@
<string name="screenrecord_description" msgid="1123231719680353736">"錄製螢幕畫面時,Android 系統可擷取螢幕上顯示或裝置播放的任何機密資訊,包括密碼、付款資訊、相片、訊息和音訊。"</string>
<string name="screenrecord_audio_label" msgid="6183558856175159629">"錄音"</string>
<string name="screenrecord_device_audio_label" msgid="9016927171280567791">"裝置音訊"</string>
- <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"裝置播放的音效,例如音樂、通話和鈴聲"</string>
+ <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"裝置所播放的音效,例如音樂、通話和鈴聲等等"</string>
<string name="screenrecord_mic_label" msgid="2111264835791332350">"麥克風"</string>
<string name="screenrecord_device_audio_and_mic_label" msgid="1831323771978646841">"裝置音訊和麥克風"</string>
<string name="screenrecord_start" msgid="330991441575775004">"開始"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"自動旋轉"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"自動旋轉螢幕"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"定位"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"螢幕保護程式"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"相機存取權"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"麥克風存取權"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"可以使用"</string>
@@ -318,6 +320,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"裝置已透過你的臉解鎖,按下即可開啟。"</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"臉孔辨識完成,按下即可開啟。"</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"臉孔辨識完成,按下「解鎖」圖示即可開啟。"</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"向上滑動即可重試"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"如要使用 NFC,請先解鎖"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"這部裝置的擁有者為貴機構"</string>
@@ -467,7 +473,7 @@
<string name="wallet_title" msgid="5369767670735827105">"電子錢包"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"完成相關設定之後,就能以更快速安全的方式透過手機消費"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"顯示全部"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"新增卡片"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"輕觸即可開啟"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"更新中"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"解鎖即可使用"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"擷取卡片時發生問題,請稍後再試"</string>
@@ -693,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"快訊"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"電池"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"螢幕截圖"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"一般訊息"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"儲存空間"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"提示"</string>
<string name="instant_apps" msgid="8337185853050247304">"免安裝應用程式"</string>
@@ -727,6 +736,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"在電池電量即將耗盡時開啟"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"不用了,謝謝"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"使用中"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"有多個應用程式正在使用<xliff:g id="TYPES_LIST">%s</xliff:g>。"</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">"、 "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" 和 "</string>
@@ -804,7 +814,7 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"滑動即可查看其他結構"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"正在載入建議控制項"</string>
<string name="controls_media_title" msgid="1746947284862928133">"媒體"</string>
- <string name="controls_media_close_session" msgid="4780485355795635052">"要隱藏「<xliff:g id="APP_NAME">%1$s</xliff:g>」的這個媒體控制選項嗎?"</string>
+ <string name="controls_media_close_session" msgid="4780485355795635052">"要隱藏「<xliff:g id="APP_NAME">%1$s</xliff:g>」的媒體控制選項嗎?"</string>
<string name="controls_media_active_session" msgid="3146882316024153337">"無法隱藏目前的媒體工作階段。"</string>
<string name="controls_media_dismiss_button" msgid="4485675693008031646">"隱藏"</string>
<string name="controls_media_resume" msgid="1933520684481586053">"繼續播放"</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"如要在「<xliff:g id="DEVICENAME">%1$s</xliff:g>」上播放,請靠近一點"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"如要在這部裝置上播放,請移到更靠近「<xliff:g id="DEVICENAME">%1$s</xliff:g>」的位置"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"正在「<xliff:g id="DEVICENAME">%1$s</xliff:g>」上播放"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"正在這支手機上播放"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"發生錯誤,請再試一次。"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"無效,請查看應用程式"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"找不到控制項"</string>
@@ -853,6 +862,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"儲存"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"啟動中…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"無法廣播"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"無法儲存,請再試一次。"</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"無法儲存。"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"版本號碼"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"已將版本號碼複製到剪貼簿。"</string>
<string name="basic_status" msgid="2315371112182658176">"開放式對話"</string>
@@ -937,6 +948,13 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"編輯複製的文字"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"編輯複製的圖片"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"傳送到鄰近裝置"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"輕觸即可查看"</string>
+ <!-- no translation found for clipboard_text_copied (5100836834278976679) -->
+ <skip />
+ <!-- no translation found for clipboard_image_copied (3793365360174328722) -->
+ <skip />
+ <!-- no translation found for clipboard_content_copied (144452398567828145) -->
+ <skip />
<string name="add" msgid="81036585205287996">"新增"</string>
<string name="manage_users" msgid="1823875311934643849">"管理使用者"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"這項通知無法拖曳到分割畫面中。"</string>
@@ -945,4 +963,12 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"鬧鐘設定成功"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"已關閉相機和麥克風"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# 則通知}other{# 則通知}}"</string>
+ <!-- no translation found for broadcasting_description_is_broadcasting (765627502786404290) -->
+ <skip />
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"要停止播送「<xliff:g id="APP_NAME">%1$s</xliff:g>」的內容嗎?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"如果播送「<xliff:g id="SWITCHAPP">%1$s</xliff:g>」的內容或變更輸出來源,系統就會停止播送目前的內容"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"播送「<xliff:g id="SWITCHAPP">%1$s</xliff:g>」的內容"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"變更輸出來源"</string>
+ <!-- no translation found for bt_le_audio_broadcast_dialog_unknown_name (3791472237793443044) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/tiles_states_strings.xml b/packages/SystemUI/res/values-zh-rTW/tiles_states_strings.xml
index 1f70740..3d6a546 100644
--- a/packages/SystemUI/res/values-zh-rTW/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"已關閉"</item>
<item msgid="460891964396502657">"已開啟"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"無法使用"</item>
+ <item msgid="8014986104355098744">"已關閉"</item>
+ <item msgid="5966994759929723339">"已開啟"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index b2864f9..38b5dc7 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -78,6 +78,7 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Zama ukuthatha isithombe-skrini futhi"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"Ayikwazi ukulondoloza isithombe-skrini"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Ukuthatha izithombe-skrini akuvunyelwe uhlelo lokusebenza noma inhlangano yakho"</string>
+ <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Ukuthatha isithombe-skrini kuvinjwe umlawuli wakho we-IT"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Hlela"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Hlela isithombe-skrini"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"Yabelana ngesithombe-skrini"</string>
@@ -225,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Ukuphenduka okuzenzakalelayo"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Phendula iskrini ngokuzenzakalela"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Indawo"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Isilondolozi sesikrini"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Ukufinyelela kwekhamera"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Ukufinyelela kwe-mic"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Iyatholakala"</string>
@@ -318,6 +320,10 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Vula ngobuso. Cindezela ukuze uvule."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Ubuso buyaziwa. Cindezela ukuze uvule."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Ubuso buyaziwa. Cindezela isithonjana sokuvula ukuze uvule."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"Swayiphela phezulu ukuze uzame futhi"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Vula ukuze usebenzise i-NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Le divayisi eyenhlangano yakho"</string>
@@ -467,7 +473,7 @@
<string name="wallet_title" msgid="5369767670735827105">"I-wallet"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"Lungela ukuthenga ngokushesha, ngokuphepha ngefoni yakho"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"Bonisa konke"</string>
- <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"Engeza ikhadi"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"Thepha ukuze uvule"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"Iyabuyekeza"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Vula ukuze usebenzise"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Kube khona inkinga yokuthola amakhadi akho, sicela uzame futhi ngemuva kwesikhathi"</string>
@@ -693,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Izexwayiso"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Ibhethri"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Izithombe-skrini"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Imilayezo ejwayelekile"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"Isitoreji"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Ukubonisa"</string>
<string name="instant_apps" msgid="8337185853050247304">"Izinhlelo zokusebenza ezisheshayo"</string>
@@ -727,6 +736,7 @@
<string name="auto_saver_text" msgid="3214960308353838764">"Vula uma ibhethri sekungenzeka liphele"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"Cha ngiyabonga"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"I-Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"Kuyasebenza"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Izinhlelo zokusebenza zisebenzisa i-<xliff:g id="TYPES_LIST">%s</xliff:g> yakho."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" kanye "</string>
@@ -824,7 +834,6 @@
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Sondeza eduze ukudlala ku-<xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Sondela eduze ne-<xliff:g id="DEVICENAME">%1$s</xliff:g> ukuze udlale lapha"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Idlala ku-<xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Okudlala kule foni"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Kukhona okungahambanga kahle. Zama futhi."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Akusebenzi, hlola uhlelo lokusebenza"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Ayitholakali"</string>
@@ -853,6 +862,8 @@
<string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"Londoloza"</string>
<string name="media_output_broadcast_starting" msgid="8130153654166235557">"Iyaqala…"</string>
<string name="media_output_broadcast_start_failed" msgid="3670835946856129775">"Ayikwazi ukusakaza"</string>
+ <string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Ayikwazi ukulondoloza. Zama futhi."</string>
+ <string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Ayikwazi ukulondoloza."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Yakha inombolo"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Yakha inombolo ekopishelwe kubhodi yokunamathisela."</string>
<string name="basic_status" msgid="2315371112182658176">"Vula ingxoxo"</string>
@@ -937,6 +948,10 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Hlela umbhalo okopishiwe"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Hlela umfanekiso okopishiwe"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Thumela kudivayisi eseduze"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"Thepha ukuze ubuke"</string>
+ <string name="clipboard_text_copied" msgid="5100836834278976679">"Umbhalo ukopishiwe"</string>
+ <string name="clipboard_image_copied" msgid="3793365360174328722">"Umfanekiso ukopishiwe"</string>
+ <string name="clipboard_content_copied" msgid="144452398567828145">"Okuqukethwe kukopishiwe"</string>
<string name="add" msgid="81036585205287996">"Faka"</string>
<string name="manage_users" msgid="1823875311934643849">"Phatha abasebenzisi"</string>
<string name="drag_split_not_supported" msgid="4326847447699729722">"Lesi saziso asikusekeli ukuhudulela ku-Splitscreen."</string>
@@ -945,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"I-alamu isethiwe"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Ikhamera nemakrofoni kuvaliwe"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{Isaziso esingu-#}one{Izaziso ezingu-#}other{Izaziso ezingu-#}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Ukusakaza"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Misa ukusakaza i-<xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Uma usakaza i-<xliff:g id="SWITCHAPP">%1$s</xliff:g> noma ushintsha okuphumayo, ukusakaza kwakho kwamanje kuzoma"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Sakaza i-<xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Shintsha okuphumayo"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Akwaziwa"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zu/tiles_states_strings.xml b/packages/SystemUI/res/values-zu/tiles_states_strings.xml
index cc8bbb0..81c4636 100644
--- a/packages/SystemUI/res/values-zu/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-zu/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Valiwe"</item>
<item msgid="460891964396502657">"Vuliwe"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Ayitholakali"</item>
+ <item msgid="8014986104355098744">"Valiwe"</item>
+ <item msgid="5966994759929723339">"Vuliwe"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values/defaults.xml b/packages/SystemUI/res/values/defaults.xml
deleted file mode 100644
index f96c178..0000000
--- a/packages/SystemUI/res/values/defaults.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/**
- * Copyright (c) 2009, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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>
- <!-- Default for SystemUiDeviceConfigFlags.DEFAULT_QR_CODE_SCANNER.
- To be set if the device wants to support out of the box QR code scanning experience -->
- <string name="def_qr_code_component" translatable="false"></string>
-</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 207879c..5956ca9 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -30,10 +30,10 @@
<dimen name="navigation_bar_deadzone_size_max">32dp</dimen>
<!-- dimensions for the navigation bar handle -->
- <dimen name="navigation_handle_radius">1dp</dimen>
- <dimen name="navigation_handle_bottom">6dp</dimen>
+ <dimen name="navigation_handle_radius">2dp</dimen>
+ <dimen name="navigation_handle_bottom">8dp</dimen>
<dimen name="navigation_handle_sample_horizontal_margin">10dp</dimen>
- <dimen name="navigation_home_handle_width">72dp</dimen>
+ <dimen name="navigation_home_handle_width">108dp</dimen>
<!-- Size of the nav bar edge panels, should be greater to the
edge sensitivity + the drag threshold -->
@@ -1461,4 +1461,18 @@
<dimen name="media_output_broadcast_info_title_height">24dp</dimen>
<dimen name="media_output_broadcast_info_summary_height">20dp</dimen>
<dimen name="media_output_broadcast_info_edit">18dp</dimen>
+
+ <!-- Broadcast dialog -->
+ <dimen name="broadcast_dialog_title_img_margin_top">18dp</dimen>
+ <dimen name="broadcast_dialog_title_text_size">24sp</dimen>
+ <dimen name="broadcast_dialog_title_text_margin">16dp</dimen>
+ <dimen name="broadcast_dialog_title_text_margin_top">18dp</dimen>
+ <dimen name="broadcast_dialog_subtitle_text_size">14sp</dimen>
+ <dimen name="broadcast_dialog_icon_size">24dp</dimen>
+ <dimen name="broadcast_dialog_icon_margin_top">25dp</dimen>
+ <dimen name="broadcast_dialog_btn_radius">100dp</dimen>
+ <dimen name="broadcast_dialog_btn_margin_bottom">4dp</dimen>
+ <dimen name="broadcast_dialog_btn_text_size">16sp</dimen>
+ <dimen name="broadcast_dialog_btn_minHeight">44dp</dimen>
+ <dimen name="broadcast_dialog_margin">16dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 770d8fd..6893c9b 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -819,6 +819,14 @@
<string name="keyguard_face_successful_unlock_press_alt_3">Face recognized. Press the unlock icon to open.</string>
+ <!-- Messages shown when users press outside of udfps region during -->
+ <string-array name="udfps_accessibility_touch_hints">
+ <item>Move left</item>
+ <item>Move down</item>
+ <item>Move right</item>
+ <item>Move up</item>
+ </string-array>
+
<!-- Message shown when face authentication fails and the pin pad is visible. [CHAR LIMIT=60] -->
<string name="keyguard_retry">Swipe up to try again</string>
@@ -1901,8 +1909,10 @@
<string name="notification_channel_battery">Battery</string>
<!-- Title for the notification channel dedicated to screenshot progress. [CHAR LIMIT=NONE] -->
<string name="notification_channel_screenshot">Screenshots</string>
- <!-- Title for the notification channel for miscellaneous notices. [CHAR LIMIT=NONE] -->
- <string name="notification_channel_general">General Messages</string>
+ <!-- Title for the notification channel for instant app notices. [CHAR LIMIT=NONE] -->
+ <string name="notification_channel_instant">Instant Apps</string>
+ <!-- Title for the notification channel for setup notices. [CHAR LIMIT=NONE] -->
+ <string name="notification_channel_setup">Setup</string>
<!-- Title for the notification channel for problems with storage (i.e. low disk). [CHAR LIMIT=NONE] -->
<string name="notification_channel_storage">Storage</string>
<!-- Title for the notification channel for hints and suggestions. [CHAR LIMIT=NONE] -->
@@ -2508,6 +2518,12 @@
<string name="clipboard_send_nearby_description">Send to nearby device</string>
<!-- Text informing user that copied content is hidden [CHAR LIMIT=NONE] -->
<string name="clipboard_text_hidden">Tap to view</string>
+ <!-- Accessibility announcement informing user that text has been copied [CHAR LIMIT=NONE] -->
+ <string name="clipboard_text_copied">Text copied</string>
+ <!-- Accessibility announcement informing user that text has been copied [CHAR LIMIT=NONE] -->
+ <string name="clipboard_image_copied">Image copied</string>
+ <!-- Accessibility announcement informing user that something has been copied [CHAR LIMIT=NONE] -->
+ <string name="clipboard_content_copied">Content copied</string>
<!-- Generic "add" string [CHAR LIMIT=NONE] -->
<string name="add">Add</string>
@@ -2532,4 +2548,18 @@
=1 {# notification}
other {# notifications}
}</string>
+
+ <!-- [CHAR LIMIT=NONE] Le audio broadcast dialog, media app is broadcasting -->
+ <string name="broadcasting_description_is_broadcasting">Broadcasting</string>
+ <!-- [CHAR LIMIT=NONE] Le audio broadcast dialog, title -->
+ <string name="bt_le_audio_broadcast_dialog_title">Stop broadcasting <xliff:g id="app_name" example="App Name 1">%1$s</xliff:g>?</string>
+ <!-- [CHAR LIMIT=NONE] Le audio broadcast dialog, sub-title -->
+ <string name="bt_le_audio_broadcast_dialog_sub_title">If you broadcast <xliff:g id="switchApp" example="App Name 2">%1$s</xliff:g> or change the output, your current broadcast will stop</string>
+ <!-- [CHAR LIMIT=NONE] Le audio broadcast dialog, switch to others app. -->
+ <string name="bt_le_audio_broadcast_dialog_switch_app">Broadcast <xliff:g id="switchApp" example="App Name 2">%1$s</xliff:g></string>
+ <!-- [CHAR LIMIT=NONE] Le audio broadcast dialog, different output. -->
+ <string name="bt_le_audio_broadcast_dialog_different_output">Change output</string>
+ <!-- [CHAR LIMIT=NONE] Le audio broadcast dialog, media app is unknown -->
+ <string name="bt_le_audio_broadcast_dialog_unknown_name">Unknown</string>
+
</resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index b17e952..4ca6e3a 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -1196,4 +1196,48 @@
<item name="android:shadowColor">@color/keyguard_shadow_color</item>
<item name="android:shadowRadius">?attr/shadowRadius</item>
</style>
+
+ <style name="BroadcastDialogTitleStyle">
+ <item name="android:textAppearance">@style/TextAppearanceBroadcastDialogTitle</item>
+ <item name="android:layout_marginStart">@dimen/broadcast_dialog_title_text_margin</item>
+ <item name="android:layout_marginEnd">@dimen/broadcast_dialog_title_text_margin</item>
+ <item name="android:layout_marginTop">@dimen/broadcast_dialog_title_text_margin_top</item>
+ <item name="android:layout_marginBottom">18dp</item>
+ </style>
+
+ <style name="TextAppearanceBroadcastDialogTitle" parent="@android:style/TextAppearance.DeviceDefault.Headline">
+ <item name="android:textSize">@dimen/broadcast_dialog_title_text_size</item>
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
+ <item name="android:textDirection">locale</item>
+ <item name="android:ellipsize">end</item>
+ </style>
+
+ <style name="BroadcastDialogBodyStyle">
+ <item name="android:textAppearance">@style/TextAppearanceBroadcastDialogSubTitle</item>
+ <item name="android:layout_margin">@dimen/broadcast_dialog_title_text_margin</item>
+ </style>
+
+ <style name="TextAppearanceBroadcastDialogSubTitle" parent="@android:style/TextAppearance.DeviceDefault.Headline">
+ <item name="android:textSize">@dimen/broadcast_dialog_subtitle_text_size</item>
+ <item name="android:textColor">?android:attr/textColorSecondary</item>
+ <item name="android:textDirection">locale</item>
+ <item name="android:ellipsize">end</item>
+ </style>
+
+ <style name="BroadcastDialogButtonStyle">
+ <item name="android:textAppearance">@style/TextAppearanceBroadcastDialogButton</item>
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_gravity">center</item>
+ <item name="android:gravity">center</item>
+ <item name="android:stateListAnimator">@null</item>
+ <item name="android:elevation">0dp</item>
+ <item name="android:minHeight">@dimen/broadcast_dialog_btn_minHeight</item>
+ <item name="android:background">@drawable/broadcast_dialog_btn_bg</item>
+ </style>
+
+ <style name="TextAppearanceBroadcastDialogButton" parent="@android:style/TextAppearance.DeviceDefault.Headline">
+ <item name="android:textColor">?androidprv:attr/textColorOnAccent</item>
+ <item name="android:textSize">@dimen/broadcast_dialog_btn_text_size</item>
+ </style>
</resources>
diff --git a/packages/SystemUI/shared/Android.bp b/packages/SystemUI/shared/Android.bp
index 3cf5bc1..9f790c6 100644
--- a/packages/SystemUI/shared/Android.bp
+++ b/packages/SystemUI/shared/Android.bp
@@ -47,6 +47,7 @@
],
static_libs: [
"PluginCoreLib",
+ "SystemUIUnfoldLib",
"androidx.dynamicanimation_dynamicanimation",
"androidx.concurrent_concurrent-futures",
"dagger2",
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java
index 675dc9b5..e9c1acb 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java
@@ -243,7 +243,7 @@
return new Task(taskKey,
td != null ? td.getPrimaryColor() : 0,
td != null ? td.getBackgroundColor() : 0,
- taskInfo.supportsSplitScreenMultiWindow, isLocked, td, taskInfo.topActivity);
+ taskInfo.supportsMultiWindow, isLocked, td, taskInfo.topActivity);
}
public Task(TaskKey key) {
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java
index f65d82a..acd4222 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java
@@ -61,7 +61,7 @@
onActivityLaunchOnSecondaryDisplayRerouted();
}
- default void onTaskProfileLocked(int taskId, int userId) { }
+ default void onTaskProfileLocked(RunningTaskInfo taskInfo) { }
default void onTaskCreated(int taskId, ComponentName componentName) { }
default void onTaskRemoved(int taskId) { }
default void onTaskMovedToFront(int taskId) { }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
index b5019b4..2fd5aae 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
@@ -211,8 +211,8 @@
}
@Override
- public void onTaskProfileLocked(int taskId, int userId) {
- mHandler.obtainMessage(ON_TASK_PROFILE_LOCKED, taskId, userId).sendToTarget();
+ public void onTaskProfileLocked(RunningTaskInfo taskInfo) {
+ mHandler.obtainMessage(ON_TASK_PROFILE_LOCKED, taskInfo).sendToTarget();
}
@Override
@@ -357,8 +357,9 @@
break;
}
case ON_TASK_PROFILE_LOCKED: {
+ final RunningTaskInfo info = (RunningTaskInfo) msg.obj;
for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
- mTaskStackListeners.get(i).onTaskProfileLocked(msg.arg1, msg.arg2);
+ mTaskStackListeners.get(i).onTaskProfileLocked(info);
}
break;
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/config/ResourceUnfoldTransitionConfig.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/config/ResourceUnfoldTransitionConfig.kt
deleted file mode 100644
index d1b0639..0000000
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/config/ResourceUnfoldTransitionConfig.kt
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.systemui.unfold.config
-
-import android.content.Context
-import android.os.SystemProperties
-
-internal class ResourceUnfoldTransitionConfig(private val context: Context) :
- UnfoldTransitionConfig {
-
- override val isEnabled: Boolean
- get() = readIsEnabledResource() && isPropertyEnabled
-
- override val isHingeAngleEnabled: Boolean
- get() = readIsHingeAngleEnabled()
-
- private val isPropertyEnabled: Boolean
- get() =
- SystemProperties.getInt(
- UNFOLD_TRANSITION_MODE_PROPERTY_NAME, UNFOLD_TRANSITION_PROPERTY_ENABLED) ==
- UNFOLD_TRANSITION_PROPERTY_ENABLED
-
- private fun readIsEnabledResource(): Boolean =
- context.resources.getBoolean(com.android.internal.R.bool.config_unfoldTransitionEnabled)
-
- private fun readIsHingeAngleEnabled(): Boolean =
- context.resources.getBoolean(com.android.internal.R.bool.config_unfoldTransitionHingeAngle)
-}
-
-/**
- * Temporary persistent property to control unfold transition mode.
- *
- * See [com.android.unfold.config.AnimationMode].
- */
-private const val UNFOLD_TRANSITION_MODE_PROPERTY_NAME = "persist.unfold.transition_enabled"
-private const val UNFOLD_TRANSITION_PROPERTY_ENABLED = 1
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/system/ActivityManagerActivityTypeProvider.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/system/ActivityManagerActivityTypeProvider.kt
new file mode 100644
index 0000000..7f2933e
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/system/ActivityManagerActivityTypeProvider.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.unfold.system
+
+import android.app.ActivityManager
+import android.app.WindowConfiguration
+import com.android.systemui.unfold.util.CurrentActivityTypeProvider
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class ActivityManagerActivityTypeProvider @Inject constructor(
+ private val activityManager: ActivityManager
+) : CurrentActivityTypeProvider {
+
+ override val isHomeActivity: Boolean?
+ get() {
+ val activityType = activityManager.getRunningTasks(/* maxNum= */ 1)
+ ?.getOrNull(0)?.topActivityType ?: return null
+
+ return activityType == WindowConfiguration.ACTIVITY_TYPE_HOME
+ }
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/system/DeviceStateManagerFoldProvider.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/system/DeviceStateManagerFoldProvider.kt
new file mode 100644
index 0000000..3b8d318
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/system/DeviceStateManagerFoldProvider.kt
@@ -0,0 +1,51 @@
+/*
+ * 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.unfold.system
+
+import android.content.Context
+import android.hardware.devicestate.DeviceStateManager
+import com.android.systemui.unfold.updates.FoldProvider
+import com.android.systemui.unfold.updates.FoldProvider.FoldCallback
+import java.util.concurrent.Executor
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class DeviceStateManagerFoldProvider @Inject constructor(
+ private val deviceStateManager: DeviceStateManager,
+ private val context: Context
+) : FoldProvider {
+
+ private val callbacks: MutableMap<FoldCallback,
+ DeviceStateManager.DeviceStateCallback> = hashMapOf()
+
+ override fun registerCallback(callback: FoldCallback, executor: Executor) {
+ val listener = FoldStateListener(context, callback)
+ deviceStateManager.registerCallback(executor, listener)
+ callbacks[callback] = listener
+ }
+
+ override fun unregisterCallback(callback: FoldCallback) {
+ val listener = callbacks.remove(callback)
+ listener?.let {
+ deviceStateManager.unregisterCallback(it)
+ }
+ }
+
+ private inner class FoldStateListener(
+ context: Context,
+ listener: FoldCallback
+ ) : DeviceStateManager.FoldStateListener(context, { listener.onFoldUpdated(it) })
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/system/SystemUnfoldSharedModule.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/system/SystemUnfoldSharedModule.kt
new file mode 100644
index 0000000..24ae42a
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/system/SystemUnfoldSharedModule.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.systemui.unfold.system
+
+import android.os.Handler
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.dagger.qualifiers.UiBackground
+import com.android.systemui.unfold.config.ResourceUnfoldTransitionConfig
+import com.android.systemui.unfold.config.UnfoldTransitionConfig
+import com.android.systemui.unfold.dagger.UnfoldBackground
+import com.android.systemui.unfold.dagger.UnfoldMain
+import com.android.systemui.unfold.updates.FoldProvider
+import com.android.systemui.unfold.util.CurrentActivityTypeProvider
+import dagger.Binds
+import dagger.Module
+import java.util.concurrent.Executor
+
+/**
+ * Dagger module with system-only dependencies for the unfold animation.
+ * The code that is used to calculate unfold transition progress
+ * depends on some hidden APIs that are not available in normal
+ * apps. In order to re-use this code and use alternative implementations
+ * of these classes in other apps and hidden APIs here.
+ */
+@Module
+abstract class SystemUnfoldSharedModule {
+
+ @Binds
+ abstract fun activityTypeProvider(executor: ActivityManagerActivityTypeProvider):
+ CurrentActivityTypeProvider
+
+ @Binds
+ abstract fun config(config: ResourceUnfoldTransitionConfig): UnfoldTransitionConfig
+
+ @Binds
+ abstract fun foldState(provider: DeviceStateManagerFoldProvider): FoldProvider
+
+ @Binds
+ @UnfoldMain
+ abstract fun mainExecutor(@Main executor: Executor): Executor
+
+ @Binds
+ @UnfoldMain
+ abstract fun mainHandler(@Main handler: Handler): Handler
+
+ @Binds
+ @UnfoldBackground
+ abstract fun backgroundExecutor(@UiBackground executor: Executor): Executor
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/hinge/EmptyHingeAngleProvider.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/hinge/EmptyHingeAngleProvider.kt
deleted file mode 100644
index b351585..0000000
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/hinge/EmptyHingeAngleProvider.kt
+++ /dev/null
@@ -1,13 +0,0 @@
-package com.android.systemui.unfold.updates.hinge
-
-import androidx.core.util.Consumer
-
-internal object EmptyHingeAngleProvider : HingeAngleProvider {
- override fun start() {}
-
- override fun stop() {}
-
- override fun removeCallback(listener: Consumer<Float>) {}
-
- override fun addCallback(listener: Consumer<Float>) {}
-}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/hinge/HingeAngleProvider.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/hinge/HingeAngleProvider.kt
deleted file mode 100644
index 48a5b12..0000000
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/hinge/HingeAngleProvider.kt
+++ /dev/null
@@ -1,19 +0,0 @@
-package com.android.systemui.unfold.updates.hinge
-
-import androidx.core.util.Consumer
-import com.android.systemui.statusbar.policy.CallbackController
-
-/**
- * Emits device hinge angle values (angle between two integral parts of the device).
- *
- * The hinge angle could be from 0 to 360 degrees inclusive. For foldable devices usually 0
- * corresponds to fully closed (folded) state and 180 degrees corresponds to fully open (flat)
- * state.
- */
-interface HingeAngleProvider : CallbackController<Consumer<Float>> {
- fun start()
- fun stop()
-}
-
-const val FULLY_OPEN_DEGREES = 180f
-const val FULLY_CLOSED_DEGREES = 0f
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/util/NaturalRotationUnfoldProgressProvider.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/util/NaturalRotationUnfoldProgressProvider.kt
index 53c528f..ec938b2 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/util/NaturalRotationUnfoldProgressProvider.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/util/NaturalRotationUnfoldProgressProvider.kt
@@ -1,3 +1,17 @@
+/*
+ * 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.unfold.util
import android.content.Context
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java
index 804d146..12fa401 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java
@@ -71,13 +71,16 @@
public void onTrustGrantedWithFlags(int flags, int userId) {
if (userId != KeyguardUpdateMonitor.getCurrentUser()) return;
boolean bouncerVisible = mView.isVisibleToUser();
+ boolean temporaryAndRenewable =
+ (flags & TrustAgentService.FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE)
+ != 0;
boolean initiatedByUser =
(flags & TrustAgentService.FLAG_GRANT_TRUST_INITIATED_BY_USER) != 0;
boolean dismissKeyguard =
(flags & TrustAgentService.FLAG_GRANT_TRUST_DISMISS_KEYGUARD) != 0;
if (initiatedByUser || dismissKeyguard) {
- if (mViewMediatorCallback.isScreenOn()
+ if ((mViewMediatorCallback.isScreenOn() || temporaryAndRenewable)
&& (bouncerVisible || dismissKeyguard)) {
if (!bouncerVisible) {
// The trust agent dismissed the keyguard without the user proving
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
index 5c9f5db..2cc5ccdc 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
@@ -32,6 +32,7 @@
import android.content.Context;
import android.graphics.Insets;
import android.graphics.Rect;
+import android.os.Trace;
import android.util.AttributeSet;
import android.view.WindowInsetsAnimationControlListener;
import android.view.WindowInsetsAnimationController;
@@ -44,6 +45,7 @@
import com.android.internal.widget.LockscreenCredential;
import com.android.internal.widget.TextViewInputDisabler;
+import com.android.systemui.DejankUtils;
import com.android.systemui.R;
import com.android.systemui.animation.Interpolators;
/**
@@ -194,9 +196,17 @@
@Override
public void onAnimationEnd(Animator animation) {
- controller.finish(false);
- runOnFinishImeAnimationRunnable();
- finishRunnable.run();
+ // Run this in the next frame since it results in a slow binder call
+ // to InputMethodManager#hideSoftInput()
+ DejankUtils.postAfterTraversal(() -> {
+ Trace.beginSection("KeyguardPasswordView#onAnimationEnd");
+ // // TODO(b/230620476): Make hideSoftInput oneway
+ // controller.finish() eventually calls hideSoftInput
+ controller.finish(false);
+ runOnFinishImeAnimationRunnable();
+ finishRunnable.run();
+ Trace.endSection();
+ });
}
});
anim.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index f8c0590..cce516d 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -15,6 +15,8 @@
*/
package com.android.keyguard;
+import static android.app.admin.DevicePolicyResources.Strings.SystemUi.KEYGUARD_DIALOG_FAILED_ATTEMPTS_ALMOST_ERASING_PROFILE;
+import static android.app.admin.DevicePolicyResources.Strings.SystemUi.KEYGUARD_DIALOG_FAILED_ATTEMPTS_ERASING_PROFILE;
import static android.view.WindowInsets.Type.ime;
import static android.view.WindowInsets.Type.systemBars;
import static android.view.WindowInsetsAnimation.Callback.DISPATCH_MODE_STOP;
@@ -32,6 +34,7 @@
import android.animation.ValueAnimator;
import android.app.Activity;
import android.app.AlertDialog;
+import android.app.admin.DevicePolicyManager;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -676,7 +679,11 @@
attempts, remaining);
break;
case USER_TYPE_WORK_PROFILE:
- message = mContext.getString(R.string.kg_failed_attempts_almost_at_erase_profile,
+ message = mContext.getSystemService(DevicePolicyManager.class).getResources()
+ .getString(KEYGUARD_DIALOG_FAILED_ATTEMPTS_ALMOST_ERASING_PROFILE,
+ () -> mContext.getString(
+ R.string.kg_failed_attempts_almost_at_erase_profile,
+ attempts, remaining),
attempts, remaining);
break;
}
@@ -695,7 +702,10 @@
attempts);
break;
case USER_TYPE_WORK_PROFILE:
- message = mContext.getString(R.string.kg_failed_attempts_now_erasing_profile,
+ message = mContext.getSystemService(DevicePolicyManager.class).getResources()
+ .getString(KEYGUARD_DIALOG_FAILED_ATTEMPTS_ERASING_PROFILE,
+ () -> mContext.getString(
+ R.string.kg_failed_attempts_now_erasing_profile, attempts),
attempts);
break;
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 707ea3a..de2eb7e 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -187,6 +187,7 @@
private static final int MSG_KEYGUARD_GOING_AWAY = 342;
private static final int MSG_TIME_FORMAT_UPDATE = 344;
private static final int MSG_REQUIRE_NFC_UNLOCK = 345;
+ private static final int MSG_KEYGUARD_DISMISS_ANIMATION_FINISHED = 346;
/** Biometric authentication state: Not listening. */
private static final int BIOMETRIC_STATE_STOPPED = 0;
@@ -2009,6 +2010,9 @@
case MSG_REQUIRE_NFC_UNLOCK:
handleRequireUnlockForNfc();
break;
+ case MSG_KEYGUARD_DISMISS_ANIMATION_FINISHED:
+ handleKeyguardDismissAnimationFinished();
+ break;
default:
super.handleMessage(msg);
break;
@@ -2417,7 +2421,7 @@
// Triggers:
final boolean triggerActiveUnlockForAssistant = shouldTriggerActiveUnlockForAssistant();
final boolean awakeKeyguard = mBouncerFullyShown || mUdfpsBouncerShowing
- || (mKeyguardIsVisible && mDeviceInteractive && !mGoingToSleep
+ || (mKeyguardIsVisible && !mGoingToSleep
&& mStatusBarState != StatusBarState.SHADE_LOCKED);
// Gates:
@@ -2799,7 +2803,7 @@
* Note: checking fingerprint enrollment directly with the AuthController requires an IPC.
*/
public boolean getCachedIsUnlockWithFingerprintPossible(int userId) {
- return mIsUnlockWithFingerprintPossible.get(userId);
+ return mIsUnlockWithFingerprintPossible.getOrDefault(userId, false);
}
private boolean isUnlockWithFacePossible(int userId) {
@@ -3281,6 +3285,19 @@
}
/**
+ * Handle {@link #MSG_KEYGUARD_DISMISS_ANIMATION_FINISHED}
+ */
+ private void handleKeyguardDismissAnimationFinished() {
+ Assert.isMainThread();
+ for (int i = 0; i < mCallbacks.size(); i++) {
+ KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+ if (cb != null) {
+ cb.onKeyguardDismissAnimationFinished();
+ }
+ }
+ }
+
+ /**
* Handle {@link #MSG_REPORT_EMERGENCY_CALL_ACTION}
*/
private void handleReportEmergencyCallAction() {
@@ -3618,6 +3635,13 @@
mHandler.sendMessage(mHandler.obtainMessage(MSG_KEYGUARD_GOING_AWAY, goingAway));
}
+ /**
+ * Sends a message to notify the keyguard dismiss animation is finished.
+ */
+ public void dispatchKeyguardDismissAnimationFinished() {
+ mHandler.sendEmptyMessage(MSG_KEYGUARD_DISMISS_ANIMATION_FINISHED);
+ }
+
public boolean isDeviceInteractive() {
return mDeviceInteractive;
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index 2620195..051b81e 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -109,6 +109,14 @@
public void onKeyguardBouncerFullyShowingChanged(boolean bouncerIsFullyShowing) { }
/**
+ * Called when the dismissing animation of keyguard and surfaces behind is finished.
+ * If the surface behind is the Launcher, we may still be playing in-window animations
+ * when this is called (since it's only called once we dismiss the keyguard and end the
+ * remote animation).
+ */
+ public void onKeyguardDismissAnimationFinished() { }
+
+ /**
* Called when visibility of lockscreen clock changes, such as when
* obscured by a widget.
*/
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
index d79b145..680b8bd 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
@@ -123,7 +123,7 @@
private float mHeightPixels;
private float mWidthPixels;
private int mBottomPaddingPx;
- private int mScaledPaddingPx;
+ private int mDefaultPaddingPx;
private boolean mShowUnlockIcon;
private boolean mShowLockIcon;
@@ -188,7 +188,6 @@
protected void onViewAttached() {
updateIsUdfpsEnrolled();
updateConfiguration();
- updateLockIconLocation();
updateKeyguardShowing();
mUserUnlockedWithBiometric = false;
@@ -340,25 +339,27 @@
mWidthPixels = bounds.right;
mHeightPixels = bounds.bottom;
mBottomPaddingPx = getResources().getDimensionPixelSize(R.dimen.lock_icon_margin_bottom);
+ mDefaultPaddingPx =
+ getResources().getDimensionPixelSize(R.dimen.lock_icon_padding);
mUnlockedLabel = mView.getContext().getResources().getString(
R.string.accessibility_unlock_button);
mLockedLabel = mView.getContext()
.getResources().getString(R.string.accessibility_lock_icon);
+ updateLockIconLocation();
}
private void updateLockIconLocation() {
+ final float scaleFactor = mAuthController.getScaleFactor();
+ final int scaledPadding = (int) (mDefaultPaddingPx * scaleFactor);
if (mUdfpsSupported) {
- final int defaultPaddingPx =
- getResources().getDimensionPixelSize(R.dimen.lock_icon_padding);
- mScaledPaddingPx = (int) (defaultPaddingPx * mAuthController.getScaleFactor());
mView.setCenterLocation(mAuthController.getUdfpsLocation(),
- mAuthController.getUdfpsRadius(), mScaledPaddingPx);
+ mAuthController.getUdfpsRadius(), scaledPadding);
} else {
mView.setCenterLocation(
new PointF(mWidthPixels / 2,
- mHeightPixels - mBottomPaddingPx - sLockIconRadiusPx),
- sLockIconRadiusPx, mScaledPaddingPx);
+ mHeightPixels - ((mBottomPaddingPx + sLockIconRadiusPx) * scaleFactor)),
+ sLockIconRadiusPx * scaleFactor, scaledPadding);
}
}
@@ -690,7 +691,6 @@
mExecutor.execute(() -> {
updateIsUdfpsEnrolled();
updateConfiguration();
- updateLockIconLocation();
});
}
@@ -707,7 +707,7 @@
@Override
public void onUdfpsLocationChanged() {
- updateLockIconLocation();
+ updateUdfpsConfig();
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/DisplayCutoutBaseView.kt b/packages/SystemUI/src/com/android/systemui/DisplayCutoutBaseView.kt
index e51a63f..032a27a 100644
--- a/packages/SystemUI/src/com/android/systemui/DisplayCutoutBaseView.kt
+++ b/packages/SystemUI/src/com/android/systemui/DisplayCutoutBaseView.kt
@@ -54,7 +54,7 @@
@VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
@JvmField val displayInfo = DisplayInfo()
- @JvmField protected var pendingRotationChange = false
+ @JvmField protected var pendingConfigChange = false
@JvmField protected val paint = Paint()
@JvmField protected val cutoutPath = Path()
@@ -145,7 +145,7 @@
@VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
open fun updateCutout() {
- if (pendingRotationChange) {
+ if (pendingConfigChange) {
return
}
cutoutPath.reset()
@@ -225,7 +225,7 @@
}
protected open fun updateProtectionBoundingPath() {
- if (pendingRotationChange) {
+ if (pendingConfigChange) {
return
}
val m = Matrix()
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index dd31218..685c585 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -53,6 +53,7 @@
import android.util.DisplayUtils;
import android.util.Log;
import android.util.Size;
+import android.view.Display;
import android.view.DisplayCutout;
import android.view.DisplayCutout.BoundsPosition;
import android.view.DisplayInfo;
@@ -151,12 +152,13 @@
private SettingObserver mColorInversionSetting;
private DelayableExecutor mExecutor;
private Handler mHandler;
- boolean mPendingRotationChange;
+ boolean mPendingConfigChange;
@VisibleForTesting
String mDisplayUniqueId;
private int mTintColor = Color.BLACK;
@VisibleForTesting
protected DisplayDecorationSupport mHwcScreenDecorationSupport;
+ private Display.Mode mDisplayMode;
private CameraAvailabilityListener.CameraTransitionCallback mCameraTransitionCallback =
new CameraAvailabilityListener.CameraTransitionCallback() {
@@ -324,6 +326,7 @@
mWindowManager = mContext.getSystemService(WindowManager.class);
mDisplayManager = mContext.getSystemService(DisplayManager.class);
mRotation = mContext.getDisplay().getRotation();
+ mDisplayMode = mContext.getDisplay().getMode();
mDisplayUniqueId = mContext.getDisplay().getUniqueId();
mRoundedCornerResDelegate = new RoundedCornerResDelegate(mContext.getResources(),
mDisplayUniqueId);
@@ -349,8 +352,10 @@
@Override
public void onDisplayChanged(int displayId) {
final int newRotation = mContext.getDisplay().getRotation();
+ final Display.Mode newDisplayMode = mContext.getDisplay().getMode();
if ((mOverlays != null || mScreenDecorHwcWindow != null)
- && mRotation != newRotation) {
+ && (mRotation != newRotation
+ || displayModeChanged(mDisplayMode, newDisplayMode))) {
// We cannot immediately update the orientation. Otherwise
// WindowManager is still deferring layout until it has finished dispatching
// the config changes, which may cause divergence between what we draw
@@ -358,10 +363,16 @@
// Instead we wait until either:
// - we are trying to redraw. This because WM resized our window and told us to.
// - the config change has been dispatched, so WM is no longer deferring layout.
- mPendingRotationChange = true;
+ mPendingConfigChange = true;
if (DEBUG) {
- Log.i(TAG, "Rotation changed, deferring " + newRotation + ", staying at "
- + mRotation);
+ if (mRotation != newRotation) {
+ Log.i(TAG, "Rotation changed, deferring " + newRotation
+ + ", staying at " + mRotation);
+ }
+ if (displayModeChanged(mDisplayMode, newDisplayMode)) {
+ Log.i(TAG, "Resolution changed, deferring " + newDisplayMode
+ + ", staying at " + mDisplayMode);
+ }
}
if (mOverlays != null) {
@@ -369,7 +380,8 @@
if (mOverlays[i] != null) {
final ViewGroup overlayView = mOverlays[i].getRootView();
overlayView.getViewTreeObserver().addOnPreDrawListener(
- new RestartingPreDrawListener(overlayView, i, newRotation));
+ new RestartingPreDrawListener(
+ overlayView, i, newRotation, newDisplayMode));
}
}
}
@@ -379,7 +391,10 @@
new RestartingPreDrawListener(
mScreenDecorHwcWindow,
-1, // Pass -1 for views with no specific position.
- newRotation));
+ newRotation, newDisplayMode));
+ }
+ if (mScreenDecorHwcLayer != null) {
+ mScreenDecorHwcLayer.pendingConfigChange = true;
}
}
@@ -435,7 +450,7 @@
};
mDisplayManager.registerDisplayListener(mDisplayListener, mHandler);
- updateOrientation();
+ updateConfiguration();
}
@Nullable
@@ -807,6 +822,17 @@
}
}
+ private static boolean displayModeChanged(Display.Mode oldMode, Display.Mode newMode) {
+ if (oldMode == null) {
+ return true;
+ }
+
+ // We purposely ignore refresh rate and id changes here, because we don't need to
+ // invalidate for those, and they can trigger the refresh rate to increase
+ return oldMode.getPhysicalWidth() != newMode.getPhysicalWidth()
+ || oldMode.getPhysicalHeight() != newMode.getPhysicalHeight();
+ }
+
private int getOverlayWindowGravity(@BoundsPosition int pos) {
final int rotated = getBoundPositionFromRotation(pos, mRotation);
switch (rotated) {
@@ -913,8 +939,8 @@
mExecutor.execute(() -> {
int oldRotation = mRotation;
- mPendingRotationChange = false;
- updateOrientation();
+ mPendingConfigChange = false;
+ updateConfiguration();
if (DEBUG) Log.i(TAG, "onConfigChanged from rot " + oldRotation + " to " + mRotation);
setupDecorations();
if (mOverlays != null) {
@@ -941,7 +967,7 @@
pw.println(" DEBUG_DISABLE_SCREEN_DECORATIONS:" + DEBUG_DISABLE_SCREEN_DECORATIONS);
pw.println(" mIsPrivacyDotEnabled:" + isPrivacyDotEnabled());
pw.println(" isOnlyPrivacyDotInSwLayer:" + isOnlyPrivacyDotInSwLayer());
- pw.println(" mPendingRotationChange:" + mPendingRotationChange);
+ pw.println(" mPendingConfigChange:" + mPendingConfigChange);
if (mHwcScreenDecorationSupport != null) {
pw.println(" mHwcScreenDecorationSupport:");
pw.println(" format="
@@ -957,15 +983,23 @@
} else {
pw.println(" mScreenDecorHwcLayer: null");
}
- pw.println(" mOverlays(left,top,right,bottom)=("
- + (mOverlays != null && mOverlays[BOUNDS_POSITION_LEFT] != null) + ","
- + (mOverlays != null && mOverlays[BOUNDS_POSITION_TOP] != null) + ","
- + (mOverlays != null && mOverlays[BOUNDS_POSITION_RIGHT] != null) + ","
- + (mOverlays != null && mOverlays[BOUNDS_POSITION_BOTTOM] != null) + ")");
+ if (mOverlays != null) {
+ pw.println(" mOverlays(left,top,right,bottom)=("
+ + (mOverlays[BOUNDS_POSITION_LEFT] != null) + ","
+ + (mOverlays[BOUNDS_POSITION_TOP] != null) + ","
+ + (mOverlays[BOUNDS_POSITION_RIGHT] != null) + ","
+ + (mOverlays[BOUNDS_POSITION_BOTTOM] != null) + ")");
+
+ for (int i = BOUNDS_POSITION_LEFT; i < BOUNDS_POSITION_LENGTH; i++) {
+ if (mOverlays[i] != null) {
+ mOverlays[i].dump(pw, getWindowTitleByPos(i));
+ }
+ }
+ }
mRoundedCornerResDelegate.dump(pw, args);
}
- private void updateOrientation() {
+ private void updateConfiguration() {
Preconditions.checkState(mHandler.getLooper().getThread() == Thread.currentThread(),
"must call on " + mHandler.getLooper().getThread()
+ ", but was " + Thread.currentThread());
@@ -974,11 +1008,14 @@
if (mRotation != newRotation) {
mDotViewController.setNewRotation(newRotation);
}
+ final Display.Mode newMod = mContext.getDisplay().getMode();
- if (!mPendingRotationChange && newRotation != mRotation) {
+ if (!mPendingConfigChange
+ && (newRotation != mRotation || displayModeChanged(mDisplayMode, newMod))) {
mRotation = newRotation;
+ mDisplayMode = newMod;
if (mScreenDecorHwcLayer != null) {
- mScreenDecorHwcLayer.pendingRotationChange = false;
+ mScreenDecorHwcLayer.pendingConfigChange = false;
mScreenDecorHwcLayer.updateRotation(mRotation);
updateHwLayerRoundedCornerExistAndSize();
updateHwLayerRoundedCornerDrawable();
@@ -1189,7 +1226,7 @@
@VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
@Override
public void updateCutout() {
- if (!isAttachedToWindow() || pendingRotationChange) {
+ if (!isAttachedToWindow() || pendingConfigChange) {
return;
}
mPosition = getBoundPositionFromRotation(mInitialPosition, mRotation);
@@ -1330,40 +1367,47 @@
private final View mView;
private final int mTargetRotation;
+ private final Display.Mode mTargetDisplayMode;
// Pass -1 for ScreenDecorHwcLayer since it's a fullscreen window and has no specific
// position.
private final int mPosition;
private RestartingPreDrawListener(View view, @BoundsPosition int position,
- int targetRotation) {
+ int targetRotation, Display.Mode targetDisplayMode) {
mView = view;
mTargetRotation = targetRotation;
+ mTargetDisplayMode = targetDisplayMode;
mPosition = position;
}
@Override
public boolean onPreDraw() {
mView.getViewTreeObserver().removeOnPreDrawListener(this);
-
- if (mTargetRotation == mRotation) {
+ if (mTargetRotation == mRotation
+ && !displayModeChanged(mDisplayMode, mTargetDisplayMode)) {
if (DEBUG) {
final String title = mPosition < 0 ? "ScreenDecorHwcLayer"
: getWindowTitleByPos(mPosition);
Log.i(TAG, title + " already in target rot "
- + mTargetRotation + ", allow draw without restarting it");
+ + mTargetRotation + " and in target resolution "
+ + mTargetDisplayMode.getPhysicalWidth() + "x"
+ + mTargetDisplayMode.getPhysicalHeight()
+ + ", allow draw without restarting it");
}
return true;
}
- mPendingRotationChange = false;
+ mPendingConfigChange = false;
// This changes the window attributes - we need to restart the traversal for them to
// take effect.
- updateOrientation();
+ updateConfiguration();
if (DEBUG) {
final String title = mPosition < 0 ? "ScreenDecorHwcLayer"
: getWindowTitleByPos(mPosition);
Log.i(TAG, title
- + " restarting listener fired, restarting draw for rot " + mRotation);
+ + " restarting listener fired, restarting draw for rot " + mRotation
+ + ", resolution " + mDisplayMode.getPhysicalWidth() + "x"
+ + mDisplayMode.getPhysicalHeight());
}
mView.invalidate();
return false;
@@ -1371,8 +1415,8 @@
}
/**
- * A pre-draw listener, that validates that the rotation we draw in matches the displays
- * rotation before continuing the draw.
+ * A pre-draw listener, that validates that the rotation and display resolution we draw in
+ * matches the display's rotation and resolution before continuing the draw.
*
* This is to prevent a race condition, where we have not received the display changed event
* yet, and would thus draw in an old orientation.
@@ -1388,10 +1432,20 @@
@Override
public boolean onPreDraw() {
final int displayRotation = mContext.getDisplay().getRotation();
- if (displayRotation != mRotation && !mPendingRotationChange) {
+ final Display.Mode displayMode = mContext.getDisplay().getMode();
+ if (displayRotation != mRotation && displayModeChanged(mDisplayMode, displayMode)
+ && !mPendingConfigChange) {
if (DEBUG) {
- Log.i(TAG, "Drawing rot " + mRotation + ", but display is at rot "
- + displayRotation + ". Restarting draw");
+ if (displayRotation != mRotation) {
+ Log.i(TAG, "Drawing rot " + mRotation + ", but display is at rot "
+ + displayRotation + ". Restarting draw");
+ }
+ if (displayModeChanged(mDisplayMode, displayMode)) {
+ Log.i(TAG, "Drawing at " + mDisplayMode.getPhysicalWidth()
+ + "x" + mDisplayMode.getPhysicalHeight() + ", but display is at "
+ + displayMode.getPhysicalWidth() + "x"
+ + displayMode.getPhysicalHeight() + ". Restarting draw");
+ }
}
mView.invalidate();
return false;
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index 3d0c08b..fe6dbe5 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -46,6 +46,8 @@
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.wm.shell.animation.FlingAnimationUtils;
+import java.util.function.Consumer;
+
public class SwipeHelper implements Gefingerpoken {
static final String TAG = "com.android.systemui.SwipeHelper";
private static final boolean DEBUG = false;
@@ -399,7 +401,7 @@
* @param useAccelerateInterpolator Should an accelerating Interpolator be used
* @param fixedDuration If not 0, this exact duration will be taken
*/
- public void dismissChild(final View animView, float velocity, final Runnable endAction,
+ public void dismissChild(final View animView, float velocity, final Consumer<Boolean> endAction,
long delay, boolean useAccelerateInterpolator, long fixedDuration,
boolean isDismissAll) {
final boolean canBeDismissed = mCallback.canChildBeDismissed(animView);
@@ -487,7 +489,7 @@
resetSwipeState();
}
if (endAction != null) {
- endAction.run();
+ endAction.accept(mCancelled);
}
if (!mDisableHwLayers) {
animView.setLayerType(View.LAYER_TYPE_NONE, null);
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index f5084f5..2dade21 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -29,9 +29,9 @@
import com.android.systemui.dagger.GlobalRootComponent;
import com.android.systemui.dagger.SysUIComponent;
import com.android.systemui.dagger.WMComponent;
-import com.android.wm.shell.dagger.WMShellConcurrencyModule;
import com.android.systemui.navigationbar.gestural.BackGestureTfClassifierProvider;
import com.android.systemui.screenshot.ScreenshotNotificationSmartActionsProvider;
+import com.android.wm.shell.dagger.WMShellConcurrencyModule;
import com.android.wm.shell.transition.ShellTransitions;
import java.util.Map;
@@ -114,13 +114,11 @@
// components that shouldn't be run in the test environment
builder = prepareSysUIComponentBuilder(builder, mWMComponent)
.setPip(mWMComponent.getPip())
- .setLegacySplitScreen(mWMComponent.getLegacySplitScreen())
.setSplitScreen(mWMComponent.getSplitScreen())
.setOneHanded(mWMComponent.getOneHanded())
.setBubbles(mWMComponent.getBubbles())
.setHideDisplayCutout(mWMComponent.getHideDisplayCutout())
.setShellCommandHandler(mWMComponent.getShellCommandHandler())
- .setAppPairs(mWMComponent.getAppPairs())
.setTaskViewFactory(mWMComponent.getTaskViewFactory())
.setTransitions(mWMComponent.getTransitions())
.setStartingSurface(mWMComponent.getStartingSurface())
@@ -135,13 +133,11 @@
// is separating this logic into newly creating SystemUITestsFactory.
builder = prepareSysUIComponentBuilder(builder, mWMComponent)
.setPip(Optional.ofNullable(null))
- .setLegacySplitScreen(Optional.ofNullable(null))
.setSplitScreen(Optional.ofNullable(null))
.setOneHanded(Optional.ofNullable(null))
.setBubbles(Optional.ofNullable(null))
.setHideDisplayCutout(Optional.ofNullable(null))
.setShellCommandHandler(Optional.ofNullable(null))
- .setAppPairs(Optional.ofNullable(null))
.setTaskViewFactory(Optional.ofNullable(null))
.setTransitions(new ShellTransitions() {})
.setDisplayAreaHelper(Optional.ofNullable(null))
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java b/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java
index bd8e44c..448b99b 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java
@@ -199,8 +199,9 @@
mNotificationShadeController = notificationShadeController;
// Saving in instance variable since to prevent GC since
// NotificationShadeWindowController.registerCallback() only keeps weak references.
- mNotificationShadeCallback = (keyguardShowing, keyguardOccluded, bouncerShowing, mDozing) ->
- registerOrUnregisterDismissNotificationShadeAction();
+ mNotificationShadeCallback =
+ (keyguardShowing, keyguardOccluded, bouncerShowing, mDozing, panelExpanded) ->
+ registerOrUnregisterDismissNotificationShadeAction();
mCentralSurfacesOptionalLazy = centralSurfacesOptionalLazy;
}
diff --git a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
index 56fbe6d..6b85976 100644
--- a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
@@ -102,6 +102,7 @@
AppOpsManager.OP_PHONE_CALL_CAMERA,
AppOpsManager.OP_SYSTEM_ALERT_WINDOW,
AppOpsManager.OP_RECORD_AUDIO,
+ AppOpsManager.OP_RECEIVE_AMBIENT_TRIGGER_AUDIO,
AppOpsManager.OP_PHONE_CALL_MICROPHONE,
AppOpsManager.OP_COARSE_LOCATION,
AppOpsManager.OP_FINE_LOCATION
@@ -375,7 +376,7 @@
Log.w(TAG, String.format("onActiveChanged(%d,%d,%s,%s,%d,%d)", code, uid, packageName,
Boolean.toString(active), attributionChainId, attributionFlags));
}
- if (attributionChainId != AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE
+ if (active && attributionChainId != AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE
&& attributionFlags != AppOpsManager.ATTRIBUTION_FLAGS_NONE
&& (attributionFlags & AppOpsManager.ATTRIBUTION_FLAG_ACCESSOR) == 0
&& (attributionFlags & AppOpsManager.ATTRIBUTION_FLAG_TRUSTED) == 0) {
@@ -535,7 +536,8 @@
}
private boolean isOpMicrophone(int op) {
- return op == AppOpsManager.OP_RECORD_AUDIO || op == AppOpsManager.OP_PHONE_CALL_MICROPHONE;
+ return op == AppOpsManager.OP_RECORD_AUDIO || op == AppOpsManager.OP_PHONE_CALL_MICROPHONE
+ || op == AppOpsManager.OP_RECEIVE_AMBIENT_TRIGGER_AUDIO;
}
protected class H extends Handler {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintView.kt
index 368bc3a..ebed296 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintView.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintView.kt
@@ -22,6 +22,7 @@
import android.widget.FrameLayout
import android.widget.TextView
import com.android.systemui.R
+import com.android.systemui.biometrics.AuthController.ScaleFactorProvider
private const val TAG = "AuthBiometricFingerprintView"
@@ -35,6 +36,7 @@
private set
private var udfpsAdapter: UdfpsDialogMeasureAdapter? = null
+ private var scaleFactorProvider: ScaleFactorProvider? = null
/** Set the [sensorProps] of this sensor so the view can be customized prior to layout. */
fun setSensorProperties(sensorProps: FingerprintSensorPropertiesInternal) {
@@ -42,9 +44,15 @@
udfpsAdapter = if (isUdfps) UdfpsDialogMeasureAdapter(this, sensorProps) else null
}
+ fun setScaleFactorProvider(scaleProvider: ScaleFactorProvider?) {
+ scaleFactorProvider = scaleProvider
+ }
+
override fun onMeasureInternal(width: Int, height: Int): AuthDialog.LayoutParams {
val layoutParams = super.onMeasureInternal(width, height)
- return udfpsAdapter?.onMeasureInternal(width, height, layoutParams) ?: layoutParams
+ val scale = scaleFactorProvider?.provide() ?: 1.0f
+ return udfpsAdapter?.onMeasureInternal(width, height, layoutParams,
+ scale) ?: layoutParams
}
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
index 233f364..3c2de89 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
@@ -56,6 +56,7 @@
import com.android.internal.widget.LockPatternUtils;
import com.android.systemui.R;
import com.android.systemui.animation.Interpolators;
+import com.android.systemui.biometrics.AuthController.ScaleFactorProvider;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.util.concurrency.DelayableExecutor;
@@ -133,6 +134,7 @@
long mRequestId = -1;
boolean mSkipAnimation = false;
@BiometricMultiSensorMode int mMultiSensorConfig = BIOMETRIC_MULTI_SENSOR_DEFAULT;
+ ScaleFactorProvider mScaleProvider;
}
public static class Builder {
@@ -196,6 +198,11 @@
return this;
}
+ public Builder setScaleFactorProvider(ScaleFactorProvider scaleProvider) {
+ mConfig.mScaleProvider = scaleProvider;
+ return this;
+ }
+
public AuthContainerView build(@Background DelayableExecutor bgExecutor, int[] sensorIds,
@Nullable List<FingerprintSensorPropertiesInternal> fpProps,
@Nullable List<FaceSensorPropertiesInternal> faceProps,
@@ -296,12 +303,14 @@
(AuthBiometricFingerprintAndFaceView) layoutInflater.inflate(
R.layout.auth_biometric_fingerprint_and_face_view, null, false);
fingerprintAndFaceView.setSensorProperties(fpProperties);
+ fingerprintAndFaceView.setScaleFactorProvider(config.mScaleProvider);
mBiometricView = fingerprintAndFaceView;
} else if (fpProperties != null) {
final AuthBiometricFingerprintView fpView =
(AuthBiometricFingerprintView) layoutInflater.inflate(
R.layout.auth_biometric_fingerprint_view, null, false);
fpView.setSensorProperties(fpProperties);
+ fpView.setScaleFactorProvider(config.mScaleProvider);
mBiometricView = fpView;
} else if (faceProperties != null) {
mBiometricView = (AuthBiometricFaceView) layoutInflater.inflate(
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index 75339aa..8c59f37 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -484,7 +484,13 @@
if (mFaceProps == null || mFaceAuthSensorLocation == null) {
return null;
}
- return new PointF(mFaceAuthSensorLocation.x, mFaceAuthSensorLocation.y);
+ DisplayInfo displayInfo = new DisplayInfo();
+ mContext.getDisplay().getDisplayInfo(displayInfo);
+ final float scaleFactor = android.util.DisplayUtils.getPhysicalPixelDisplaySizeRatio(
+ mStableDisplaySize.x, mStableDisplaySize.y, displayInfo.getNaturalWidth(),
+ displayInfo.getNaturalHeight());
+ return new PointF(mFaceAuthSensorLocation.x * scaleFactor,
+ mFaceAuthSensorLocation.y * scaleFactor);
}
/**
@@ -1031,11 +1037,24 @@
.setOperationId(operationId)
.setRequestId(requestId)
.setMultiSensorConfig(multiSensorConfig)
+ .setScaleFactorProvider(() -> {
+ return getScaleFactor();
+ })
.build(bgExecutor, sensorIds, mFpProps, mFaceProps, wakefulnessLifecycle,
userManager, lockPatternUtils);
}
/**
+ * Provides a float that represents the resolution scale(if the controller is for UDFPS).
+ */
+ public interface ScaleFactorProvider {
+ /**
+ * Returns a float representing the scaled resolution(if the controller if for UDFPS).
+ */
+ float provide();
+ }
+
+ /**
* AuthController callback used to receive signal for when biometric authenticators are
* registered.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.kt
index 5cfbdb0..742c65c 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.kt
@@ -192,4 +192,9 @@
* Called on touches outside of the view if listenForTouchesOutsideView returns true
*/
open fun onTouchOutsideView() {}
+
+ /**
+ * Called when a view should announce an accessibility event.
+ */
+ open fun doAnnounceForAccessibility(str: String) {}
}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpViewController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpViewController.kt
index 4cd40d2..2035781 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpViewController.kt
@@ -15,9 +15,11 @@
*/
package com.android.systemui.biometrics
+import com.android.systemui.broadcast.BroadcastSender
import com.android.systemui.dump.DumpManager
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.phone.SystemUIDialogManager
+import com.android.systemui.statusbar.phone.panelstate.PanelExpansionListener
import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager
/**
@@ -28,6 +30,7 @@
statusBarStateController: StatusBarStateController,
panelExpansionStateManager: PanelExpansionStateManager,
systemUIDialogManager: SystemUIDialogManager,
+ val broadcastSender: BroadcastSender,
dumpManager: DumpManager
) : UdfpsAnimationViewController<UdfpsBpView>(
view,
@@ -37,4 +40,29 @@
dumpManager
) {
override val tag = "UdfpsBpViewController"
+ private val bpPanelExpansionListener = PanelExpansionListener { event ->
+ // Notification shade can be expanded but not visible (fraction: 0.0), for example
+ // when a heads-up notification (HUN) is showing.
+ notificationShadeVisible = event.expanded && event.fraction > 0f
+ view.onExpansionChanged(event.fraction)
+ cancelAuth()
+ }
+
+ fun cancelAuth() {
+ if (shouldPauseAuth()) {
+ broadcastSender.closeSystemDialogs()
+ }
+ }
+
+ override fun onViewAttached() {
+ super.onViewAttached()
+
+ panelExpansionStateManager.addExpansionListener(bpPanelExpansionListener)
+ }
+
+ override fun onViewDetached() {
+ super.onViewDetached()
+
+ panelExpansionStateManager.removeExpansionListener(bpPanelExpansionListener)
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index 471240e..7775f50 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -51,9 +51,10 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.LatencyTracker;
-import com.android.keyguard.ActiveUnlockConfig;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.animation.ActivityLaunchAnimator;
+import com.android.systemui.biometrics.dagger.BiometricsBackground;
+import com.android.systemui.broadcast.BroadcastSender;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.doze.DozeReceiver;
@@ -76,6 +77,7 @@
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
+import java.util.concurrent.Executor;
import javax.inject.Inject;
@@ -107,6 +109,7 @@
@NonNull private final LayoutInflater mInflater;
private final WindowManager mWindowManager;
private final DelayableExecutor mFgExecutor;
+ @NonNull private final Executor mBiometricExecutor;
@NonNull private final PanelExpansionStateManager mPanelExpansionStateManager;
@NonNull private final StatusBarStateController mStatusBarStateController;
@NonNull private final KeyguardStateController mKeyguardStateController;
@@ -125,6 +128,7 @@
@NonNull private final UnlockedScreenOffAnimationController
mUnlockedScreenOffAnimationController;
@NonNull private final LatencyTracker mLatencyTracker;
+ @NonNull private final BroadcastSender mBroadcastSender;
@VisibleForTesting @NonNull final BiometricDisplayListener mOrientationListener;
@NonNull private final ActivityLaunchAnimator mActivityLaunchAnimator;
@@ -205,7 +209,7 @@
mUnlockedScreenOffAnimationController, mHalControlsIllumination,
mHbmProvider, requestId, reason, callback,
(view, event, fromUdfpsView) -> onTouch(requestId, event,
- fromUdfpsView), mActivityLaunchAnimator)));
+ fromUdfpsView), mActivityLaunchAnimator, mBroadcastSender)));
}
@Override
@@ -380,6 +384,27 @@
&& mOverlayParams.getSensorBounds().contains((int) x, (int) y);
}
+ private Point getTouchInNativeCoordinates(@NonNull MotionEvent event, int idx) {
+ Point portraitTouch = new Point(
+ (int) event.getRawX(idx),
+ (int) event.getRawY(idx)
+ );
+ final int rot = mOverlayParams.getRotation();
+ if (rot == Surface.ROTATION_90 || rot == Surface.ROTATION_270) {
+ RotationUtils.rotatePoint(portraitTouch,
+ RotationUtils.deltaRotation(rot, Surface.ROTATION_0),
+ mOverlayParams.getLogicalDisplayWidth(),
+ mOverlayParams.getLogicalDisplayHeight()
+ );
+ }
+
+ // Scale the coordinates to native resolution.
+ final float scale = mOverlayParams.getScaleFactor();
+ portraitTouch.x = (int) (portraitTouch.x / scale);
+ portraitTouch.y = (int) (portraitTouch.y / scale);
+ return portraitTouch;
+ }
+
@VisibleForTesting
boolean onTouch(long requestId, @NonNull MotionEvent event, boolean fromUdfpsView) {
if (mOverlay == null) {
@@ -433,6 +458,7 @@
mKeyguardViewManager.notifyKeyguardAuthenticated(false /* strongAuth */);
mAttemptedToDismissKeyguard = true;
}
+
Trace.endSection();
break;
@@ -456,6 +482,8 @@
mAttemptedToDismissKeyguard = true;
break;
}
+ // Map the touch to portrait mode if the device is in landscape mode.
+ final Point scaledTouch = getTouchInNativeCoordinates(event, idx);
if (actionMoveWithinSensorArea) {
if (mVelocityTracker == null) {
// touches could be injected, so the velocity tracker may not have
@@ -476,28 +504,13 @@
final long sinceLastLog = mSystemClock.elapsedRealtime() - mTouchLogTime;
if (!isIlluminationRequested && !mAcquiredReceived
&& !exceedsVelocityThreshold) {
- // Map the touch to portrait mode if the device is in landscape mode.
- Point portraitTouch = new Point(
- (int) event.getRawX(idx),
- (int) event.getRawY(idx)
- );
- final int rot = mOverlayParams.getRotation();
- if (rot == Surface.ROTATION_90 || rot == Surface.ROTATION_270) {
- RotationUtils.rotatePoint(portraitTouch,
- RotationUtils.deltaRotation(rot, Surface.ROTATION_0),
- mOverlayParams.getLogicalDisplayWidth(),
- mOverlayParams.getLogicalDisplayHeight()
- );
- }
- // Scale the coordinates to native resolution.
final float scale = mOverlayParams.getScaleFactor();
- int scaledX = (int) (portraitTouch.x / scale);
- int scaledY = (int) (portraitTouch.y / scale);
float scaledMinor = minor / scale;
float scaledMajor = major / scale;
- onFingerDown(requestId, scaledX, scaledY, scaledMinor, scaledMajor);
+ onFingerDown(requestId, scaledTouch.x, scaledTouch.y, scaledMinor,
+ scaledMajor);
Log.v(TAG, "onTouch | finger down: " + touchInfo);
mTouchLogTime = mSystemClock.elapsedRealtime();
mPowerManager.userActivity(mSystemClock.uptimeMillis(),
@@ -510,6 +523,24 @@
} else {
Log.v(TAG, "onTouch | finger outside");
onFingerUp(requestId, udfpsView);
+ // Maybe announce for accessibility.
+ mFgExecutor.execute(() -> {
+ if (mOverlay == null) {
+ Log.e(TAG, "touch outside sensor area received"
+ + "but serverRequest is null");
+ return;
+ }
+ // Scale the coordinates to native resolution.
+ final float scale = mOverlayParams.getScaleFactor();
+ final float scaledSensorX =
+ mOverlayParams.getSensorBounds().centerX() / scale;
+ final float scaledSensorY =
+ mOverlayParams.getSensorBounds().centerY() / scale;
+
+ mOverlay.onTouchOutsideOfSensorArea(
+ scaledTouch.x, scaledTouch.y, scaledSensorX, scaledSensorY,
+ mOverlayParams.getRotation());
+ });
}
}
Trace.endSection();
@@ -574,7 +605,9 @@
@NonNull SystemUIDialogManager dialogManager,
@NonNull LatencyTracker latencyTracker,
@NonNull ActivityLaunchAnimator activityLaunchAnimator,
- @NonNull Optional<AlternateUdfpsTouchProvider> aternateTouchProvider) {
+ @NonNull Optional<AlternateUdfpsTouchProvider> aternateTouchProvider,
+ @NonNull BroadcastSender broadcastSender,
+ @BiometricsBackground Executor biometricsExecutor) {
mContext = context;
mExecution = execution;
mVibrator = vibrator;
@@ -604,6 +637,8 @@
mLatencyTracker = latencyTracker;
mActivityLaunchAnimator = activityLaunchAnimator;
mAlternateTouchProvider = aternateTouchProvider.orElse(null);
+ mBroadcastSender = broadcastSender;
+ mBiometricExecutor = biometricsExecutor;
mOrientationListener = new BiometricDisplayListener(
context,
@@ -804,14 +839,12 @@
if (!mKeyguardUpdateMonitor.isFaceDetectionRunning()) {
mKeyguardUpdateMonitor.requestFaceAuth(/* userInitiatedRequest */ false);
}
-
- mKeyguardUpdateMonitor.requestActiveUnlock(
- ActiveUnlockConfig.ACTIVE_UNLOCK_REQUEST_ORIGIN.UNLOCK_INTENT,
- "udfpsFingerDown");
}
mOnFingerDown = true;
if (mAlternateTouchProvider != null) {
- mAlternateTouchProvider.onPointerDown(requestId, x, y, minor, major);
+ mBiometricExecutor.execute(() -> {
+ mAlternateTouchProvider.onPointerDown(requestId, x, y, minor, major);
+ });
mFgExecutor.execute(() -> {
if (mKeyguardUpdateMonitor.isFingerprintDetectionRunning()) {
mKeyguardUpdateMonitor.onUdfpsPointerDown((int) requestId);
@@ -821,16 +854,18 @@
mFingerprintManager.onPointerDown(requestId, mSensorId, x, y, minor, major);
}
Trace.endAsyncSection("UdfpsController.e2e.onPointerDown", 0);
-
final UdfpsView view = mOverlay.getOverlayView();
if (view != null) {
view.startIllumination(() -> {
if (mAlternateTouchProvider != null) {
- mAlternateTouchProvider.onUiReady();
+ mBiometricExecutor.execute(() -> {
+ mAlternateTouchProvider.onUiReady();
+ mLatencyTracker.onActionEnd(LatencyTracker.ACTION_UDFPS_ILLUMINATE);
+ });
} else {
mFingerprintManager.onUiReady(requestId, mSensorId);
+ mLatencyTracker.onActionEnd(LatencyTracker.ACTION_UDFPS_ILLUMINATE);
}
- mLatencyTracker.onActionEnd(LatencyTracker.ACTION_UDFPS_ILLUMINATE);
});
}
@@ -845,7 +880,9 @@
mAcquiredReceived = false;
if (mOnFingerDown) {
if (mAlternateTouchProvider != null) {
- mAlternateTouchProvider.onPointerUp(requestId);
+ mBiometricExecutor.execute(() -> {
+ mAlternateTouchProvider.onPointerUp(requestId);
+ });
mFgExecutor.execute(() -> {
if (mKeyguardUpdateMonitor.isFingerprintDetectionRunning()) {
mKeyguardUpdateMonitor.onUdfpsPointerUp((int) requestId);
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
index 2d51c97..37db2bd 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
@@ -41,6 +41,7 @@
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.systemui.R
import com.android.systemui.animation.ActivityLaunchAnimator
+import com.android.systemui.broadcast.BroadcastSender
import com.android.systemui.dump.DumpManager
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.LockscreenShadeTransitionController
@@ -83,7 +84,8 @@
@ShowReason val requestReason: Int,
private val controllerCallback: IUdfpsOverlayControllerCallback,
private val onTouch: (View, MotionEvent, Boolean) -> Boolean,
- private val activityLaunchAnimator: ActivityLaunchAnimator
+ private val activityLaunchAnimator: ActivityLaunchAnimator,
+ private val broadcastSender: BroadcastSender
) {
/** The view, when [isShowing], or null. */
var overlayView: UdfpsView? = null
@@ -102,8 +104,8 @@
fitInsetsTypes = 0
gravity = android.view.Gravity.TOP or android.view.Gravity.LEFT
layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
- flags =
- (Utils.FINGERPRINT_OVERLAY_LAYOUT_PARAM_FLAGS or WindowManager.LayoutParams.FLAG_SPLIT_TOUCH)
+ flags = (Utils.FINGERPRINT_OVERLAY_LAYOUT_PARAM_FLAGS
+ or WindowManager.LayoutParams.FLAG_SPLIT_TOUCH)
privateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY
// Avoid announcing window title.
accessibilityTitle = " "
@@ -128,6 +130,8 @@
val animationViewController: UdfpsAnimationViewController<*>?
get() = overlayView?.animationViewController
+ private var touchExplorationEnabled = false
+
/** Show the overlay or return false and do nothing if it is already showing. */
@SuppressLint("ClickableViewAccessibility")
fun show(controller: UdfpsController, params: UdfpsOverlayParams): Boolean {
@@ -152,14 +156,16 @@
}
windowManager.addView(this, coreLayoutParams.updateDimensions(animation))
-
+ touchExplorationEnabled = accessibilityManager.isTouchExplorationEnabled
overlayTouchListener = TouchExplorationStateChangeListener {
if (accessibilityManager.isTouchExplorationEnabled) {
setOnHoverListener { v, event -> onTouch(v, event, true) }
setOnTouchListener(null)
+ touchExplorationEnabled = true
} else {
setOnHoverListener(null)
setOnTouchListener { v, event -> onTouch(v, event, true) }
+ touchExplorationEnabled = false
}
}
accessibilityManager.addTouchExplorationStateChangeListener(
@@ -177,7 +183,7 @@
return false
}
- private fun inflateUdfpsAnimation(
+ fun inflateUdfpsAnimation(
view: UdfpsView,
controller: UdfpsController
): UdfpsAnimationViewController<*>? {
@@ -221,6 +227,7 @@
statusBarStateController,
panelExpansionStateManager,
dialogManager,
+ broadcastSender,
dumpManager
)
}
@@ -275,6 +282,88 @@
enrollHelper?.onEnrollmentHelp()
}
+ /**
+ * This function computes the angle of touch relative to the sensor and maps
+ * the angle to a list of help messages which are announced if accessibility is enabled.
+ *
+ */
+ fun onTouchOutsideOfSensorArea(
+ touchX: Float,
+ touchY: Float,
+ sensorX: Float,
+ sensorY: Float,
+ rotation: Int
+ ) {
+
+ if (!touchExplorationEnabled) {
+ return
+ }
+ val touchHints =
+ context.resources.getStringArray(R.array.udfps_accessibility_touch_hints)
+ if (touchHints.size != 4) {
+ Log.e(TAG, "expected exactly 4 touch hints, got $touchHints.size?")
+ return
+ }
+ val theStr = onTouchOutsideOfSensorAreaImpl(touchX, touchY, sensorX, sensorY, rotation)
+ Log.v(TAG, "Announcing touch outside : " + theStr)
+ animationViewController?.doAnnounceForAccessibility(theStr)
+ }
+
+ /**
+ * This function computes the angle of touch relative to the sensor and maps
+ * the angle to a list of help messages which are announced if accessibility is enabled.
+ *
+ * There are 4 quadrants of the circle (90 degree arcs)
+ *
+ * [315, 360] && [0, 45) -> touchHints[0] = "Move Fingerprint to the left"
+ * [45, 135) -> touchHints[1] = "Move Fingerprint down"
+ * And so on.
+ */
+ fun onTouchOutsideOfSensorAreaImpl(
+ touchX: Float,
+ touchY: Float,
+ sensorX: Float,
+ sensorY: Float,
+ rotation: Int
+ ): String {
+ val touchHints =
+ context.resources.getStringArray(R.array.udfps_accessibility_touch_hints)
+
+ val xRelativeToSensor = touchX - sensorX
+ // Touch coordinates are with respect to the upper left corner, so reverse
+ // this calculation
+ val yRelativeToSensor = sensorY - touchY
+
+ var angleInRad =
+ Math.atan2(yRelativeToSensor.toDouble(), xRelativeToSensor.toDouble())
+ // If the radians are negative, that means we are counting clockwise.
+ // So we need to add 360 degrees
+ if (angleInRad < 0.0) {
+ angleInRad += 2.0 * Math.PI
+ }
+ // rad to deg conversion
+ val degrees = Math.toDegrees(angleInRad)
+
+ val degreesPerBucket = 360.0 / touchHints.size
+ val halfBucketDegrees = degreesPerBucket / 2.0
+ // The mapping should be as follows
+ // [315, 360] && [0, 45] -> 0
+ // [45, 135] -> 1
+ var index = (((degrees + halfBucketDegrees) % 360) / degreesPerBucket).toInt()
+ index %= touchHints.size
+
+ // A rotation of 90 degrees corresponds to increasing the index by 1.
+ if (rotation == Surface.ROTATION_90) {
+ index = (index + 1) % touchHints.size
+ }
+
+ if (rotation == Surface.ROTATION_270) {
+ index = (index + 3) % touchHints.size
+ }
+
+ return touchHints[index]
+ }
+
/** Cancel this request. */
fun cancel() {
try {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapter.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapter.java
index 8de7213..2ab97e7 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapter.java
@@ -64,15 +64,16 @@
@NonNull
AuthDialog.LayoutParams onMeasureInternal(
- int width, int height, @NonNull AuthDialog.LayoutParams layoutParams) {
+ int width, int height, @NonNull AuthDialog.LayoutParams layoutParams,
+ float scaleFactor) {
final int displayRotation = mView.getDisplay().getRotation();
switch (displayRotation) {
case Surface.ROTATION_0:
- return onMeasureInternalPortrait(width, height);
+ return onMeasureInternalPortrait(width, height, scaleFactor);
case Surface.ROTATION_90:
case Surface.ROTATION_270:
- return onMeasureInternalLandscape(width, height);
+ return onMeasureInternalLandscape(width, height, scaleFactor);
default:
Log.e(TAG, "Unsupported display rotation: " + displayRotation);
return layoutParams;
@@ -90,7 +91,8 @@
}
@NonNull
- private AuthDialog.LayoutParams onMeasureInternalPortrait(int width, int height) {
+ private AuthDialog.LayoutParams onMeasureInternalPortrait(int width, int height,
+ float scaleFactor) {
final WindowMetrics windowMetrics = mWindowManager.getMaximumWindowMetrics();
// Figure out where the bottom of the sensor anim should be.
@@ -101,12 +103,13 @@
final Insets navbarInsets = getNavbarInsets(windowMetrics);
mBottomSpacerHeight = calculateBottomSpacerHeightForPortrait(
mSensorProps, displayHeight, textIndicatorHeight, buttonBarHeight,
- dialogMargin, navbarInsets.bottom);
+ dialogMargin, navbarInsets.bottom, scaleFactor);
// Go through each of the children and do the custom measurement.
int totalHeight = 0;
final int numChildren = mView.getChildCount();
- final int sensorDiameter = mSensorProps.getLocation().sensorRadius * 2;
+ final int sensorDiameter =
+ (int) (scaleFactor * mSensorProps.getLocation().sensorRadius * 2);
for (int i = 0; i < numChildren; i++) {
final View child = mView.getChildAt(i);
if (child.getId() == R.id.biometric_icon_frame) {
@@ -176,7 +179,8 @@
}
@NonNull
- private AuthDialog.LayoutParams onMeasureInternalLandscape(int width, int height) {
+ private AuthDialog.LayoutParams onMeasureInternalLandscape(int width, int height,
+ float scaleFactor) {
final WindowMetrics windowMetrics = mWindowManager.getMaximumWindowMetrics();
// Find the spacer height needed to vertically align the icon with the sensor.
@@ -197,9 +201,10 @@
final int dialogMargin = getDialogMarginPx();
final int horizontalInset = navbarInsets.left + navbarInsets.right;
final int horizontalSpacerWidth = calculateHorizontalSpacerWidthForLandscape(
- mSensorProps, displayWidth, dialogMargin, horizontalInset);
+ mSensorProps, displayWidth, dialogMargin, horizontalInset, scaleFactor);
- final int sensorDiameter = mSensorProps.getLocation().sensorRadius * 2;
+ final int sensorDiameter =
+ (int) (scaleFactor * mSensorProps.getLocation().sensorRadius * 2);
final int remeasuredWidth = sensorDiameter + 2 * horizontalSpacerWidth;
int remeasuredHeight = 0;
@@ -281,11 +286,11 @@
static int calculateBottomSpacerHeightForPortrait(
@NonNull FingerprintSensorPropertiesInternal sensorProperties, int displayHeightPx,
int textIndicatorHeightPx, int buttonBarHeightPx, int dialogMarginPx,
- int navbarBottomInsetPx) {
+ int navbarBottomInsetPx, float scaleFactor) {
final SensorLocationInternal location = sensorProperties.getLocation();
final int sensorDistanceFromBottom = displayHeightPx
- - location.sensorLocationY
- - location.sensorRadius;
+ - (int) (scaleFactor * location.sensorLocationY)
+ - (int) (scaleFactor * location.sensorRadius);
final int spacerHeight = sensorDistanceFromBottom
- textIndicatorHeightPx
@@ -298,7 +303,8 @@
+ ", Distance from bottom: " + sensorDistanceFromBottom
+ ", Bottom margin: " + dialogMarginPx
+ ", Navbar bottom inset: " + navbarBottomInsetPx
- + ", Bottom spacer height (portrait): " + spacerHeight);
+ + ", Bottom spacer height (portrait): " + spacerHeight
+ + ", Scale Factor: " + scaleFactor);
}
return spacerHeight;
@@ -346,11 +352,11 @@
@VisibleForTesting
static int calculateHorizontalSpacerWidthForLandscape(
@NonNull FingerprintSensorPropertiesInternal sensorProperties, int displayWidthPx,
- int dialogMarginPx, int navbarHorizontalInsetPx) {
+ int dialogMarginPx, int navbarHorizontalInsetPx, float scaleFactor) {
final SensorLocationInternal location = sensorProperties.getLocation();
final int sensorDistanceFromEdge = displayWidthPx
- - location.sensorLocationY
- - location.sensorRadius;
+ - (int) (scaleFactor * location.sensorLocationY)
+ - (int) (scaleFactor * location.sensorRadius);
final int horizontalPadding = sensorDistanceFromEdge
- dialogMarginPx
@@ -361,7 +367,8 @@
+ ", Distance from edge: " + sensorDistanceFromEdge
+ ", Dialog margin: " + dialogMarginPx
+ ", Navbar horizontal inset: " + navbarHorizontalInsetPx
- + ", Horizontal spacer width (landscape): " + horizontalPadding);
+ + ", Horizontal spacer width (landscape): " + horizontalPadding
+ + ", Scale Factor: " + scaleFactor);
}
return horizontalPadding;
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java
index 2ed60e5..0b7bdde 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java
@@ -99,4 +99,10 @@
public int getPaddingY() {
return mEnrollProgressBarRadius;
}
+
+ @Override
+ public void doAnnounceForAccessibility(String str) {
+ mView.announceForAccessibility(str);
+ }
+
}
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/BroadcastDialog.java b/packages/SystemUI/src/com/android/systemui/bluetooth/BroadcastDialog.java
new file mode 100644
index 0000000..9b7d498
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/bluetooth/BroadcastDialog.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.systemui.bluetooth;
+
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.Button;
+import android.widget.TextView;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.logging.UiEvent;
+import com.android.internal.logging.UiEventLogger;
+import com.android.systemui.R;
+import com.android.systemui.media.MediaDataUtils;
+import com.android.systemui.media.dialog.MediaOutputDialogFactory;
+import com.android.systemui.statusbar.phone.SystemUIDialog;
+
+/**
+ * Dialog for showing le audio broadcasting dialog.
+ */
+public class BroadcastDialog extends SystemUIDialog {
+
+ private static final String TAG = "BroadcastDialog";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+ private Context mContext;
+ private UiEventLogger mUiEventLogger;
+ @VisibleForTesting
+ protected View mDialogView;
+ private MediaOutputDialogFactory mMediaOutputDialogFactory;
+ private String mSwitchBroadcastApp;
+ private String mOutputPackageName;
+
+ public BroadcastDialog(Context context, MediaOutputDialogFactory mediaOutputDialogFactory,
+ String switchBroadcastApp, String outputPkgName, UiEventLogger uiEventLogger) {
+ super(context);
+ if (DEBUG) {
+ Log.d(TAG, "Init BroadcastDialog");
+ }
+
+ mContext = getContext();
+ mMediaOutputDialogFactory = mediaOutputDialogFactory;
+ mSwitchBroadcastApp = switchBroadcastApp;
+ mOutputPackageName = outputPkgName;
+ mUiEventLogger = uiEventLogger;
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ if (DEBUG) {
+ Log.d(TAG, "onCreate");
+ }
+
+ mUiEventLogger.log(BroadcastDialogEvent.BROADCAST_DIALOG_SHOW);
+ mDialogView = LayoutInflater.from(mContext).inflate(R.layout.broadcast_dialog, null);
+ final Window window = getWindow();
+ window.setContentView(mDialogView);
+
+ TextView title = mDialogView.requireViewById(R.id.dialog_title);
+ TextView subTitle = mDialogView.requireViewById(R.id.dialog_subtitle);
+ title.setText(
+ mContext.getString(R.string.bt_le_audio_broadcast_dialog_title,
+ MediaDataUtils.getAppLabel(mContext, mOutputPackageName,
+ mContext.getString(
+ R.string.bt_le_audio_broadcast_dialog_unknown_name))));
+ subTitle.setText(
+ mContext.getString(R.string.bt_le_audio_broadcast_dialog_sub_title,
+ mSwitchBroadcastApp));
+
+ Button switchBroadcast = mDialogView.requireViewById(R.id.switch_broadcast);
+ Button changeOutput = mDialogView.requireViewById(R.id.change_output);
+ Button cancelBtn = mDialogView.requireViewById(R.id.cancel);
+ switchBroadcast.setText(mContext.getString(
+ R.string.bt_le_audio_broadcast_dialog_switch_app, mSwitchBroadcastApp), null);
+ changeOutput.setOnClickListener((view) -> {
+ mMediaOutputDialogFactory.create(mOutputPackageName, true, null);
+ dismiss();
+ });
+ cancelBtn.setOnClickListener((view) -> {
+ if (DEBUG) {
+ Log.d(TAG, "BroadcastDialog dismiss.");
+ }
+ dismiss();
+ });
+ }
+
+ @Override
+ public void onWindowFocusChanged(boolean hasFocus) {
+ super.onWindowFocusChanged(hasFocus);
+ if (!hasFocus && isShowing()) {
+ dismiss();
+ }
+ }
+
+ public enum BroadcastDialogEvent implements UiEventLogger.UiEventEnum {
+ @UiEvent(doc = "The Broadcast dialog became visible on the screen.")
+ BROADCAST_DIALOG_SHOW(1062);
+
+ private final int mId;
+
+ BroadcastDialogEvent(int id) {
+ mId = id;
+ }
+
+ @Override
+ public int getId() {
+ return mId;
+ }
+ }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/BroadcastDialogController.java b/packages/SystemUI/src/com/android/systemui/bluetooth/BroadcastDialogController.java
new file mode 100644
index 0000000..8a54345
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/bluetooth/BroadcastDialogController.java
@@ -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.bluetooth;
+
+import android.content.Context;
+import android.view.View;
+
+import com.android.internal.logging.UiEventLogger;
+import com.android.systemui.animation.DialogLaunchAnimator;
+import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.media.dialog.MediaOutputDialogFactory;
+
+import javax.inject.Inject;
+
+/**
+ * Controller to create BroadcastDialog objects.
+ */
+@SysUISingleton
+public class BroadcastDialogController {
+
+ private Context mContext;
+ private UiEventLogger mUiEventLogger;
+ private DialogLaunchAnimator mDialogLaunchAnimator;
+ private MediaOutputDialogFactory mMediaOutputDialogFactory;
+
+ @Inject
+ public BroadcastDialogController(Context context, UiEventLogger uiEventLogger,
+ DialogLaunchAnimator dialogLaunchAnimator,
+ MediaOutputDialogFactory mediaOutputDialogFactory) {
+ mContext = context;
+ mUiEventLogger = uiEventLogger;
+ mDialogLaunchAnimator = dialogLaunchAnimator;
+ mMediaOutputDialogFactory = mediaOutputDialogFactory;
+ }
+
+ public void createBroadcastDialog(String switchAppName, String outputPkgName,
+ boolean aboveStatusBar, View view) {
+ BroadcastDialog broadcastDialog = new BroadcastDialog(mContext, mMediaOutputDialogFactory,
+ switchAppName, outputPkgName, mUiEventLogger);
+ if (view != null) {
+ mDialogLaunchAnimator.showFromView(broadcastDialog, view);
+ } else {
+ broadcastDialog.show();
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardListener.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardListener.java
index 6a9317f..f526277 100644
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardListener.java
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardListener.java
@@ -20,10 +20,14 @@
import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_ENTERED;
import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_UPDATED;
+import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
+import android.os.SystemProperties;
import android.provider.DeviceConfig;
+import android.util.Log;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.CoreStartable;
import com.android.systemui.dagger.SysUISingleton;
@@ -37,6 +41,13 @@
@SysUISingleton
public class ClipboardListener extends CoreStartable
implements ClipboardManager.OnPrimaryClipChangedListener {
+ private static final String TAG = "ClipboardListener";
+
+ @VisibleForTesting
+ static final String SHELL_PACKAGE = "com.android.shell";
+ @VisibleForTesting
+ static final String EXTRA_SUPPRESS_OVERLAY =
+ "com.android.systemui.SUPPRESS_CLIPBOARD_OVERLAY";
private final DeviceConfigProxy mDeviceConfig;
private final ClipboardOverlayControllerFactory mOverlayFactory;
@@ -68,18 +79,44 @@
if (!mClipboardManager.hasPrimaryClip()) {
return;
}
+
String clipSource = mClipboardManager.getPrimaryClipSource();
+ ClipData clipData = mClipboardManager.getPrimaryClip();
+
+ if (shouldSuppressOverlay(clipData, clipSource, isEmulator())) {
+ Log.i(TAG, "Clipboard overlay suppressed.");
+ return;
+ }
+
if (mClipboardOverlayController == null) {
mClipboardOverlayController = mOverlayFactory.create(mContext);
mUiEventLogger.log(CLIPBOARD_OVERLAY_ENTERED, 0, clipSource);
} else {
mUiEventLogger.log(CLIPBOARD_OVERLAY_UPDATED, 0, clipSource);
}
- mClipboardOverlayController.setClipData(
- mClipboardManager.getPrimaryClip(), clipSource);
+ mClipboardOverlayController.setClipData(clipData, clipSource);
mClipboardOverlayController.setOnSessionCompleteListener(() -> {
// Session is complete, free memory until it's needed again.
mClipboardOverlayController = null;
});
}
+
+ // The overlay is suppressed if EXTRA_SUPPRESS_OVERLAY is true and the device is an emulator or
+ // the source package is SHELL_PACKAGE. This is meant to suppress the overlay when the emulator
+ // or a mirrored device is syncing the clipboard.
+ @VisibleForTesting
+ static boolean shouldSuppressOverlay(ClipData clipData, String clipSource,
+ boolean isEmulator) {
+ if (!(isEmulator || SHELL_PACKAGE.equals(clipSource))) {
+ return false;
+ }
+ if (clipData == null || clipData.getDescription().getExtras() == null) {
+ return false;
+ }
+ return clipData.getDescription().getExtras().getBoolean(EXTRA_SUPPRESS_OVERLAY, false);
+ }
+
+ private static boolean isEmulator() {
+ return SystemProperties.getBoolean("ro.boot.qemu", false);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
index ee8363f..c3dd29e 100644
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
@@ -35,6 +35,7 @@
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
import android.annotation.MainThread;
+import android.app.ICompatCameraControlCallback;
import android.app.RemoteAction;
import android.content.BroadcastReceiver;
import android.content.ClipData;
@@ -44,7 +45,9 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
+import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Insets;
import android.graphics.Rect;
@@ -68,6 +71,7 @@
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
+import android.view.ViewRootImpl;
import android.view.ViewTreeObserver;
import android.view.WindowInsets;
import android.view.WindowManager;
@@ -85,6 +89,7 @@
import com.android.internal.logging.UiEventLogger;
import com.android.internal.policy.PhoneWindow;
+import com.android.settingslib.applications.InterestingConfigChanges;
import com.android.systemui.R;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.broadcast.BroadcastSender;
@@ -150,6 +155,10 @@
private boolean mBlockAttach = false;
private Animator mExitAnimator;
+ /** Tracks config changes that require updating insets */
+ private final InterestingConfigChanges mConfigChanges = new InterestingConfigChanges(
+ ActivityInfo.CONFIG_KEYBOARD_HIDDEN);
+
public ClipboardOverlayController(Context context,
BroadcastDispatcher broadcastDispatcher,
BroadcastSender broadcastSender,
@@ -232,6 +241,24 @@
mWindow.setContentView(mView);
updateInsets(mWindowManager.getCurrentWindowMetrics().getWindowInsets());
mView.requestLayout();
+ mWindow.peekDecorView().getViewRootImpl().setActivityConfigCallback(
+ new ViewRootImpl.ActivityConfigCallback() {
+ @Override
+ public void onConfigurationChanged(Configuration overrideConfig,
+ int newDisplayId) {
+ if (mConfigChanges.applyNewConfig(mContext.getResources())) {
+ updateInsets(
+ mWindowManager.getCurrentWindowMetrics().getWindowInsets());
+ }
+ }
+
+ @Override
+ public void requestCompatCameraControl(
+ boolean showControl, boolean transformationApplied,
+ ICompatCameraControlCallback callback) {
+ Log.w(TAG, "unexpected requestCompatCameraControl call");
+ }
+ });
});
mTimeoutHandler.setOnTimeoutRunnable(() -> {
@@ -275,6 +302,7 @@
mExitAnimator.cancel();
}
reset();
+ String accessibilityAnnouncement;
boolean isSensitive = clipData != null && clipData.getDescription().getExtras() != null
&& clipData.getDescription().getExtras()
@@ -283,6 +311,7 @@
showTextPreview(
mContext.getResources().getString(R.string.clipboard_overlay_text_copied),
mTextPreview);
+ accessibilityAnnouncement = mContext.getString(R.string.clipboard_content_copied);
} else if (!TextUtils.isEmpty(clipData.getItemAt(0).getText())) {
ClipData.Item item = clipData.getItemAt(0);
if (item.getTextLinks() != null) {
@@ -294,13 +323,18 @@
} else {
showEditableText(item.getText(), false);
}
+ accessibilityAnnouncement = mContext.getString(R.string.clipboard_text_copied);
} else if (clipData.getItemAt(0).getUri() != null) {
- // How to handle non-image URIs?
- showEditableImage(clipData.getItemAt(0).getUri(), isSensitive);
+ if (tryShowEditableImage(clipData.getItemAt(0).getUri(), isSensitive)) {
+ accessibilityAnnouncement = mContext.getString(R.string.clipboard_image_copied);
+ } else {
+ accessibilityAnnouncement = mContext.getString(R.string.clipboard_content_copied);
+ }
} else {
showTextPreview(
mContext.getResources().getString(R.string.clipboard_overlay_text_copied),
mTextPreview);
+ accessibilityAnnouncement = mContext.getString(R.string.clipboard_content_copied);
}
Intent remoteCopyIntent = getRemoteCopyIntent(clipData);
// Only show remote copy if it's available.
@@ -317,7 +351,12 @@
} else {
mRemoteCopyChip.setVisibility(View.GONE);
}
- withWindowAttached(() -> mView.post(this::animateIn));
+ withWindowAttached(() -> {
+ updateInsets(
+ mWindowManager.getCurrentWindowMetrics().getWindowInsets());
+ mView.post(this::animateIn);
+ mView.announceForAccessibility(accessibilityAnnouncement);
+ });
mTimeoutHandler.resetTimeout();
}
@@ -449,33 +488,46 @@
textView.setOnClickListener(listener);
}
- private void showEditableImage(Uri uri, boolean isSensitive) {
- mEditChip.setAlpha(1f);
- mActionContainerBackground.setVisibility(View.VISIBLE);
+ private boolean tryShowEditableImage(Uri uri, boolean isSensitive) {
View.OnClickListener listener = v -> editImage(uri);
+ ContentResolver resolver = mContext.getContentResolver();
+ String mimeType = resolver.getType(uri);
+ boolean isEditableImage = mimeType != null && mimeType.startsWith("image");
if (isSensitive) {
showSinglePreview(mHiddenImagePreview);
- mHiddenImagePreview.setOnClickListener(listener);
- } else {
- showSinglePreview(mImagePreview);
- ContentResolver resolver = mContext.getContentResolver();
+ if (isEditableImage) {
+ mHiddenImagePreview.setOnClickListener(listener);
+ }
+ } else if (isEditableImage) { // if the MIMEtype is image, try to load
try {
int size = mContext.getResources().getDimensionPixelSize(R.dimen.overlay_x_scale);
// The width of the view is capped, height maintains aspect ratio, so allow it to be
// taller if needed.
Bitmap thumbnail = resolver.loadThumbnail(uri, new Size(size, size * 4), null);
+ showSinglePreview(mImagePreview);
mImagePreview.setImageBitmap(thumbnail);
+ mImagePreview.setOnClickListener(listener);
} catch (IOException e) {
Log.e(TAG, "Thumbnail loading failed", e);
showTextPreview(
mContext.getResources().getString(R.string.clipboard_overlay_text_copied),
mTextPreview);
+ isEditableImage = false;
}
- mImagePreview.setOnClickListener(listener);
+ } else {
+ showTextPreview(
+ mContext.getResources().getString(R.string.clipboard_overlay_text_copied),
+ mTextPreview);
}
- mEditChip.setOnClickListener(listener);
- mEditChip.setContentDescription(
- mContext.getString(R.string.clipboard_edit_image_description));
+ if (isEditableImage) {
+ mEditChip.setVisibility(View.VISIBLE);
+ mEditChip.setAlpha(1f);
+ mActionContainerBackground.setVisibility(View.VISIBLE);
+ mEditChip.setOnClickListener(listener);
+ mEditChip.setContentDescription(
+ mContext.getString(R.string.clipboard_edit_image_description));
+ }
+ return isEditableImage;
}
private Intent getRemoteCopyIntent(ClipData clipData) {
@@ -499,6 +551,9 @@
}
private void animateOut() {
+ if (mExitAnimator != null && mExitAnimator.isRunning()) {
+ return;
+ }
Animator anim = getExitAnimation();
anim.addListener(new AnimatorListenerAdapter() {
private boolean mCancelled;
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
index a4f9f3a..6a9aaf8 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
@@ -472,7 +472,6 @@
updateContentDescription()
status.setTextColor(color)
- chevronIcon.imageTintList = color
control?.getCustomIcon()?.let {
icon.setImageIcon(it)
@@ -495,10 +494,13 @@
icon.imageTintList = color
}
}
+
+ chevronIcon.imageTintList = icon.imageTintList
}
private fun setEnabled(enabled: Boolean) {
- status.setEnabled(enabled)
- icon.setEnabled(enabled)
+ status.isEnabled = enabled
+ icon.isEnabled = enabled
+ chevronIcon.isEnabled = enabled
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
index 5d34a69..3a1b129 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
@@ -39,14 +39,12 @@
import com.android.systemui.unfold.util.NaturalRotationUnfoldProgressProvider;
import com.android.wm.shell.ShellCommandHandler;
import com.android.wm.shell.TaskViewFactory;
-import com.android.wm.shell.apppairs.AppPairs;
import com.android.wm.shell.back.BackAnimation;
import com.android.wm.shell.bubbles.Bubbles;
import com.android.wm.shell.compatui.CompatUI;
import com.android.wm.shell.displayareahelper.DisplayAreaHelper;
import com.android.wm.shell.draganddrop.DragAndDrop;
import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout;
-import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import com.android.wm.shell.onehanded.OneHanded;
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.recents.RecentTasks;
@@ -86,15 +84,9 @@
Builder setPip(Optional<Pip> p);
@BindsInstance
- Builder setLegacySplitScreen(Optional<LegacySplitScreen> s);
-
- @BindsInstance
Builder setSplitScreen(Optional<SplitScreen> s);
@BindsInstance
- Builder setAppPairs(Optional<AppPairs> s);
-
- @BindsInstance
Builder setOneHanded(Optional<OneHanded> o);
@BindsInstance
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
index b02074a..1570a7e 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
@@ -26,7 +26,6 @@
import com.android.wm.shell.ShellCommandHandler;
import com.android.wm.shell.ShellInit;
import com.android.wm.shell.TaskViewFactory;
-import com.android.wm.shell.apppairs.AppPairs;
import com.android.wm.shell.back.BackAnimation;
import com.android.wm.shell.bubbles.Bubbles;
import com.android.wm.shell.common.annotations.ShellMainThread;
@@ -37,7 +36,6 @@
import com.android.wm.shell.displayareahelper.DisplayAreaHelper;
import com.android.wm.shell.draganddrop.DragAndDrop;
import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout;
-import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import com.android.wm.shell.onehanded.OneHanded;
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.recents.RecentTasks;
@@ -96,15 +94,9 @@
Optional<Pip> getPip();
@WMSingleton
- Optional<LegacySplitScreen> getLegacySplitScreen();
-
- @WMSingleton
Optional<SplitScreen> getSplitScreen();
@WMSingleton
- Optional<AppPairs> getAppPairs();
-
- @WMSingleton
Optional<Bubbles> getBubbles();
@WMSingleton
diff --git a/packages/SystemUI/src/com/android/systemui/decor/OverlayWindow.kt b/packages/SystemUI/src/com/android/systemui/decor/OverlayWindow.kt
index d775ad3..3c0748e 100644
--- a/packages/SystemUI/src/com/android/systemui/decor/OverlayWindow.kt
+++ b/packages/SystemUI/src/com/android/systemui/decor/OverlayWindow.kt
@@ -16,11 +16,13 @@
package com.android.systemui.decor
import android.annotation.IdRes
+import android.annotation.NonNull
import android.content.Context
import android.view.Surface
import android.view.View
import android.view.ViewGroup
import com.android.systemui.RegionInterceptingFrameLayout
+import java.io.PrintWriter
class OverlayWindow(private val context: Context) {
@@ -100,4 +102,13 @@
}
}
}
+
+ fun dump(@NonNull pw: PrintWriter, name: String) {
+ pw.println(" $name=")
+ pw.println(" rootView=$rootView")
+ for (i in 0 until rootView.childCount) {
+ val child = rootView.getChildAt(i)
+ pw.println(" child[$i]=$child")
+ }
+ }
}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java
index c1dff24..cd23f14 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java
@@ -17,10 +17,14 @@
package com.android.systemui.dreams.dagger;
import android.content.Context;
+import android.content.res.Resources;
import com.android.settingslib.dream.DreamBackend;
+import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dreams.complication.dagger.RegisteredComplicationsModule;
+import javax.inject.Named;
+
import dagger.Module;
import dagger.Provides;
@@ -34,6 +38,10 @@
DreamOverlayComponent.class,
})
public interface DreamModule {
+ String DREAM_ONLY_ENABLED_FOR_SYSTEM_USER = "dream_only_enabled_for_system_user";
+
+ String DREAM_SUPPORTED = "dream_supported";
+
/**
* Provides an instance of the dream backend.
*/
@@ -41,4 +49,19 @@
static DreamBackend providesDreamBackend(Context context) {
return DreamBackend.getInstance(context);
}
+
+ /** */
+ @Provides
+ @Named(DREAM_ONLY_ENABLED_FOR_SYSTEM_USER)
+ static boolean providesDreamOnlyEnabledForSystemUser(@Main Resources resources) {
+ return resources.getBoolean(
+ com.android.internal.R.bool.config_dreamsOnlyEnabledForSystemUser);
+ }
+
+ /** */
+ @Provides
+ @Named(DREAM_SUPPORTED)
+ static boolean providesDreamSupported(@Main Resources resources) {
+ return resources.getBoolean(com.android.internal.R.bool.config_dreamsSupported);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.java b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
index c62c0bf..55bbcb6 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
@@ -151,7 +151,7 @@
/***************************************/
// 900 - media
public static final BooleanFlag MEDIA_TAP_TO_TRANSFER = new BooleanFlag(900, true);
- public static final BooleanFlag MEDIA_SESSION_ACTIONS = new BooleanFlag(901, true);
+ public static final BooleanFlag MEDIA_SESSION_ACTIONS = new BooleanFlag(901, false);
public static final BooleanFlag MEDIA_NEARBY_DEVICES = new BooleanFlag(903, true);
public static final BooleanFlag MEDIA_MUTE_AWAIT = new BooleanFlag(904, true);
@@ -166,6 +166,13 @@
public static final SysPropBooleanFlag WM_ENABLE_SHELL_TRANSITIONS =
new SysPropBooleanFlag(1100, "persist.wm.debug.shell_transit", false);
+ /**
+ * b/170163464: animate bubbles expanded view collapse with home gesture
+ */
+ @Keep
+ public static final SysPropBooleanFlag BUBBLES_HOME_GESTURE =
+ new SysPropBooleanFlag(1101, "persist.wm.debug.bubbles_home_gesture", false);
+
// 1200 - predictive back
@Keep
public static final SysPropBooleanFlag WM_ENABLE_PREDICTIVE_BACK = new SysPropBooleanFlag(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
index 14a7e3c..6dfc5e1 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
@@ -44,6 +44,7 @@
import com.android.systemui.shared.system.smartspace.ILauncherUnlockAnimationController
import com.android.systemui.shared.system.smartspace.ISysuiUnlockAnimationController
import com.android.systemui.shared.system.smartspace.SmartspaceState
+import com.android.systemui.statusbar.NotificationShadeWindowController
import com.android.systemui.statusbar.SysuiStatusBarStateController
import com.android.systemui.statusbar.phone.BiometricUnlockController
import com.android.systemui.statusbar.policy.KeyguardStateController
@@ -142,7 +143,8 @@
private val keyguardViewController: KeyguardViewController,
private val featureFlags: FeatureFlags,
private val biometricUnlockControllerLazy: Lazy<BiometricUnlockController>,
- private val statusBarStateController: SysuiStatusBarStateController
+ private val statusBarStateController: SysuiStatusBarStateController,
+ private val notificationShadeWindowController: NotificationShadeWindowController
) : KeyguardStateController.Callback, ISysuiUnlockAnimationController.Stub() {
interface KeyguardUnlockAnimationListener {
@@ -362,6 +364,9 @@
*/
fun canPerformInWindowLauncherAnimations(): Boolean {
return isNexusLauncherUnderneath() &&
+ // If the launcher is underneath, but we're about to launch an activity, don't do
+ // the animations since they won't be visible.
+ !notificationShadeWindowController.isLaunchingActivity &&
launcherUnlockController != null &&
!keyguardStateController.isDismissingFromSwipe &&
// Temporarily disable for foldables since foldable launcher has two first pages,
@@ -413,7 +418,6 @@
(lockscreenSmartspace as BcSmartspaceDataPlugin.SmartspaceView?)?.selectedPage ?: -1
try {
-
// Let the launcher know to prepare for this animation.
launcherUnlockController?.prepareForUnlock(
willUnlockWithSmartspaceTransition, /* willAnimateSmartspace */
@@ -857,6 +861,13 @@
}
/**
+ * Whether the RemoteAnimation on the app/launcher surface behind the keyguard is 'running'.
+ */
+ fun isAnimatingBetweenKeyguardAndSurfaceBehind(): Boolean {
+ return keyguardViewMediator.get().isAnimatingBetweenKeyguardAndSurfaceBehind
+ }
+
+ /**
* Whether we are playing a canned unlock animation, vs. unlocking from a touch gesture such as
* a swipe.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index cb12f6f..faf1863 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -2619,6 +2619,9 @@
// The remote animation is over, so we're not going away anymore.
mKeyguardStateController.notifyKeyguardGoingAway(false);
+
+ // Dispatch the callback on animation finishes.
+ mUpdateMonitor.dispatchKeyguardDismissAnimationFinished();
});
mKeyguardUnlockAnimationControllerLazy.get().notifyFinishedKeyguardExitAnimation(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java
index e6b650b..546a409 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java
@@ -17,23 +17,22 @@
package com.android.systemui.keyguard;
import static android.app.ActivityManager.TaskDescription;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.WORK_LOCK_ACCESSIBILITY;
-import android.annotation.ColorInt;
import android.annotation.UserIdInt;
import android.app.Activity;
import android.app.ActivityOptions;
import android.app.KeyguardManager;
import android.app.PendingIntent;
-import android.app.admin.DevicePolicyManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.graphics.Color;
+import android.content.pm.PackageManager;
+import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.UserHandle;
-import android.view.View;
+import android.os.UserManager;
+import android.widget.ImageView;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.R;
@@ -52,12 +51,6 @@
public class WorkLockActivity extends Activity {
private static final String TAG = "WorkLockActivity";
- /**
- * Contains a {@link TaskDescription} for the activity being covered.
- */
- static final String EXTRA_TASK_DESCRIPTION =
- "com.android.systemui.keyguard.extra.TASK_DESCRIPTION";
-
private static final int REQUEST_CODE_CONFIRM_CREDENTIALS = 1;
/**
@@ -65,12 +58,17 @@
* @see KeyguardManager
*/
private KeyguardManager mKgm;
+ private UserManager mUserManager;
+ private PackageManager mPackageManager;
private final BroadcastDispatcher mBroadcastDispatcher;
@Inject
- public WorkLockActivity(BroadcastDispatcher broadcastDispatcher) {
+ public WorkLockActivity(BroadcastDispatcher broadcastDispatcher, UserManager userManager,
+ PackageManager packageManager) {
super();
mBroadcastDispatcher = broadcastDispatcher;
+ mUserManager = userManager;
+ mPackageManager = packageManager;
}
@Override
@@ -91,15 +89,28 @@
// Draw captions overlaid on the content view, so the whole window is one solid color.
setOverlayWithDecorCaptionEnabled(true);
- // Blank out the activity. When it is on-screen it will look like a Recents thumbnail with
- // redaction switched on.
- final DevicePolicyManager dpm = getSystemService(DevicePolicyManager.class);
- String contentDescription = dpm.getResources().getString(
- WORK_LOCK_ACCESSIBILITY, () -> getString(R.string.accessibility_desc_work_lock));
- final View blankView = new View(this);
- blankView.setContentDescription(contentDescription);
- blankView.setBackgroundColor(getPrimaryColor());
- setContentView(blankView);
+ // Add background protection that contains a badged icon of the app being opened.
+ setContentView(R.layout.auth_biometric_background);
+ Drawable badgedIcon = getBadgedIcon();
+ if (badgedIcon != null) {
+ ((ImageView) findViewById(R.id.icon)).setImageDrawable(badgedIcon);
+ }
+ }
+
+ @VisibleForTesting
+ protected Drawable getBadgedIcon() {
+ String packageName = getIntent().getStringExtra(Intent.EXTRA_PACKAGE_NAME);
+ if (!packageName.isEmpty()) {
+ try {
+ return mUserManager.getBadgedIconForUser(mPackageManager.getApplicationIcon(
+ mPackageManager.getApplicationInfoAsUser(packageName,
+ PackageManager.ApplicationInfoFlags.of(0), getTargetUserId())),
+ UserHandle.of(getTargetUserId()));
+ } catch (PackageManager.NameNotFoundException e) {
+ // Unable to set the badged icon, show the background protection without an icon.
+ }
+ }
+ return null;
}
/**
@@ -208,19 +219,4 @@
final int getTargetUserId() {
return getIntent().getIntExtra(Intent.EXTRA_USER_ID, UserHandle.myUserId());
}
-
- @VisibleForTesting
- @ColorInt
- final int getPrimaryColor() {
- final TaskDescription taskDescription = (TaskDescription)
- getIntent().getExtra(EXTRA_TASK_DESCRIPTION);
- if (taskDescription != null && Color.alpha(taskDescription.getPrimaryColor()) == 255) {
- return taskDescription.getPrimaryColor();
- } else {
- // No task description. Use an organization color set by the policy controller.
- final DevicePolicyManager devicePolicyManager = (DevicePolicyManager)
- getSystemService(Context.DEVICE_POLICY_SERVICE);
- return devicePolicyManager.getOrganizationColorForUser(getTargetUserId());
- }
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java
index 7585110..16817ed 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java
@@ -52,22 +52,17 @@
tscl.registerTaskStackListener(mLockListener);
}
- private void startWorkChallengeInTask(int taskId, int userId) {
- ActivityManager.TaskDescription taskDescription = null;
- try {
- taskDescription = mIatm.getTaskDescription(taskId);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to get description for task=" + taskId);
- }
+ private void startWorkChallengeInTask(ActivityManager.RunningTaskInfo info) {
+ String packageName = info.baseActivity != null ? info.baseActivity.getPackageName() : "";
Intent intent = new Intent(KeyguardManager.ACTION_CONFIRM_DEVICE_CREDENTIAL_WITH_USER)
.setComponent(new ComponentName(mContext, WorkLockActivity.class))
- .putExtra(Intent.EXTRA_USER_ID, userId)
- .putExtra(WorkLockActivity.EXTRA_TASK_DESCRIPTION, taskDescription)
+ .putExtra(Intent.EXTRA_USER_ID, info.userId)
+ .putExtra(Intent.EXTRA_PACKAGE_NAME, packageName)
.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT
| Intent.FLAG_ACTIVITY_CLEAR_TOP);
final ActivityOptions options = ActivityOptions.makeBasic();
- options.setLaunchTaskId(taskId);
+ options.setLaunchTaskId(info.taskId);
options.setTaskOverlay(true, false /* canResume */);
final int result = startActivityAsUser(intent, options.toBundle(), UserHandle.USER_CURRENT);
@@ -77,9 +72,9 @@
// Starting the activity inside the task failed. We can't be sure why, so to be
// safe just remove the whole task if it still exists.
try {
- mIatm.removeTask(taskId);
+ mIatm.removeTask(info.taskId);
} catch (RemoteException e) {
- Log.w(TAG, "Failed to get description for task=" + taskId);
+ Log.w(TAG, "Failed to get description for task=" + info.taskId);
}
}
}
@@ -112,8 +107,8 @@
private final TaskStackChangeListener mLockListener = new TaskStackChangeListener() {
@Override
- public void onTaskProfileLocked(int taskId, int userId) {
- startWorkChallengeInTask(taskId, userId);
+ public void onTaskProfileLocked(ActivityManager.RunningTaskInfo info) {
+ startWorkChallengeInTask(info);
}
};
}
diff --git a/packages/SystemUI/src/com/android/systemui/log/LogBuffer.kt b/packages/SystemUI/src/com/android/systemui/log/LogBuffer.kt
index 25effec..db446c3 100644
--- a/packages/SystemUI/src/com/android/systemui/log/LogBuffer.kt
+++ b/packages/SystemUI/src/com/android/systemui/log/LogBuffer.kt
@@ -19,13 +19,14 @@
import android.os.Trace
import android.util.Log
import com.android.systemui.log.dagger.LogModule
+import com.android.systemui.util.collection.RingBuffer
import java.io.PrintWriter
import java.text.SimpleDateFormat
-import java.util.ArrayDeque
import java.util.Locale
import java.util.concurrent.ArrayBlockingQueue
import java.util.concurrent.BlockingQueue
import kotlin.concurrent.thread
+import kotlin.math.max
/**
* A simple ring buffer of recyclable log messages
@@ -63,29 +64,22 @@
*
* Buffers are provided by [LogModule]. Instances should be created using a [LogBufferFactory].
*
- * @param name The name of this buffer
- * @param maxLogs The maximum number of messages to keep in memory at any one time, including the
- * unused pool. Must be >= [poolSize].
- * @param poolSize The maximum amount that the size of the buffer is allowed to flex in response to
- * sequential calls to [document] that aren't immediately followed by a matching call to [push].
+ * @param name The name of this buffer, printed when the buffer is dumped and in some other
+ * situations.
+ * @param maxSize The maximum number of messages to keep in memory at any one time. Buffers start
+ * out empty and grow up to [maxSize] as new messages are logged. Once the buffer's size reaches
+ * the maximum, it behaves like a ring buffer.
*/
class LogBuffer @JvmOverloads constructor(
private val name: String,
- private val maxLogs: Int,
- private val poolSize: Int,
+ private val maxSize: Int,
private val logcatEchoTracker: LogcatEchoTracker,
private val systrace: Boolean = true
) {
- init {
- if (maxLogs < poolSize) {
- throw IllegalArgumentException("maxLogs must be greater than or equal to poolSize, " +
- "but maxLogs=$maxLogs < $poolSize=poolSize")
- }
- }
+ private val buffer = RingBuffer(maxSize) { LogMessageImpl.create() }
- private val buffer: ArrayDeque<LogMessageImpl> = ArrayDeque()
- private val echoMessageQueue: BlockingQueue<LogMessageImpl>? =
- if (logcatEchoTracker.logInBackgroundThread) ArrayBlockingQueue(poolSize) else null
+ private val echoMessageQueue: BlockingQueue<LogMessage>? =
+ if (logcatEchoTracker.logInBackgroundThread) ArrayBlockingQueue(10) else null
init {
if (logcatEchoTracker.logInBackgroundThread && echoMessageQueue != null) {
@@ -104,6 +98,9 @@
var frozen = false
private set
+ private val mutable
+ get() = !frozen && maxSize > 0
+
/**
* Logs a message to the log buffer
*
@@ -138,34 +135,19 @@
initializer: LogMessage.() -> Unit,
noinline printer: LogMessage.() -> String
) {
- if (!frozen) {
- val message = obtain(tag, level, printer)
- initializer(message)
- push(message)
- }
- }
-
- /**
- * Same as [log], but doesn't push the message to the buffer. Useful if you need to supply a
- * "reason" for doing something (the thing you supply the reason to will presumably call [push]
- * on that message at some point).
- */
- inline fun document(
- tag: String,
- level: LogLevel,
- initializer: LogMessage.() -> Unit,
- noinline printer: LogMessage.() -> String
- ): LogMessage {
val message = obtain(tag, level, printer)
initializer(message)
- return message
+ commit(message)
}
/**
- * Obtains an instance of [LogMessageImpl], usually from the object pool. If the pool has been
- * exhausted, creates a new instance.
+ * You should call [log] instead of this method.
*
- * In general, you should call [log] or [document] instead of this method.
+ * Obtains the next [LogMessage] from the ring buffer. If the buffer is not yet at max size,
+ * grows the buffer by one.
+ *
+ * After calling [obtain], the message will now be at the end of the buffer. The caller must
+ * store any relevant data on the message and then call [commit].
*/
@Synchronized
fun obtain(
@@ -173,28 +155,26 @@
level: LogLevel,
printer: (LogMessage) -> String
): LogMessageImpl {
- val message = when {
- frozen -> LogMessageImpl.create()
- buffer.size > maxLogs - poolSize -> buffer.removeFirst()
- else -> LogMessageImpl.create()
+ if (!mutable) {
+ return FROZEN_MESSAGE
}
+ val message = buffer.advance()
message.reset(tag, level, System.currentTimeMillis(), printer)
return message
}
/**
- * Pushes a message into buffer, possibly evicting an older message if the buffer is full.
+ * You should call [log] instead of this method.
+ *
+ * After acquiring a message via [obtain], call this method to signal to the buffer that you
+ * have finished filling in its data fields. The message will be echoed to logcat if
+ * necessary.
*/
@Synchronized
- fun push(message: LogMessage) {
- if (frozen) {
+ fun commit(message: LogMessage) {
+ if (!mutable) {
return
}
- if (buffer.size == maxLogs) {
- Log.e(TAG, "LogBuffer $name has exceeded its pool size")
- buffer.removeFirst()
- }
- buffer.add(message as LogMessageImpl)
// Log in the background thread only if echoMessageQueue exists and has capacity (checking
// capacity avoids the possibility of blocking this thread)
if (echoMessageQueue != null && echoMessageQueue.remainingCapacity() > 0) {
@@ -210,7 +190,7 @@
}
/** Sends message to echo after determining whether to use Logcat and/or systrace. */
- private fun echoToDesiredEndpoints(message: LogMessageImpl) {
+ private fun echoToDesiredEndpoints(message: LogMessage) {
val includeInLogcat = logcatEchoTracker.isBufferLoggable(name, message.level) ||
logcatEchoTracker.isTagLoggable(message.tag, message.level)
echo(message, toLogcat = includeInLogcat, toSystrace = systrace)
@@ -219,19 +199,17 @@
/** Converts the entire buffer to a newline-delimited string */
@Synchronized
fun dump(pw: PrintWriter, tailLength: Int) {
- val start = if (tailLength <= 0) { 0 } else { buffer.size - tailLength }
+ val iterationStart = if (tailLength <= 0) { 0 } else { max(0, buffer.size - tailLength) }
- for ((i, message) in buffer.withIndex()) {
- if (i >= start) {
- dumpMessage(message, pw)
- }
+ for (i in iterationStart until buffer.size) {
+ dumpMessage(buffer[i], pw)
}
}
/**
- * "Freezes" the contents of the buffer, making them immutable until [unfreeze] is called.
- * Calls to [log], [document], [obtain], and [push] will not affect the buffer and will return
- * dummy values if necessary.
+ * "Freezes" the contents of the buffer, making it immutable until [unfreeze] is called.
+ * Calls to [log], [obtain], and [commit] will not affect the buffer and will return dummy
+ * values if necessary.
*/
@Synchronized
fun freeze() {
@@ -293,3 +271,4 @@
private const val TAG = "LogBuffer"
private val DATE_FORMAT = SimpleDateFormat("MM-dd HH:mm:ss.SSS", Locale.US)
+private val FROZEN_MESSAGE = LogMessageImpl.create()
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/log/LogBufferFactory.kt b/packages/SystemUI/src/com/android/systemui/log/LogBufferFactory.kt
index cbfca25..5651399 100644
--- a/packages/SystemUI/src/com/android/systemui/log/LogBufferFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/log/LogBufferFactory.kt
@@ -27,22 +27,21 @@
private val logcatEchoTracker: LogcatEchoTracker
) {
/* limit the size of maxPoolSize for low ram (Go) devices */
- private fun poolLimit(maxPoolSize_requested: Int): Int {
- if (ActivityManager.isLowRamDeviceStatic()) {
- return minOf(maxPoolSize_requested, 20) /* low ram max log size*/
+ private fun adjustMaxSize(requestedMaxSize: Int): Int {
+ return if (ActivityManager.isLowRamDeviceStatic()) {
+ minOf(requestedMaxSize, 20) /* low ram max log size*/
} else {
- return maxPoolSize_requested
+ requestedMaxSize
}
}
@JvmOverloads
fun create(
name: String,
- maxPoolSize: Int,
- flexSize: Int = 10,
+ maxSize: Int,
systrace: Boolean = true
): LogBuffer {
- val buffer = LogBuffer(name, poolLimit(maxPoolSize), flexSize, logcatEchoTracker, systrace)
+ val buffer = LogBuffer(name, adjustMaxSize(maxSize), logcatEchoTracker, systrace)
dumpManager.registerBuffer(name, buffer)
return buffer
}
diff --git a/packages/SystemUI/src/com/android/systemui/log/LogcatEchoTrackerDebug.kt b/packages/SystemUI/src/com/android/systemui/log/LogcatEchoTrackerDebug.kt
index 91734cc..40b0cdc 100644
--- a/packages/SystemUI/src/com/android/systemui/log/LogcatEchoTrackerDebug.kt
+++ b/packages/SystemUI/src/com/android/systemui/log/LogcatEchoTrackerDebug.kt
@@ -60,7 +60,7 @@
Settings.Global.getUriFor(BUFFER_PATH),
true,
object : ContentObserver(Handler(mainLooper)) {
- override fun onChange(selfChange: Boolean, uri: Uri) {
+ override fun onChange(selfChange: Boolean, uri: Uri?) {
super.onChange(selfChange, uri)
cachedBufferLevels.clear()
}
@@ -70,7 +70,7 @@
Settings.Global.getUriFor(TAG_PATH),
true,
object : ContentObserver(Handler(mainLooper)) {
- override fun onChange(selfChange: Boolean, uri: Uri) {
+ override fun onChange(selfChange: Boolean, uri: Uri?) {
super.onChange(selfChange, uri)
cachedTagLevels.clear()
}
@@ -110,7 +110,7 @@
}
private fun parseProp(propValue: String?): LogLevel {
- return when (propValue?.toLowerCase()) {
+ return when (propValue?.lowercase()) {
"verbose" -> LogLevel.VERBOSE
"v" -> LogLevel.VERBOSE
"debug" -> LogLevel.DEBUG
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
index f72f1bb..eff025f 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
@@ -49,8 +49,7 @@
@SysUISingleton
@NotificationLog
public static LogBuffer provideNotificationsLogBuffer(LogBufferFactory factory) {
- return factory.create("NotifLog", 1000 /* maxPoolSize */,
- 10 /* flexSize */, false /* systrace */);
+ return factory.create("NotifLog", 1000 /* maxSize */, false /* systrace */);
}
/** Provides a logging buffer for all logs related to the data layer of notifications. */
@@ -74,8 +73,7 @@
@SysUISingleton
@NotificationSectionLog
public static LogBuffer provideNotificationSectionLogBuffer(LogBufferFactory factory) {
- return factory.create("NotifSectionLog", 1000 /* maxPoolSize */,
- 10 /* flexSize */, false /* systrace */);
+ return factory.create("NotifSectionLog", 1000 /* maxSize */, false /* systrace */);
}
/** Provides a logging buffer for all logs related to the data layer of notifications. */
@@ -91,8 +89,7 @@
@SysUISingleton
@QSLog
public static LogBuffer provideQuickSettingsLogBuffer(LogBufferFactory factory) {
- return factory.create("QSLog", 500 /* maxPoolSize */,
- 10 /* flexSize */, false /* systrace */);
+ return factory.create("QSLog", 500 /* maxSize */, false /* systrace */);
}
/** Provides a logging buffer for {@link com.android.systemui.broadcast.BroadcastDispatcher} */
@@ -100,8 +97,8 @@
@SysUISingleton
@BroadcastDispatcherLog
public static LogBuffer provideBroadcastDispatcherLogBuffer(LogBufferFactory factory) {
- return factory.create("BroadcastDispatcherLog", 500 /* maxPoolSize */,
- 10 /* flexSize */, false /* systrace */);
+ return factory.create("BroadcastDispatcherLog", 500 /* maxSize */,
+ false /* systrace */);
}
/** Provides a logging buffer for all logs related to Toasts shown by SystemUI. */
@@ -139,8 +136,8 @@
@SysUISingleton
@QSFragmentDisableLog
public static LogBuffer provideQSFragmentDisableLogBuffer(LogBufferFactory factory) {
- return factory.create("QSFragmentDisableFlagsLog", 10 /* maxPoolSize */,
- 10 /* flexSize */, false /* systrace */);
+ return factory.create("QSFragmentDisableFlagsLog", 10 /* maxSize */,
+ false /* systrace */);
}
/**
@@ -230,6 +227,18 @@
return factory.create("MediaBrowser", 100);
}
+ /**
+ * Provides a buffer for updates to the media carousel.
+ *
+ * See {@link com.android.systemui.media.MediaCarouselController}.
+ */
+ @Provides
+ @SysUISingleton
+ @MediaCarouselControllerLog
+ public static LogBuffer provideMediaCarouselControllerBuffer(LogBufferFactory factory) {
+ return factory.create("MediaCarouselCtlrLog", 20);
+ }
+
/** Allows logging buffers to be tweaked via adb on debug builds but not on prod builds. */
@Provides
@SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/MediaCarouselControllerLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/MediaCarouselControllerLog.java
new file mode 100644
index 0000000..b03655a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/MediaCarouselControllerLog.java
@@ -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.log.dagger;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import com.android.systemui.log.LogBuffer;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+
+import javax.inject.Qualifier;
+
+/**
+ * A {@link LogBuffer} for {@link com.android.systemui.media.MediaCarouselController}
+ */
+@Qualifier
+@Documented
+@Retention(RUNTIME)
+public @interface MediaCarouselControllerLog {
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
index 3483bc3..8a104c4 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
@@ -59,7 +59,8 @@
falsingCollector: FalsingCollector,
falsingManager: FalsingManager,
dumpManager: DumpManager,
- private val logger: MediaUiEventLogger
+ private val logger: MediaUiEventLogger,
+ private val debugLogger: MediaCarouselControllerLogger
) : Dumpable {
/**
* The current width of the carousel
@@ -439,12 +440,16 @@
newPlayer.mediaViewHolder?.player?.setLayoutParams(lp)
newPlayer.bindPlayer(data, key)
newPlayer.setListening(currentlyExpanded)
- MediaPlayerData.addMediaPlayer(key, data, newPlayer, systemClock, isSsReactivated)
+ MediaPlayerData.addMediaPlayer(
+ key, data, newPlayer, systemClock, isSsReactivated, debugLogger
+ )
updatePlayerToState(newPlayer, noAnimation = true)
reorderAllPlayers(curVisibleMediaKey)
} else {
existingPlayer.bindPlayer(data, key)
- MediaPlayerData.addMediaPlayer(key, data, existingPlayer, systemClock, isSsReactivated)
+ MediaPlayerData.addMediaPlayer(
+ key, data, existingPlayer, systemClock, isSsReactivated, debugLogger
+ )
if (isReorderingAllowed || shouldScrollToActivePlayer) {
reorderAllPlayers(curVisibleMediaKey)
} else {
@@ -475,7 +480,8 @@
val existingSmartspaceMediaKey = MediaPlayerData.smartspaceMediaKey()
existingSmartspaceMediaKey?.let {
- MediaPlayerData.removeMediaPlayer(existingSmartspaceMediaKey)
+ val removedPlayer = MediaPlayerData.removeMediaPlayer(existingSmartspaceMediaKey)
+ removedPlayer?.run { debugLogger.logPotentialMemoryLeak(existingSmartspaceMediaKey) }
}
val newRecs = mediaControlPanelFactory.get()
@@ -488,7 +494,9 @@
newRecs.bindRecommendation(data)
val curVisibleMediaKey = MediaPlayerData.playerKeys()
.elementAtOrNull(mediaCarouselScrollHandler.visibleMediaIndex)
- MediaPlayerData.addMediaRecommendation(key, data, newRecs, shouldPrioritize, systemClock)
+ MediaPlayerData.addMediaRecommendation(
+ key, data, newRecs, shouldPrioritize, systemClock, debugLogger
+ )
updatePlayerToState(newRecs, noAnimation = true)
reorderAllPlayers(curVisibleMediaKey)
updatePageIndicator()
@@ -845,7 +853,8 @@
uid,
interactedSubcardRank,
interactedSubcardCardinality,
- receivedLatencyMillis
+ receivedLatencyMillis,
+ null // Media cards cannot have subcards.
)
/* ktlint-disable max-line-length */
if (DEBUG) {
@@ -882,7 +891,8 @@
override fun dump(pw: PrintWriter, args: Array<out String>) {
pw.apply {
println("keysNeedRemoval: $keysNeedRemoval")
- println("playerKeys: ${MediaPlayerData.playerKeys()}")
+ println("dataKeys: ${MediaPlayerData.dataKeys()}")
+ println("playerSortKeys: ${MediaPlayerData.playerKeys()}")
println("smartspaceMediaData: ${MediaPlayerData.smartspaceMediaData}")
println("shouldPrioritizeSs: ${MediaPlayerData.shouldPrioritizeSs}")
println("current size: $currentCarouselWidth x $currentCarouselHeight")
@@ -945,9 +955,13 @@
data: MediaData,
player: MediaControlPanel,
clock: SystemClock,
- isSsReactivated: Boolean
+ isSsReactivated: Boolean,
+ debugLogger: MediaCarouselControllerLogger? = null
) {
- removeMediaPlayer(key)
+ val removedPlayer = removeMediaPlayer(key)
+ if (removedPlayer != null && removedPlayer != player) {
+ debugLogger?.logPotentialMemoryLeak(key)
+ }
val sortKey = MediaSortKey(isSsMediaRec = false,
data, clock.currentTimeMillis(), isSsReactivated = isSsReactivated)
mediaData.put(key, sortKey)
@@ -959,10 +973,14 @@
data: SmartspaceMediaData,
player: MediaControlPanel,
shouldPrioritize: Boolean,
- clock: SystemClock
+ clock: SystemClock,
+ debugLogger: MediaCarouselControllerLogger? = null
) {
shouldPrioritizeSs = shouldPrioritize
- removeMediaPlayer(key)
+ val removedPlayer = removeMediaPlayer(key)
+ if (removedPlayer != null && removedPlayer != player) {
+ debugLogger?.logPotentialMemoryLeak(key)
+ }
val sortKey = MediaSortKey(isSsMediaRec = true,
EMPTY.copy(isPlaying = false), clock.currentTimeMillis(), isSsReactivated = true)
mediaData.put(key, sortKey)
@@ -970,13 +988,18 @@
smartspaceMediaData = data
}
- fun moveIfExists(oldKey: String?, newKey: String) {
+ fun moveIfExists(
+ oldKey: String?,
+ newKey: String,
+ debugLogger: MediaCarouselControllerLogger? = null
+ ) {
if (oldKey == null || oldKey == newKey) {
return
}
mediaData.remove(oldKey)?.let {
- removeMediaPlayer(newKey)
+ val removedPlayer = removeMediaPlayer(newKey)
+ removedPlayer?.run { debugLogger?.logPotentialMemoryLeak(newKey) }
mediaData.put(newKey, it)
}
}
@@ -1004,6 +1027,8 @@
fun mediaData() = mediaData.entries.map { e -> Triple(e.key, e.value.data, e.value.isSsMediaRec) }
+ fun dataKeys() = mediaData.keys
+
fun players() = mediaPlayers.values
fun playerKeys() = mediaPlayers.keys
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselControllerLogger.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselControllerLogger.kt
new file mode 100644
index 0000000..04ebd5a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselControllerLogger.kt
@@ -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 com.android.systemui.media
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
+import com.android.systemui.log.dagger.MediaCarouselControllerLog
+import javax.inject.Inject
+
+/** A debug logger for [MediaCarouselController]. */
+@SysUISingleton
+class MediaCarouselControllerLogger @Inject constructor(
+ @MediaCarouselControllerLog private val buffer: LogBuffer
+) {
+ /**
+ * Log that there might be a potential memory leak for the [MediaControlPanel] and/or
+ * [MediaViewController] related to [key].
+ */
+ fun logPotentialMemoryLeak(key: String) = buffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ { str1 = key },
+ {
+ "Potential memory leak: " +
+ "Removing control panel for $str1 from map without calling #onDestroy"
+ }
+ )
+}
+
+private const val TAG = "MediaCarouselCtlrLog"
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
index 8c2cb6d..6ef2504 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
@@ -75,6 +75,7 @@
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.media.dialog.MediaOutputDialogFactory;
import com.android.systemui.monet.ColorScheme;
+import com.android.systemui.monet.Style;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.shared.system.SysUiStatsLog;
@@ -627,7 +628,7 @@
if (artworkIcon != null) {
WallpaperColors wallpaperColors = WallpaperColors
.fromBitmap(artworkIcon.getBitmap());
- mutableColorScheme = new ColorScheme(wallpaperColors, true);
+ mutableColorScheme = new ColorScheme(wallpaperColors, true, Style.CONTENT);
artwork = getScaledBackground(artworkIcon, width, height);
isArtworkBound = true;
} else {
@@ -637,7 +638,8 @@
try {
Drawable icon = mContext.getPackageManager()
.getApplicationIcon(data.getPackageName());
- mutableColorScheme = new ColorScheme(WallpaperColors.fromDrawable(icon), true);
+ mutableColorScheme = new ColorScheme(WallpaperColors.fromDrawable(icon), true,
+ Style.CONTENT);
} catch (PackageManager.NameNotFoundException e) {
Log.w(TAG, "Cannot find icon for package " + data.getPackageName(), e);
}
@@ -674,10 +676,6 @@
mIsArtworkBound = isArtworkBound;
}
- // Scrim bounds are set manually so it scales as expected
- albumView.getForeground().setBounds(0, 0,
- Math.max(width, height), Math.max(width, height));
-
// Transition Colors to current color scheme
mColorSchemeTransition.updateColorScheme(colorScheme, mIsArtworkBound);
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataUtils.java b/packages/SystemUI/src/com/android/systemui/media/MediaDataUtils.java
new file mode 100644
index 0000000..b8185b9
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataUtils.java
@@ -0,0 +1,43 @@
+/**
+ * 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.media;
+
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.text.TextUtils;
+
+public class MediaDataUtils {
+
+ public static String getAppLabel(Context context, String packageName, String unknownName) {
+ if (TextUtils.isEmpty(packageName)) {
+ return null;
+ }
+ final PackageManager packageManager = context.getPackageManager();
+ ApplicationInfo applicationInfo;
+ try {
+ applicationInfo = packageManager.getApplicationInfo(packageName, 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ applicationInfo = null;
+ }
+ final String applicationName =
+ (String) (applicationInfo != null
+ ? packageManager.getApplicationLabel(applicationInfo)
+ : unknownName);
+ return applicationName;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt b/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt
index fc8d38d..d4c4f216 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt
@@ -22,8 +22,11 @@
import com.android.internal.annotations.VisibleForTesting
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.NotificationMediaManager.isPlayingState
+import com.android.systemui.statusbar.SysuiStatusBarStateController
import com.android.systemui.util.concurrency.DelayableExecutor
+import com.android.systemui.util.time.SystemClock
import java.util.concurrent.TimeUnit
import javax.inject.Inject
@@ -42,7 +45,9 @@
class MediaTimeoutListener @Inject constructor(
private val mediaControllerFactory: MediaControllerFactory,
@Main private val mainExecutor: DelayableExecutor,
- private val logger: MediaTimeoutLogger
+ private val logger: MediaTimeoutLogger,
+ statusBarStateController: SysuiStatusBarStateController,
+ private val systemClock: SystemClock
) : MediaDataManager.Listener {
private val mediaListeners: MutableMap<String, PlaybackStateListener> = mutableMapOf()
@@ -62,6 +67,24 @@
*/
lateinit var stateCallback: (String, PlaybackState) -> Unit
+ init {
+ statusBarStateController.addCallback(object : StatusBarStateController.StateListener {
+ override fun onDozingChanged(isDozing: Boolean) {
+ if (!isDozing) {
+ // Check whether any timeouts should have expired
+ mediaListeners.forEach { (key, listener) ->
+ if (listener.cancellation != null &&
+ listener.expiration <= systemClock.elapsedRealtime()) {
+ // We dozed too long - timeout now, and cancel the pending one
+ listener.expireMediaTimeout(key, "timeout happened while dozing")
+ listener.doTimeout()
+ }
+ }
+ }
+ }
+ })
+ }
+
override fun onMediaDataLoaded(
key: String,
oldKey: String?,
@@ -131,6 +154,7 @@
var lastState: PlaybackState? = null
var resumption: Boolean? = null
var destroyed = false
+ var expiration = Long.MAX_VALUE
var mediaData: MediaData = data
set(value) {
@@ -150,7 +174,8 @@
// Resume controls may have null token
private var mediaController: MediaController? = null
- private var cancellation: Runnable? = null
+ var cancellation: Runnable? = null
+ private set
fun Int.isPlaying() = isPlayingState(this)
fun isPlaying() = lastState?.state?.isPlaying() ?: false
@@ -216,12 +241,9 @@
} else {
PAUSED_MEDIA_TIMEOUT
}
+ expiration = systemClock.elapsedRealtime() + timeout
cancellation = mainExecutor.executeDelayed({
- cancellation = null
- logger.logTimeout(key)
- timedOut = true
- // this event is async, so it's safe even when `dispatchEvents` is false
- timeoutCallback(key, timedOut)
+ doTimeout()
}, timeout)
} else {
expireMediaTimeout(key, "playback started - $state, $key")
@@ -232,11 +254,21 @@
}
}
- private fun expireMediaTimeout(mediaKey: String, reason: String) {
+ fun doTimeout() {
+ cancellation = null
+ logger.logTimeout(key)
+ timedOut = true
+ expiration = Long.MAX_VALUE
+ // this event is async, so it's safe even when `dispatchEvents` is false
+ timeoutCallback(key, timedOut)
+ }
+
+ fun expireMediaTimeout(mediaKey: String, reason: String) {
cancellation?.apply {
logger.logTimeoutCancelled(mediaKey, reason)
run()
}
+ expiration = Long.MAX_VALUE
cancellation = null
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/ResumeMediaBrowser.java b/packages/SystemUI/src/com/android/systemui/media/ResumeMediaBrowser.java
index 4f598ff..40a5653 100644
--- a/packages/SystemUI/src/com/android/systemui/media/ResumeMediaBrowser.java
+++ b/packages/SystemUI/src/com/android/systemui/media/ResumeMediaBrowser.java
@@ -52,8 +52,10 @@
private final MediaBrowserFactory mBrowserFactory;
private final ResumeMediaBrowserLogger mLogger;
private final ComponentName mComponentName;
+ private final MediaController.Callback mMediaControllerCallback = new SessionDestroyCallback();
private MediaBrowser mMediaBrowser;
+ @Nullable private MediaController mMediaController;
/**
* Initialize a new media browser
@@ -90,6 +92,7 @@
mComponentName,
mConnectionCallback,
rootHints);
+ updateMediaController();
mLogger.logConnection(mComponentName, "findRecentMedia");
mMediaBrowser.connect();
}
@@ -154,7 +157,8 @@
@Override
public void onConnected() {
Log.d(TAG, "Service connected for " + mComponentName);
- if (mMediaBrowser != null && mMediaBrowser.isConnected()) {
+ updateMediaController();
+ if (isBrowserConnected()) {
String root = mMediaBrowser.getRoot();
if (!TextUtils.isEmpty(root)) {
if (mCallback != null) {
@@ -207,6 +211,7 @@
mMediaBrowser.disconnect();
}
mMediaBrowser = null;
+ updateMediaController();
}
/**
@@ -225,7 +230,8 @@
@Override
public void onConnected() {
Log.d(TAG, "Connected for restart " + mMediaBrowser.isConnected());
- if (mMediaBrowser == null || !mMediaBrowser.isConnected()) {
+ updateMediaController();
+ if (!isBrowserConnected()) {
if (mCallback != null) {
mCallback.onError();
}
@@ -259,6 +265,7 @@
disconnect();
}
}, rootHints);
+ updateMediaController();
mLogger.logConnection(mComponentName, "restart");
mMediaBrowser.connect();
}
@@ -273,7 +280,7 @@
* @return the token, or null if the MediaBrowser is null or disconnected
*/
public MediaSession.Token getToken() {
- if (mMediaBrowser == null || !mMediaBrowser.isConnected()) {
+ if (!isBrowserConnected()) {
return null;
}
return mMediaBrowser.getSessionToken();
@@ -305,10 +312,39 @@
mComponentName,
mConnectionCallback,
rootHints);
+ updateMediaController();
mLogger.logConnection(mComponentName, "testConnection");
mMediaBrowser.connect();
}
+ /** Updates mMediaController based on our current browser values. */
+ private void updateMediaController() {
+ MediaSession.Token controllerToken =
+ mMediaController != null ? mMediaController.getSessionToken() : null;
+ MediaSession.Token currentToken = getToken();
+ boolean areEqual = (controllerToken == null && currentToken == null)
+ || (controllerToken != null && controllerToken.equals(currentToken));
+ if (areEqual) {
+ return;
+ }
+
+ // Whenever the token changes, un-register the callback on the old controller (if we have
+ // one) and create a new controller with the callback attached.
+ if (mMediaController != null) {
+ mMediaController.unregisterCallback(mMediaControllerCallback);
+ }
+ if (currentToken != null) {
+ mMediaController = createMediaController(currentToken);
+ mMediaController.registerCallback(mMediaControllerCallback);
+ } else {
+ mMediaController = null;
+ }
+ }
+
+ private boolean isBrowserConnected() {
+ return mMediaBrowser != null && mMediaBrowser.isConnected();
+ }
+
/**
* Interface to handle results from ResumeMediaBrowser
*/
@@ -335,4 +371,12 @@
ResumeMediaBrowser browser) {
}
}
+
+ private class SessionDestroyCallback extends MediaController.Callback {
+ @Override
+ public void onSessionDestroyed() {
+ mLogger.logSessionDestroyed(isBrowserConnected(), mComponentName);
+ disconnect();
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/ResumeMediaBrowserLogger.kt b/packages/SystemUI/src/com/android/systemui/media/ResumeMediaBrowserLogger.kt
index ccc5edc..41f7354 100644
--- a/packages/SystemUI/src/com/android/systemui/media/ResumeMediaBrowserLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/ResumeMediaBrowserLogger.kt
@@ -48,6 +48,27 @@
},
{ "Disconnecting browser for component $str1" }
)
+
+ /**
+ * Logs that we received a [android.media.session.MediaController.Callback.onSessionDestroyed]
+ * event.
+ *
+ * @param isBrowserConnected true if there's a currently connected
+ * [android.media.browse.MediaBrowser] and false otherwise.
+ * @param componentName the component name for the [ResumeMediaBrowser] that triggered this log.
+ */
+ fun logSessionDestroyed(
+ isBrowserConnected: Boolean,
+ componentName: ComponentName
+ ) = buffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ {
+ bool1 = isBrowserConnected
+ str1 = componentName.toShortString()
+ },
+ { "Session destroyed. Active browser = $bool1. Browser component = $str1." }
+ )
}
private const val TAG = "MediaBrowser"
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 509bc38..b464436 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
@@ -76,6 +76,7 @@
private static final String PREF_NAME = "MediaOutputDialog";
private static final String PREF_IS_LE_BROADCAST_FIRST_LAUNCH = "PrefIsLeBroadcastFirstLaunch";
private static final boolean DEBUG = true;
+ private static final int HANDLE_BROADCAST_FAILED_DELAY = 3000;
private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper());
private final RecyclerView.LayoutManager mLayoutManager;
@@ -119,7 +120,7 @@
Log.d(TAG, "onBroadcastStarted(), reason = " + reason
+ ", broadcastId = " + broadcastId);
}
- mMainThreadHandler.post(() -> startLeBroadcastDialog());
+ mMainThreadHandler.post(() -> handleLeBroadcastStarted());
}
@Override
@@ -127,7 +128,8 @@
if (DEBUG) {
Log.d(TAG, "onBroadcastStartFailed(), reason = " + reason);
}
- handleLeBroadcastStartFailed();
+ mMainThreadHandler.postDelayed(() -> handleLeBroadcastStartFailed(),
+ HANDLE_BROADCAST_FAILED_DELAY);
}
@Override
@@ -137,7 +139,7 @@
Log.d(TAG, "onBroadcastMetadataChanged(), broadcastId = " + broadcastId
+ ", metadata = " + metadata);
}
- mMainThreadHandler.post(() -> refresh());
+ mMainThreadHandler.post(() -> handleLeBroadcastMetadataChanged());
}
@Override
@@ -146,7 +148,7 @@
Log.d(TAG, "onBroadcastStopped(), reason = " + reason
+ ", broadcastId = " + broadcastId);
}
- mMainThreadHandler.post(() -> refresh());
+ mMainThreadHandler.post(() -> handleLeBroadcastStopped());
}
@Override
@@ -154,7 +156,7 @@
if (DEBUG) {
Log.d(TAG, "onBroadcastStopFailed(), reason = " + reason);
}
- mMainThreadHandler.post(() -> refresh());
+ mMainThreadHandler.post(() -> handleLeBroadcastStopFailed());
}
@Override
@@ -163,7 +165,7 @@
Log.d(TAG, "onBroadcastUpdated(), reason = " + reason
+ ", broadcastId = " + broadcastId);
}
- mMainThreadHandler.post(() -> refresh());
+ mMainThreadHandler.post(() -> handleLeBroadcastUpdated());
}
@Override
@@ -172,7 +174,7 @@
Log.d(TAG, "onBroadcastUpdateFailed(), reason = " + reason
+ ", broadcastId = " + broadcastId);
}
- mMainThreadHandler.post(() -> refresh());
+ mMainThreadHandler.post(() -> handleLeBroadcastUpdateFailed());
}
@Override
@@ -368,10 +370,34 @@
Bitmap.createScaledBitmap(bitmap, size, size, false));
}
- protected void handleLeBroadcastStartFailed() {
+ public void handleLeBroadcastStarted() {
+ startLeBroadcastDialog();
+ }
+
+ public void handleLeBroadcastStartFailed() {
mStopButton.setText(R.string.media_output_broadcast_start_failed);
mStopButton.setEnabled(false);
- mMainThreadHandler.postDelayed(() -> refresh(), 3000);
+ refresh();
+ }
+
+ public void handleLeBroadcastMetadataChanged() {
+ refresh();
+ }
+
+ public void handleLeBroadcastStopped() {
+ refresh();
+ }
+
+ public void handleLeBroadcastStopFailed() {
+ refresh();
+ }
+
+ public void handleLeBroadcastUpdated() {
+ refresh();
+ }
+
+ public void handleLeBroadcastUpdateFailed() {
+ refresh();
}
protected void startLeBroadcast() {
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java
index dd4f1d6..8f06546 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java
@@ -61,6 +61,10 @@
private ImageView mBroadcastCodeEdit;
private AlertDialog mAlertDialog;
private TextView mBroadcastErrorMessage;
+ private int mRetryCount = 0;
+ private String mCurrentBroadcastName;
+ private String mCurrentBroadcastCode;
+ private boolean mIsStopbyUpdateBroadcastCode = false;
static final int METADATA_BROADCAST_NAME = 0;
static final int METADATA_BROADCAST_CODE = 1;
@@ -144,8 +148,6 @@
//init UI component
mBroadcastQrCodeView = getDialogView().requireViewById(R.id.qrcode_view);
- //Set the QR code view
- setQrCodeView();
mBroadcastNotify = getDialogView().requireViewById(R.id.broadcast_info);
mBroadcastNotify.setOnClickListener(v -> {
@@ -171,8 +173,16 @@
launchBroadcastUpdatedDialog(true, mBroadcastCode.getText().toString());
});
- mBroadcastName.setText(getBroadcastMetadataInfo(METADATA_BROADCAST_NAME));
- mBroadcastCode.setText(getBroadcastMetadataInfo(METADATA_BROADCAST_CODE));
+ refreshUi();
+ }
+
+ private void refreshUi() {
+ setQrCodeView();
+
+ mCurrentBroadcastName = getBroadcastMetadataInfo(METADATA_BROADCAST_NAME);
+ mCurrentBroadcastCode = getBroadcastMetadataInfo(METADATA_BROADCAST_CODE);
+ mBroadcastName.setText(mCurrentBroadcastName);
+ mBroadcastCode.setText(mCurrentBroadcastCode);
}
private void inflateBroadcastInfoArea() {
@@ -239,52 +249,99 @@
}
if (isBroadcastCode) {
- handleBroadcastCodeUpdated(updatedString);
+ /* If the user wants to update the Broadcast Code, the Broadcast session should be
+ * stopped then used the new Broadcast code to start the Broadcast.
+ */
+ mIsStopbyUpdateBroadcastCode = true;
+ mMediaOutputController.setBroadcastCode(updatedString);
+ if (!mMediaOutputController.stopBluetoothLeBroadcast()) {
+ handleLeBroadcastStopFailed();
+ return;
+ }
} else {
- handleBroadcastNameUpdated(updatedString);
+ /* If the user wants to update the Broadcast Name, we don't need to stop the Broadcast
+ * session. Only use the new Broadcast name to update the broadcast session.
+ */
+ mMediaOutputController.setBroadcastName(updatedString);
+ if (!mMediaOutputController.updateBluetoothLeBroadcast()) {
+ handleLeBroadcastUpdateFailed();
+ }
}
}
- private void handleBroadcastNameUpdated(String name) {
- // TODO(b/230473995) Add the retry mechanism and error handling when update fails
- String currentName = mMediaOutputController.getBroadcastName();
- int retryCount = MAX_BROADCAST_INFO_UPDATE;
- mMediaOutputController.setBroadcastName(name);
- if (!mMediaOutputController.updateBluetoothLeBroadcast()) {
- mMediaOutputController.setBroadcastName(currentName);
- handleLeUpdateBroadcastFailed(retryCount);
+ @Override
+ public void handleLeBroadcastStarted() {
+ mRetryCount = 0;
+ if (mAlertDialog != null) {
+ mAlertDialog.dismiss();
+ }
+ refreshUi();
+ }
+
+ @Override
+ public void handleLeBroadcastStartFailed() {
+ mMediaOutputController.setBroadcastCode(mCurrentBroadcastCode);
+ mRetryCount++;
+
+ handleUpdateFailedUi();
+ }
+
+ @Override
+ public void handleLeBroadcastMetadataChanged() {
+ refreshUi();
+ }
+
+ @Override
+ public void handleLeBroadcastUpdated() {
+ mRetryCount = 0;
+ if (mAlertDialog != null) {
+ mAlertDialog.dismiss();
+ }
+ refreshUi();
+ }
+
+ @Override
+ public void handleLeBroadcastUpdateFailed() {
+ //Change the value in shared preferences back to it original value
+ mMediaOutputController.setBroadcastName(mCurrentBroadcastName);
+ mRetryCount++;
+
+ handleUpdateFailedUi();
+ }
+
+ @Override
+ public void handleLeBroadcastStopped() {
+ if (mIsStopbyUpdateBroadcastCode) {
+ mIsStopbyUpdateBroadcastCode = false;
+ mRetryCount = 0;
+ if (!mMediaOutputController.startBluetoothLeBroadcast()) {
+ handleLeBroadcastStartFailed();
+ return;
+ }
+ } else {
+ dismiss();
}
}
- private void handleBroadcastCodeUpdated(String newPassword) {
- // TODO(b/230473995) Add the retry mechanism and error handling when update fails
- String currentPassword = mMediaOutputController.getBroadcastCode();
- int retryCount = MAX_BROADCAST_INFO_UPDATE;
- if (!mMediaOutputController.stopBluetoothLeBroadcast()) {
- mMediaOutputController.setBroadcastCode(currentPassword);
- handleLeUpdateBroadcastFailed(retryCount);
- return;
- }
+ @Override
+ public void handleLeBroadcastStopFailed() {
+ //Change the value in shared preferences back to it original value
+ mMediaOutputController.setBroadcastCode(mCurrentBroadcastCode);
+ mRetryCount++;
- mMediaOutputController.setBroadcastCode(newPassword);
- if (!mMediaOutputController.startBluetoothLeBroadcast()) {
- mMediaOutputController.setBroadcastCode(currentPassword);
- handleLeUpdateBroadcastFailed(retryCount);
- return;
- }
-
- mAlertDialog.dismiss();
+ handleUpdateFailedUi();
}
- private void handleLeUpdateBroadcastFailed(int retryCount) {
+ private void handleUpdateFailedUi() {
final Button positiveBtn = mAlertDialog.getButton(AlertDialog.BUTTON_POSITIVE);
mBroadcastErrorMessage.setVisibility(View.VISIBLE);
- if (retryCount < MAX_BROADCAST_INFO_UPDATE) {
+ if (mRetryCount < MAX_BROADCAST_INFO_UPDATE) {
if (positiveBtn != null) {
positiveBtn.setEnabled(true);
}
mBroadcastErrorMessage.setText(R.string.media_output_broadcast_update_error);
} else {
+ mRetryCount = 0;
mBroadcastErrorMessage.setText(R.string.media_output_broadcast_last_update_error);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarInflaterView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarInflaterView.java
index 4d9175b..59bb2278e 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarInflaterView.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarInflaterView.java
@@ -168,6 +168,7 @@
public void setButtonDispatchers(SparseArray<ButtonDispatcher> buttonDispatchers) {
mButtonDispatchers = buttonDispatchers;
+ clearDispatcherViews();
for (int i = 0; i < buttonDispatchers.size(); i++) {
initiallyFill(buttonDispatchers.valueAt(i));
}
@@ -454,12 +455,16 @@
}
}
- private void clearViews() {
+ private void clearDispatcherViews() {
if (mButtonDispatchers != null) {
for (int i = 0; i < mButtonDispatchers.size(); i++) {
mButtonDispatchers.valueAt(i).clear();
}
}
+ }
+
+ private void clearViews() {
+ clearDispatcherViews();
clearAllChildren(mHorizontal.findViewById(R.id.nav_buttons));
clearAllChildren(mVertical.findViewById(R.id.nav_buttons));
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
index ac6a8ff..3fc9afe 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
@@ -301,7 +301,7 @@
R.drawable.ic_sysbar_rotate_button_ccw_start_90,
R.drawable.ic_sysbar_rotate_button_cw_start_0,
R.drawable.ic_sysbar_rotate_button_cw_start_90,
- () -> getDisplay().getRotation());
+ () -> mCurrentRotation);
mConfiguration = new Configuration();
mTmpLastConfiguration = new Configuration();
@@ -473,6 +473,7 @@
mRotationButtonController.setRotationButton(mRotationContextButton,
mRotationButtonListener);
}
+ mNavigationInflaterView.setButtonDispatchers(mButtonDispatchers);
}
public KeyButtonDrawable getBackDrawable() {
@@ -876,15 +877,27 @@
return mCurrentRotation != rotation;
}
+ private void updateCurrentRotation() {
+ final int rotation = mConfiguration.windowConfiguration.getDisplayRotation();
+ if (mCurrentRotation == rotation) {
+ return;
+ }
+ mCurrentRotation = rotation;
+ mNavigationInflaterView.setAlternativeOrder(mCurrentRotation == Surface.ROTATION_90);
+ mDeadZone.onConfigurationChanged(mCurrentRotation);
+ if (DEBUG) {
+ Log.d(TAG, "updateCurrentRotation(): rot=" + mCurrentRotation);
+ }
+ }
+
private void updateCurrentView() {
resetViews();
mCurrentView = mIsVertical ? mVertical : mHorizontal;
mCurrentView.setVisibility(View.VISIBLE);
mNavigationInflaterView.setVertical(mIsVertical);
- mCurrentRotation = getContextDisplay().getRotation();
- mNavigationInflaterView.setAlternativeOrder(mCurrentRotation == Surface.ROTATION_90);
mNavigationInflaterView.updateButtonDispatchersCurrentView();
updateLayoutTransitionsEnabled();
+ updateCurrentRotation();
}
private void resetViews() {
@@ -917,17 +930,11 @@
public void reorient() {
updateCurrentView();
-
((NavigationBarFrame) getRootView()).setDeadZone(mDeadZone);
- mDeadZone.onConfigurationChanged(mCurrentRotation);
// force the low profile & disabled states into compliance
mBarTransitions.init();
- if (DEBUG) {
- Log.d(TAG, "reorient(): rot=" + mCurrentRotation);
- }
-
// Resolve layout direction if not resolved since components changing layout direction such
// as changing languages will recreate this view and the direction will be resolved later
if (!isLayoutDirectionResolved()) {
@@ -998,6 +1005,7 @@
boolean uiCarModeChanged = updateCarMode();
updateIcons(mTmpLastConfiguration);
updateRecentsIcon();
+ updateCurrentRotation();
mEdgeBackGestureHandler.onConfigurationChanged(mConfiguration);
if (uiCarModeChanged || mTmpLastConfiguration.densityDpi != mConfiguration.densityDpi
|| mTmpLastConfiguration.getLayoutDirection() != mConfiguration.getLayoutDirection()) {
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/KeyButtonView.java
index d27b716..622f5a2 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/KeyButtonView.java
@@ -273,9 +273,8 @@
mLongClicked = false;
setPressed(true);
- // Use raw X and Y to detect gestures in case a parent changes the x and y values
- mTouchDownX = (int) ev.getRawX();
- mTouchDownY = (int) ev.getRawY();
+ mTouchDownX = (int) ev.getX();
+ mTouchDownY = (int) ev.getY();
if (mCode != KEYCODE_UNKNOWN) {
sendEvent(KeyEvent.ACTION_DOWN, 0, mDownTime);
} else {
@@ -289,8 +288,8 @@
postDelayed(mCheckLongPress, ViewConfiguration.getLongPressTimeout());
break;
case MotionEvent.ACTION_MOVE:
- x = (int)ev.getRawX();
- y = (int)ev.getRawY();
+ x = (int) ev.getX();
+ y = (int) ev.getY();
float slop = QuickStepContract.getQuickStepTouchSlopPx(getContext());
if (Math.abs(x - mTouchDownX) > slop || Math.abs(y - mTouchDownY) > slop) {
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
index 001a462..ea41fe7 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
@@ -105,8 +105,7 @@
private static final int MAX_NUM_LOGGED_PREDICTIONS = 10;
private static final int MAX_NUM_LOGGED_GESTURES = 10;
- // Temporary log until b/202433017 is resolved
- static final boolean DEBUG_MISSING_GESTURE = true;
+ static final boolean DEBUG_MISSING_GESTURE = false;
static final String DEBUG_MISSING_GESTURE_TAG = "NoBackGesture";
private ISystemGestureExclusionListener mGestureExclusionListener =
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationHandle.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationHandle.java
index 33e6aa4..913b6528 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationHandle.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationHandle.java
@@ -36,8 +36,8 @@
protected final Paint mPaint = new Paint();
private @ColorInt final int mLightColor;
private @ColorInt final int mDarkColor;
- protected final int mRadius;
- protected final int mBottom;
+ protected final float mRadius;
+ protected final float mBottom;
private boolean mRequiresInvalidate;
public NavigationHandle(Context context) {
@@ -47,8 +47,8 @@
public NavigationHandle(Context context, AttributeSet attr) {
super(context, attr);
final Resources res = context.getResources();
- mRadius = res.getDimensionPixelSize(R.dimen.navigation_handle_radius);
- mBottom = res.getDimensionPixelSize(R.dimen.navigation_handle_bottom);
+ mRadius = res.getDimension(R.dimen.navigation_handle_radius);
+ mBottom = res.getDimension(R.dimen.navigation_handle_bottom);
final int dualToneDarkTheme = Utils.getThemeAttr(context, R.attr.darkIconTheme);
final int dualToneLightTheme = Utils.getThemeAttr(context, R.attr.lightIconTheme);
@@ -75,9 +75,9 @@
// Draw that bar
int navHeight = getHeight();
- int height = mRadius * 2;
+ float height = mRadius * 2;
int width = getWidth();
- int y = (navHeight - mBottom - height);
+ float y = (navHeight - mBottom - height);
canvas.drawRoundRect(0, y, width, y + height, mRadius, mRadius, mPaint);
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/QuickswitchOrientedNavHandle.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/QuickswitchOrientedNavHandle.java
index 71c8a2c..88622aa 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/QuickswitchOrientedNavHandle.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/QuickswitchOrientedNavHandle.java
@@ -44,33 +44,33 @@
}
public RectF computeHomeHandleBounds() {
- int left;
- int top;
- int bottom;
- int right;
- int radiusOffset = mRadius * 2;
+ float left;
+ float top;
+ float bottom;
+ float right;
+ float radiusOffset = mRadius * 2;
int topStart = getLocationOnScreen()[1];
switch (mDeltaRotation) {
default:
case Surface.ROTATION_0:
case Surface.ROTATION_180:
- int height = mRadius * 2;
- left = getWidth() / 2 - mWidth / 2;
+ float height = mRadius * 2;
+ left = getWidth() / 2f - mWidth / 2f;
top = (getHeight() - mBottom - height);
- right = getWidth() / 2 + mWidth / 2;
+ right = getWidth() / 2f + mWidth / 2f;
bottom = top + height;
break;
case Surface.ROTATION_90:
left = mBottom;
right = left + radiusOffset;
- top = getHeight() / 2 - (mWidth / 2) - (topStart / 2);
+ top = getHeight() / 2f - (mWidth / 2f) - (topStart / 2f);
bottom = top + mWidth;
break;
case Surface.ROTATION_270:
right = getWidth() - mBottom;
left = right - radiusOffset;
- top = getHeight() / 2 - (mWidth / 2) - (topStart / 2);
+ top = getHeight() / 2f - (mWidth / 2f) - (topStart / 2f);
bottom = top + mWidth;
break;
}
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
index dbdb9d2..cd6eb99 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
@@ -58,7 +58,8 @@
internal companion object {
val OPS_MIC_CAMERA = intArrayOf(AppOpsManager.OP_CAMERA,
AppOpsManager.OP_PHONE_CALL_CAMERA, AppOpsManager.OP_RECORD_AUDIO,
- AppOpsManager.OP_PHONE_CALL_MICROPHONE)
+ AppOpsManager.OP_PHONE_CALL_MICROPHONE,
+ AppOpsManager.OP_RECEIVE_AMBIENT_TRIGGER_AUDIO)
val OPS_LOCATION = intArrayOf(
AppOpsManager.OP_COARSE_LOCATION,
AppOpsManager.OP_FINE_LOCATION)
@@ -315,6 +316,7 @@
AppOpsManager.OP_COARSE_LOCATION,
AppOpsManager.OP_FINE_LOCATION -> PrivacyType.TYPE_LOCATION
AppOpsManager.OP_PHONE_CALL_MICROPHONE,
+ AppOpsManager.OP_RECEIVE_AMBIENT_TRIGGER_AUDIO,
AppOpsManager.OP_RECORD_AUDIO -> PrivacyType.TYPE_MICROPHONE
else -> return null
}
diff --git a/packages/SystemUI/src/com/android/systemui/qrcodescanner/controller/QRCodeScannerController.java b/packages/SystemUI/src/com/android/systemui/qrcodescanner/controller/QRCodeScannerController.java
index 8000bdc..2c20feb 100644
--- a/packages/SystemUI/src/com/android/systemui/qrcodescanner/controller/QRCodeScannerController.java
+++ b/packages/SystemUI/src/com/android/systemui/qrcodescanner/controller/QRCodeScannerController.java
@@ -29,7 +29,6 @@
import android.util.Log;
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
-import com.android.systemui.R;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.settings.UserTracker;
@@ -119,7 +118,6 @@
mSecureSettings = secureSettings;
mDeviceConfigProxy = proxy;
mUserTracker = userTracker;
-
mConfigEnableLockScreenButton = mContext.getResources().getBoolean(
android.R.bool.config_enableQrCodeScannerOnLockScreen);
}
@@ -258,16 +256,20 @@
}
}
+ private String getDefaultScannerActivity() {
+ return mContext.getResources().getString(
+ com.android.internal.R.string.config_defaultQrCodeComponent);
+ }
+
private void updateQRCodeScannerActivityDetails() {
String qrCodeScannerActivity = mDeviceConfigProxy.getString(
DeviceConfig.NAMESPACE_SYSTEMUI,
SystemUiDeviceConfigFlags.DEFAULT_QR_CODE_SCANNER, "");
// "" means either the flags is not available or is set to "", and in both the cases we
- // want to use R.string.def_qr_code_component
+ // want to use R.string.config_defaultQrCodeComponent
if (Objects.equals(qrCodeScannerActivity, "")) {
- qrCodeScannerActivity =
- mContext.getResources().getString(R.string.def_qr_code_component);
+ qrCodeScannerActivity = getDefaultScannerActivity();
}
String prevQrCodeScannerActivity = mQRCodeScannerActivity;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt b/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt
index 3e8cdf3..e5d7b400 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt
@@ -23,10 +23,12 @@
import android.content.Intent
import android.content.IntentFilter
import android.content.pm.PackageManager
+import android.content.pm.UserInfo
import android.graphics.drawable.Drawable
import android.os.IBinder
import android.os.PowerExemptionManager
import android.os.RemoteException
+import android.os.UserHandle
import android.provider.DeviceConfig.NAMESPACE_SYSTEMUI
import android.text.format.DateUtils
import android.util.ArrayMap
@@ -51,6 +53,7 @@
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.dump.DumpManager
import com.android.systemui.shared.system.SysUiStatsLog
+import com.android.systemui.settings.UserTracker
import com.android.systemui.statusbar.phone.SystemUIDialog
import com.android.systemui.util.DeviceConfigProxy
import com.android.systemui.util.indentIfPossible
@@ -69,6 +72,7 @@
private val systemClock: SystemClock,
private val activityManager: IActivityManager,
private val packageManager: PackageManager,
+ private val userTracker: UserTracker,
private val deviceConfigProxy: DeviceConfigProxy,
private val dialogLaunchAnimator: DialogLaunchAnimator,
private val broadcastDispatcher: BroadcastDispatcher,
@@ -82,7 +86,8 @@
var changesSinceDialog = false
private set
- private var isAvailable = false
+ var isAvailable = false
+ private set
private val lock = Any()
@@ -90,6 +95,12 @@
var initialized = false
@GuardedBy("lock")
+ private var lastNumberOfVisiblePackages = 0
+
+ @GuardedBy("lock")
+ private var currentProfileIds = mutableSetOf<Int>()
+
+ @GuardedBy("lock")
private val runningServiceTokens = mutableMapOf<UserPackage, StartTimeAndTokens>()
@GuardedBy("lock")
@@ -101,6 +112,19 @@
@GuardedBy("lock")
private var runningApps: ArrayMap<UserPackage, RunningApp> = ArrayMap()
+ private val userTrackerCallback = object : UserTracker.Callback {
+ override fun onUserChanged(newUser: Int, userContext: Context) {}
+
+ override fun onProfilesChanged(profiles: List<UserInfo>) {
+ synchronized(lock) {
+ currentProfileIds.clear()
+ currentProfileIds.addAll(profiles.map { it.id })
+ lastNumberOfVisiblePackages = 0
+ updateNumberOfVisibleRunningPackagesLocked()
+ }
+ }
+ }
+
interface OnNumberOfPackagesChangedListener {
fun onNumberOfPackagesChanged(numPackages: Int)
}
@@ -120,6 +144,10 @@
e.rethrowFromSystemServer()
}
+ userTracker.addCallback(userTrackerCallback, backgroundExecutor)
+
+ currentProfileIds.addAll(userTracker.userProfiles.map { it.id })
+
deviceConfigProxy.addOnPropertiesChangedListener(NAMESPACE_SYSTEMUI,
backgroundExecutor) {
isAvailable = it.getBoolean(TASK_MANAGER_ENABLED, isAvailable)
@@ -153,10 +181,9 @@
isForeground: Boolean
) {
synchronized(lock) {
- val numPackagesBefore = getNumRunningPackagesLocked()
val userPackageKey = UserPackage(userId, packageName)
if (isForeground) {
- runningServiceTokens.getOrPut(userPackageKey, { StartTimeAndTokens(systemClock) })
+ runningServiceTokens.getOrPut(userPackageKey) { StartTimeAndTokens(systemClock) }
.addToken(token)
} else {
if (runningServiceTokens[userPackageKey]?.also {
@@ -165,14 +192,7 @@
}
}
- val numPackagesAfter = getNumRunningPackagesLocked()
-
- if (numPackagesAfter != numPackagesBefore) {
- changesSinceDialog = true
- onNumberOfPackagesChangedListeners.forEach {
- backgroundExecutor.execute { it.onNumberOfPackagesChanged(numPackagesAfter) }
- }
- }
+ updateNumberOfVisibleRunningPackagesLocked()
updateAppItemsLocked()
}
@@ -209,18 +229,30 @@
}
}
- fun isAvailable(): Boolean {
- return isAvailable
- }
-
fun getNumRunningPackages(): Int {
synchronized(lock) {
- return getNumRunningPackagesLocked()
+ return getNumVisiblePackagesLocked()
}
}
- private fun getNumRunningPackagesLocked() =
- runningServiceTokens.keys.count { it.uiControl != UIControl.HIDE_ENTRY }
+ private fun getNumVisiblePackagesLocked(): Int {
+ return runningServiceTokens.keys.count {
+ it.uiControl != UIControl.HIDE_ENTRY && currentProfileIds.contains(it.userId)
+ }
+ }
+
+ private fun updateNumberOfVisibleRunningPackagesLocked() {
+ val num = getNumVisiblePackagesLocked()
+ if (num != lastNumberOfVisiblePackages) {
+ lastNumberOfVisiblePackages = num
+ changesSinceDialog = true
+ onNumberOfPackagesChangedListeners.forEach {
+ backgroundExecutor.execute {
+ it.onNumberOfPackagesChanged(num)
+ }
+ }
+ }
+ }
fun shouldUpdateFooterVisibility() = dialog == null
@@ -289,7 +321,9 @@
val ai = packageManager.getApplicationInfoAsUser(it.packageName, 0, it.userId)
runningApps[it] = RunningApp(it.userId, it.packageName,
runningServiceTokens[it]!!.startTime, it.uiControl,
- ai.loadLabel(packageManager), ai.loadIcon(packageManager))
+ packageManager.getApplicationLabel(ai),
+ packageManager.getUserBadgedIcon(
+ packageManager.getApplicationIcon(ai), UserHandle.of(it.userId)))
logEvent(stopped = false, it.packageName, it.userId, runningApps[it]!!.timeStarted)
}
@@ -404,6 +438,7 @@
val packageName: String
) {
val uid by lazy { packageManager.getPackageUidAsUser(packageName, userId) }
+ var backgroundRestrictionExemptionReason = PowerExemptionManager.REASON_DENIED
private var uiControlInitialized = false
var uiControl: UIControl = UIControl.NORMAL
@@ -416,7 +451,9 @@
private set
fun updateUiControl() {
- uiControl = when (activityManager.getBackgroundRestrictionExemptionReason(uid)) {
+ backgroundRestrictionExemptionReason =
+ activityManager.getBackgroundRestrictionExemptionReason(uid)
+ uiControl = when (backgroundRestrictionExemptionReason) {
PowerExemptionManager.REASON_SYSTEM_UID,
PowerExemptionManager.REASON_DEVICE_DEMO_MODE -> UIControl.HIDE_ENTRY
@@ -448,7 +485,7 @@
pw.indentIfPossible {
pw.println("userId=$userId")
pw.println("packageName=$packageName")
- pw.println("uiControl=$uiControl")
+ pw.println("uiControl=$uiControl (reason=$backgroundRestrictionExemptionReason)")
}
pw.println("]")
}
@@ -525,7 +562,7 @@
pw.println("userId=$userId")
pw.println("packageName=$packageName")
pw.println("timeStarted=$timeStarted (time since start =" +
- " ${systemClock.elapsedRealtime() - timeStarted}ms)\"")
+ " ${systemClock.elapsedRealtime() - timeStarted}ms)")
pw.println("uiControl=$uiControl")
pw.println("appLabel=$appLabel")
pw.println("icon=$icon")
@@ -542,6 +579,7 @@
override fun dump(printwriter: PrintWriter, args: Array<out String>) {
val pw = IndentingPrintWriter(printwriter)
synchronized(lock) {
+ pw.println("current user profiles = $currentProfileIds")
pw.println("changesSinceDialog=$changesSinceDialog")
pw.println("Running service tokens: [")
pw.indentIfPossible {
@@ -560,8 +598,10 @@
pw.indentIfPossible {
runningApps.forEach { (userPackage, runningApp) ->
pw.println("{")
- userPackage.dump(pw)
- runningApp.dump(pw, systemClock)
+ pw.indentIfPossible {
+ userPackage.dump(pw)
+ runningApp.dump(pw, systemClock)
+ }
pw.println("}")
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index f87cb29..f9bebc52 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -622,10 +622,11 @@
if (mLastQSExpansion == 1.0f) {
// Fully expanded, let's set the layout bounds as clip bounds. This is necessary because
// it's a scrollview and otherwise wouldn't be clipped. However, we set the horizontal
- // bounds so the pages go to the ends of QSContainerImpl
- ViewGroup.MarginLayoutParams lp =
- (ViewGroup.MarginLayoutParams) mQSPanelScrollView.getLayoutParams();
- mQsBounds.set(-lp.leftMargin, 0, mQSPanelScrollView.getWidth() + lp.rightMargin,
+ // bounds so the pages go to the ends of QSContainerImpl (most cases) or its parent
+ // (large screen portrait)
+ int sideMargin = getResources().getDimensionPixelSize(
+ R.dimen.qs_tiles_page_horizontal_margin) * 2;
+ mQsBounds.set(-sideMargin, 0, mQSPanelScrollView.getWidth() + sideMargin,
mQSPanelScrollView.getHeight());
}
mQSPanelScrollView.setClipBounds(mQsBounds);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
index dd99db4..584de6e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
@@ -22,6 +22,9 @@
import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_DIALOG_MANAGEMENT_NETWORK;
import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_DIALOG_MANAGEMENT_TITLE;
import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_DIALOG_MANAGEMENT_TWO_NAMED_VPN;
+import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_DIALOG_MONITORING_CA_CERT_SUBTITLE;
+import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_DIALOG_MONITORING_NETWORK_SUBTITLE;
+import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_DIALOG_MONITORING_VPN_SUBTITLE;
import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_DIALOG_NAMED_MANAGEMENT;
import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_DIALOG_PERSONAL_PROFILE_NAMED_VPN;
import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_DIALOG_VIEW_POLICIES;
@@ -92,6 +95,7 @@
import com.android.systemui.util.ViewController;
import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.Supplier;
import javax.inject.Inject;
import javax.inject.Named;
@@ -106,7 +110,7 @@
private final TextView mFooterText;
private final ImageView mPrimaryFooterIcon;
- private final Context mContext;
+ private Context mContext;
private final DevicePolicyManager mDpm;
private final Callback mCallback = new Callback();
private final SecurityController mSecurityController;
@@ -141,6 +145,63 @@
}
};
+ private Supplier<String> mManagementTitleSupplier = () ->
+ mContext == null ? null : mContext.getString(R.string.monitoring_title_device_owned);
+
+ private Supplier<String> mManagementMessageSupplier = () ->
+ mContext == null ? null : mContext.getString(
+ R.string.quick_settings_disclosure_management);
+
+ private Supplier<String> mManagementMonitoringStringSupplier = () ->
+ mContext == null ? null : mContext.getString(
+ R.string.quick_settings_disclosure_management_monitoring);
+
+ private Supplier<String> mManagementMultipleVpnStringSupplier = () ->
+ mContext == null ? null : mContext.getString(
+ R.string.quick_settings_disclosure_management_vpns);
+
+ private Supplier<String> mWorkProfileMonitoringStringSupplier = () ->
+ mContext == null ? null : mContext.getString(
+ R.string.quick_settings_disclosure_managed_profile_monitoring);
+
+ private Supplier<String> mWorkProfileNetworkStringSupplier = () ->
+ mContext == null ? null : mContext.getString(
+ R.string.quick_settings_disclosure_managed_profile_network_activity);
+
+ private Supplier<String> mMonitoringSubtitleCaCertStringSupplier = () ->
+ mContext == null ? null : mContext.getString(
+ R.string.monitoring_subtitle_ca_certificate);
+
+ private Supplier<String> mMonitoringSubtitleNetworkStringSupplier = () ->
+ mContext == null ? null : mContext.getString(
+ R.string.monitoring_subtitle_network_logging);
+
+ private Supplier<String> mMonitoringSubtitleVpnStringSupplier = () ->
+ mContext == null ? null : mContext.getString(R.string.monitoring_subtitle_vpn);
+
+ private Supplier<String> mViewPoliciesButtonStringSupplier = () ->
+ mContext == null ? null : mContext.getString(R.string.monitoring_button_view_policies);
+
+ private Supplier<String> mManagementDialogStringSupplier = () ->
+ mContext == null ? null : mContext.getString(
+ R.string.monitoring_description_management);
+
+ private Supplier<String> mManagementDialogCaCertStringSupplier = () ->
+ mContext == null ? null : mContext.getString(
+ R.string.monitoring_description_management_ca_certificate);
+
+ private Supplier<String> mWorkProfileDialogCaCertStringSupplier = () ->
+ mContext == null ? null : mContext.getString(
+ R.string.monitoring_description_managed_profile_ca_certificate);
+
+ private Supplier<String> mManagementDialogNetworkStringSupplier = () ->
+ mContext == null ? null : mContext.getString(
+ R.string.monitoring_description_management_network_logging);
+
+ private Supplier<String> mWorkProfileDialogNetworkStringSupplier = () ->
+ mContext == null ? null : mContext.getString(
+ R.string.monitoring_description_managed_profile_network_logging);
+
@Inject
QSSecurityFooter(@Named(QS_SECURITY_FOOTER_VIEW) View rootView,
UserTracker userTracker, @Main Handler mainHandler,
@@ -337,9 +398,7 @@
private String getManagedDeviceMonitoringText(CharSequence organizationName) {
if (organizationName == null) {
return mDpm.getResources().getString(
- QS_MSG_MANAGEMENT_MONITORING,
- () -> mContext.getString(
- R.string.quick_settings_disclosure_management_monitoring));
+ QS_MSG_MANAGEMENT_MONITORING, mManagementMonitoringStringSupplier);
}
return mDpm.getResources().getString(
QS_MSG_NAMED_MANAGEMENT_MONITORING,
@@ -354,9 +413,7 @@
if (vpnName != null && vpnNameWorkProfile != null) {
if (organizationName == null) {
return mDpm.getResources().getString(
- QS_MSG_MANAGEMENT_MULTIPLE_VPNS,
- () -> mContext.getString(
- R.string.quick_settings_disclosure_management_vpns));
+ QS_MSG_MANAGEMENT_MULTIPLE_VPNS, mManagementMultipleVpnStringSupplier);
}
return mDpm.getResources().getString(
QS_MSG_NAMED_MANAGEMENT_MULTIPLE_VPNS,
@@ -386,10 +443,7 @@
private String getMangedDeviceGeneralText(CharSequence organizationName) {
if (organizationName == null) {
- return mDpm.getResources().getString(
- QS_MSG_MANAGEMENT,
- () -> mContext.getString(
- R.string.quick_settings_disclosure_management));
+ return mDpm.getResources().getString(QS_MSG_MANAGEMENT, mManagementMessageSupplier);
}
if (isFinancedDevice()) {
return mContext.getString(
@@ -431,9 +485,7 @@
if (hasCACertsInWorkProfile && isWorkProfileOn) {
if (workProfileOrganizationName == null) {
return mDpm.getResources().getString(
- QS_MSG_WORK_PROFILE_MONITORING,
- () -> mContext.getString(
- R.string.quick_settings_disclosure_managed_profile_monitoring));
+ QS_MSG_WORK_PROFILE_MONITORING, mWorkProfileMonitoringStringSupplier);
}
return mDpm.getResources().getString(
QS_MSG_NAMED_WORK_PROFILE_MONITORING,
@@ -478,10 +530,9 @@
private String getManagedProfileNetworkActivityText() {
return mDpm.getResources().getString(
- QS_MSG_WORK_PROFILE_NETWORK,
- () -> mContext.getString(
- R.string.quick_settings_disclosure_managed_profile_network_activity));
+ QS_MSG_WORK_PROFILE_NETWORK, mWorkProfileNetworkStringSupplier);
}
+
@Override
public void onClick(DialogInterface dialog, int which) {
if (which == DialogInterface.BUTTON_NEGATIVE) {
@@ -569,6 +620,12 @@
caCertsWarning.setText(caCertsMessage);
// Make "Open trusted credentials"-link clickable
caCertsWarning.setMovementMethod(new LinkMovementMethod());
+
+ TextView caCertsSubtitle = (TextView) dialogView.findViewById(R.id.ca_certs_subtitle);
+ String caCertsSubtitleMessage = mDpm.getResources().getString(
+ QS_DIALOG_MONITORING_CA_CERT_SUBTITLE, mMonitoringSubtitleCaCertStringSupplier);
+ caCertsSubtitle.setText(caCertsSubtitleMessage);
+
}
// network logging section
@@ -581,6 +638,13 @@
TextView networkLoggingWarning =
(TextView) dialogView.findViewById(R.id.network_logging_warning);
networkLoggingWarning.setText(networkLoggingMessage);
+
+ TextView networkLoggingSubtitle = (TextView) dialogView.findViewById(
+ R.id.network_logging_subtitle);
+ String networkLoggingSubtitleMessage = mDpm.getResources().getString(
+ QS_DIALOG_MONITORING_NETWORK_SUBTITLE,
+ mMonitoringSubtitleNetworkStringSupplier);
+ networkLoggingSubtitle.setText(networkLoggingSubtitleMessage);
}
// vpn section
@@ -594,6 +658,11 @@
vpnWarning.setText(vpnMessage);
// Make "Open VPN Settings"-link clickable
vpnWarning.setMovementMethod(new LinkMovementMethod());
+
+ TextView vpnSubtitle = (TextView) dialogView.findViewById(R.id.vpn_subtitle);
+ String vpnSubtitleMessage = mDpm.getResources().getString(
+ QS_DIALOG_MONITORING_VPN_SUBTITLE, mMonitoringSubtitleVpnStringSupplier);
+ vpnSubtitle.setText(vpnSubtitleMessage);
}
// Note: if a new section is added, should update configSubtitleVisibility to include
@@ -657,8 +726,7 @@
@VisibleForTesting
String getSettingsButton() {
return mDpm.getResources().getString(
- QS_DIALOG_VIEW_POLICIES,
- () -> mContext.getString(R.string.monitoring_button_view_policies));
+ QS_DIALOG_VIEW_POLICIES, mViewPoliciesButtonStringSupplier);
}
private String getPositiveButton() {
@@ -692,9 +760,7 @@
organizationName);
}
}
- return mDpm.getResources().getString(
- QS_DIALOG_MANAGEMENT,
- () -> mContext.getString(R.string.monitoring_description_management));
+ return mDpm.getResources().getString(QS_DIALOG_MANAGEMENT, mManagementDialogStringSupplier);
}
@Nullable
@@ -703,15 +769,11 @@
if (!(hasCACerts || hasCACertsInWorkProfile)) return null;
if (isDeviceManaged) {
return mDpm.getResources().getString(
- QS_DIALOG_MANAGEMENT_CA_CERT,
- () -> mContext.getString(
- R.string.monitoring_description_management_ca_certificate));
+ QS_DIALOG_MANAGEMENT_CA_CERT, mManagementDialogCaCertStringSupplier);
}
if (hasCACertsInWorkProfile) {
return mDpm.getResources().getString(
- QS_DIALOG_WORK_PROFILE_CA_CERT,
- () -> mContext.getString(
- R.string.monitoring_description_managed_profile_ca_certificate));
+ QS_DIALOG_WORK_PROFILE_CA_CERT, mWorkProfileDialogCaCertStringSupplier);
}
return mContext.getString(R.string.monitoring_description_ca_certificate);
}
@@ -722,14 +784,10 @@
if (!isNetworkLoggingEnabled) return null;
if (isDeviceManaged) {
return mDpm.getResources().getString(
- QS_DIALOG_MANAGEMENT_NETWORK,
- () -> mContext.getString(
- R.string.monitoring_description_management_network_logging));
+ QS_DIALOG_MANAGEMENT_NETWORK, mManagementDialogNetworkStringSupplier);
} else {
return mDpm.getResources().getString(
- QS_DIALOG_WORK_PROFILE_NETWORK,
- () -> mContext.getString(
- R.string.monitoring_description_managed_profile_network_logging));
+ QS_DIALOG_WORK_PROFILE_NETWORK, mWorkProfileDialogNetworkStringSupplier);
}
}
@@ -799,7 +857,7 @@
} else {
return mDpm.getResources().getString(
QS_DIALOG_MANAGEMENT_TITLE,
- () -> mContext.getString(R.string.monitoring_title_device_owned));
+ mManagementTitleSupplier);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
index 311ee56..3d00dd4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
@@ -47,7 +47,7 @@
private int mMaxColumns = NO_MAX_COLUMNS;
protected int mResourceColumns;
private float mSquishinessFraction = 1f;
- private int mLastTileBottom;
+ protected int mLastTileBottom;
public TileLayout(Context context) {
this(context, null);
@@ -243,12 +243,11 @@
record.tileView.setLeftTopRightBottom(left, top, right, bottom);
}
record.tileView.setPosition(i);
- if (forLayout) {
- mLastTileBottom = record.tileView.getBottom();
- } else {
- float scale = QSTileViewImplKt.constrainSquishiness(mSquishinessFraction);
- mLastTileBottom = top + (int) (record.tileView.getMeasuredHeight() * scale);
- }
+
+ // Set the bottom to the unoverriden squished bottom. This is to avoid fake bottoms that
+ // are only used for QQS -> QS expansion animations
+ float scale = QSTileViewImplKt.constrainSquishiness(mSquishinessFraction);
+ mLastTileBottom = top + (int) (record.tileView.getMeasuredHeight() * scale);
}
}
@@ -258,7 +257,8 @@
}
protected int getRowTop(int row) {
- return (int) (row * (mCellHeight * mSquishinessFraction + mCellMarginVertical));
+ float scale = QSTileViewImplKt.constrainSquishiness(mSquishinessFraction);
+ return (int) (row * (mCellHeight * scale + mCellMarginVertical));
}
protected int getColumnStart(int column) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DreamTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DreamTile.java
index f24773a..22e725b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DreamTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DreamTile.java
@@ -42,6 +42,7 @@
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.dreams.dagger.DreamModule;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.qs.QSTile;
@@ -50,19 +51,24 @@
import com.android.systemui.qs.SettingObserver;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.qs.tileimpl.QSTileImpl;
+import com.android.systemui.settings.UserTracker;
import com.android.systemui.util.settings.SecureSettings;
import javax.inject.Inject;
+import javax.inject.Named;
/** Quick settings tile: Screensaver (dream) **/
public class DreamTile extends QSTileImpl<QSTile.BooleanState> {
private static final String LOG_TAG = "QSDream";
+ private final Icon mIcon = ResourceIcon.get(R.drawable.ic_qs_screen_saver);
private final IDreamManager mDreamManager;
- private final SecureSettings mSecureSettings;
private final BroadcastDispatcher mBroadcastDispatcher;
private final SettingObserver mEnabledSettingObserver;
private final SettingObserver mDreamSettingObserver;
+ private final UserTracker mUserTracker;
+ private final boolean mDreamSupported;
+ private final boolean mDreamOnlyEnabledForSystemUser;
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
@@ -83,12 +89,15 @@
QSLogger qsLogger,
IDreamManager dreamManager,
SecureSettings secureSettings,
- BroadcastDispatcher broadcastDispatcher
+ BroadcastDispatcher broadcastDispatcher,
+ UserTracker userTracker,
+ @Named(DreamModule.DREAM_SUPPORTED) boolean dreamSupported,
+ @Named(DreamModule.DREAM_ONLY_ENABLED_FOR_SYSTEM_USER)
+ boolean dreamOnlyEnabledForSystemUser
) {
super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
statusBarStateController, activityStarter, qsLogger);
mDreamManager = dreamManager;
- mSecureSettings = secureSettings;
mBroadcastDispatcher = broadcastDispatcher;
mEnabledSettingObserver = new SettingObserver(secureSettings, mHandler,
Settings.Secure.SCREENSAVER_ENABLED) {
@@ -104,6 +113,9 @@
refreshState();
}
};
+ mUserTracker = userTracker;
+ mDreamSupported = dreamSupported;
+ mDreamOnlyEnabledForSystemUser = dreamOnlyEnabledForSystemUser;
}
@Override
@@ -156,6 +168,7 @@
state.label = getTileLabel();
state.secondaryLabel = getActiveDreamName();
state.contentDescription = getContentDescription(state.secondaryLabel);
+ state.icon = mIcon;
if (getActiveDream() == null || !isScreensaverEnabled()) {
state.state = Tile.STATE_UNAVAILABLE;
@@ -177,8 +190,11 @@
@Override
public boolean isAvailable() {
- // For now, only present on userdebug devices.
- return Build.isDebuggable();
+ // Only enable for devices that have dreams for the user(s) that can dream.
+ // For now, restrict to debug users.
+ return Build.isDebuggable()
+ && mDreamSupported
+ && (!mDreamOnlyEnabledForSystemUser || mUserTracker.getUserHandle().isSystem());
}
@VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
index d7aa8b2..7c8e77b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
@@ -30,6 +30,7 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.settingslib.wifi.WifiEnterpriseRestrictionUtils;
import com.android.systemui.R;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
@@ -158,7 +159,9 @@
state.expandedAccessibilityClassName = Switch.class.getName();
state.contentDescription = state.label;
- final boolean isTileUnavailable = isDataSaverEnabled;
+ final boolean isWifiTetheringAllowed =
+ WifiEnterpriseRestrictionUtils.isWifiTetheringAllowed(mHost.getUserContext());
+ final boolean isTileUnavailable = isDataSaverEnabled || !isWifiTetheringAllowed;
final boolean isTileActive = (state.value || state.isTransient);
if (isTileUnavailable) {
@@ -167,15 +170,17 @@
state.state = isTileActive ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
}
- state.secondaryLabel = getSecondaryLabel(
- isTileActive, isTransient, isDataSaverEnabled, numConnectedDevices);
+ state.secondaryLabel = getSecondaryLabel(isTileActive, isTransient, isDataSaverEnabled,
+ numConnectedDevices, isWifiTetheringAllowed);
state.stateDescription = state.secondaryLabel;
}
@Nullable
private String getSecondaryLabel(boolean isActive, boolean isTransient,
- boolean isDataSaverEnabled, int numConnectedDevices) {
- if (isTransient) {
+ boolean isDataSaverEnabled, int numConnectedDevices, boolean isWifiTetheringAllowed) {
+ if (!isWifiTetheringAllowed) {
+ return mContext.getString(R.string.wifitrackerlib_admin_restricted_network);
+ } else if (isTransient) {
return mContext.getString(R.string.quick_settings_hotspot_secondary_label_transient);
} else if (isDataSaverEnabled) {
return mContext.getString(
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index 9768e70..da943d2 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -736,7 +736,7 @@
}
private void onStatusBarStateChanged(boolean keyguardShowing, boolean keyguardOccluded,
- boolean bouncerShowing, boolean isDozing) {
+ boolean bouncerShowing, boolean isDozing, boolean panelExpanded) {
mSysUiState.setFlag(SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING,
keyguardShowing && !keyguardOccluded)
.setFlag(SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED,
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
index 4728c67..489f881 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
@@ -78,7 +78,6 @@
import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
-import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.widget.Toast;
import android.window.WindowContext;
@@ -484,6 +483,7 @@
setWindowFocusable(false);
}
});
+ mScreenshotView.setDefaultTimeoutMillis(mScreenshotHandler.getDefaultTimeoutMillis());
mScreenshotView.setOnKeyListener((v, keyCode, event) -> {
if (keyCode == KeyEvent.KEYCODE_BACK) {
@@ -558,14 +558,9 @@
private void saveScreenshot(Bitmap screenshot, Consumer<Uri> finisher, Rect screenRect,
Insets screenInsets, ComponentName topComponent, boolean showFlash) {
- if (mAccessibilityManager.isEnabled()) {
- AccessibilityEvent event =
- new AccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
- event.setContentDescription(
- mContext.getResources().getString(R.string.screenshot_saving_title));
- mAccessibilityManager.sendAccessibilityEvent(event);
- }
-
+ withWindowAttached(() ->
+ mScreenshotView.announceForAccessibility(
+ mContext.getResources().getString(R.string.screenshot_saving_title)));
if (mScreenshotView.isAttachedToWindow()) {
// if we didn't already dismiss for another reason
@@ -632,6 +627,7 @@
}
}
}
+
@Override
public void requestCompatCameraControl(boolean showControl,
boolean transformationApplied,
@@ -717,6 +713,7 @@
Log.e(TAG, "requestScrollCapture failed", e);
}
}
+
ListenableFuture<ScrollCaptureController.LongScreenshot> mLongScreenshotFuture;
private void runBatchScrollCapture(ScrollCaptureResponse response) {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
index ccfcaa6..79939c8 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
@@ -18,6 +18,7 @@
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
+import static com.android.internal.jank.InteractionJankMonitor.CUJ_TAKE_SCREENSHOT;
import static com.android.systemui.screenshot.LogConfig.DEBUG_ANIM;
import static com.android.systemui.screenshot.LogConfig.DEBUG_DISMISS;
import static com.android.systemui.screenshot.LogConfig.DEBUG_INPUT;
@@ -83,6 +84,7 @@
import androidx.constraintlayout.widget.ConstraintLayout;
+import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.R;
import com.android.systemui.screenshot.ScreenshotController.SavedImageData.ActionTransition;
@@ -166,6 +168,9 @@
private final ArrayList<OverlayActionChip> mSmartChips = new ArrayList<>();
private PendingInteraction mPendingInteraction;
+ private final InteractionJankMonitor mInteractionJankMonitor;
+ private long mDefaultTimeoutOfTimeoutHandler;
+
private enum PendingInteraction {
PREVIEW,
EDIT,
@@ -189,6 +194,7 @@
Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
mResources = mContext.getResources();
+ mInteractionJankMonitor = getInteractionJankMonitorInstance();
mFixedSize = mResources.getDimensionPixelSize(R.dimen.overlay_x_scale);
@@ -229,6 +235,14 @@
});
}
+ private InteractionJankMonitor getInteractionJankMonitorInstance() {
+ return InteractionJankMonitor.getInstance();
+ }
+
+ void setDefaultTimeoutMillis(long timeout) {
+ mDefaultTimeoutOfTimeoutHandler = timeout;
+ }
+
public void hideScrollChip() {
mScrollChip.setVisibility(View.GONE);
}
@@ -395,6 +409,9 @@
@Override
public void onDismissComplete() {
+ if (mInteractionJankMonitor.isInstrumenting(CUJ_TAKE_SCREENSHOT)) {
+ mInteractionJankMonitor.end(CUJ_TAKE_SCREENSHOT);
+ }
mCallbacks.onDismiss();
}
});
@@ -595,6 +612,20 @@
dropInAnimation.addListener(new AnimatorListenerAdapter() {
@Override
+ public void onAnimationCancel(Animator animation) {
+ mInteractionJankMonitor.cancel(CUJ_TAKE_SCREENSHOT);
+ }
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ InteractionJankMonitor.Configuration.Builder builder =
+ InteractionJankMonitor.Configuration.Builder.withView(
+ CUJ_TAKE_SCREENSHOT, mScreenshotPreview)
+ .setTag("DropIn");
+ mInteractionJankMonitor.begin(builder);
+ }
+
+ @Override
public void onAnimationEnd(Animator animation) {
if (DEBUG_ANIM) {
Log.d(TAG, "drop-in animation ended");
@@ -620,7 +651,7 @@
mScreenshotPreview.setX(finalPos.x - mScreenshotPreview.getWidth() / 2f);
mScreenshotPreview.setY(finalPos.y - mScreenshotPreview.getHeight() / 2f);
requestLayout();
-
+ mInteractionJankMonitor.end(CUJ_TAKE_SCREENSHOT);
createScreenshotActionsShadeAnimation().start();
}
});
@@ -691,6 +722,28 @@
mActionsContainer.setVisibility(View.VISIBLE);
mActionsContainerBackground.setVisibility(View.VISIBLE);
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ mInteractionJankMonitor.cancel(CUJ_TAKE_SCREENSHOT);
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mInteractionJankMonitor.end(CUJ_TAKE_SCREENSHOT);
+ }
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ InteractionJankMonitor.Configuration.Builder builder =
+ InteractionJankMonitor.Configuration.Builder.withView(
+ CUJ_TAKE_SCREENSHOT, mScreenshotStatic)
+ .setTag("Actions")
+ .setTimeout(mDefaultTimeoutOfTimeoutHandler);
+ mInteractionJankMonitor.begin(builder);
+ }
+ });
+
animator.addUpdateListener(animation -> {
float t = animation.getAnimatedFraction();
float containerAlpha = t < alphaFraction ? t / alphaFraction : 1;
@@ -767,7 +820,7 @@
animateDismissal();
});
actionChip.setAlpha(1);
- mActionsView.addView(actionChip);
+ mActionsView.addView(actionChip, mActionsView.getChildCount() - 1);
mSmartChips.add(actionChip);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
index 7f3758e..2621f6d 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
@@ -16,6 +16,7 @@
package com.android.systemui.screenshot;
+import static android.app.admin.DevicePolicyResources.Strings.SystemUi.SCREENSHOT_BLOCKED_BY_ADMIN;
import static android.content.Intent.ACTION_CLOSE_SYSTEM_DIALOGS;
import static com.android.internal.util.ScreenshotHelper.SCREENSHOT_MSG_PROCESS_COMPLETE;
@@ -54,7 +55,9 @@
import com.android.internal.logging.UiEventLogger;
import com.android.internal.util.ScreenshotHelper;
import com.android.systemui.R;
+import com.android.systemui.dagger.qualifiers.Background;
+import java.util.concurrent.Executor;
import java.util.function.Consumer;
import javax.inject.Inject;
@@ -70,6 +73,7 @@
private final ScreenshotNotificationsController mNotificationsController;
private final Handler mHandler;
private final Context mContext;
+ private final @Background Executor mBgExecutor;
private final BroadcastReceiver mCloseSystemDialogs = new BroadcastReceiver() {
@Override
@@ -97,7 +101,8 @@
@Inject
public TakeScreenshotService(ScreenshotController screenshotController, UserManager userManager,
DevicePolicyManager devicePolicyManager, UiEventLogger uiEventLogger,
- ScreenshotNotificationsController notificationsController, Context context) {
+ ScreenshotNotificationsController notificationsController, Context context,
+ @Background Executor bgExecutor) {
if (DEBUG_SERVICE) {
Log.d(TAG, "new " + this);
}
@@ -108,6 +113,7 @@
mUiEventLogger = uiEventLogger;
mNotificationsController = notificationsController;
mContext = context;
+ mBgExecutor = bgExecutor;
}
@Override
@@ -189,12 +195,18 @@
requestCallback.reportError();
return true;
}
- if(mDevicePolicyManager.getScreenCaptureDisabled(null, UserHandle.USER_ALL)) {
- Log.w(TAG, "Skipping screenshot because an IT admin has disabled "
- + "screenshots on the device");
- Toast.makeText(mContext, R.string.screenshot_blocked_by_admin,
- Toast.LENGTH_SHORT).show();
- requestCallback.reportError();
+
+ if (mDevicePolicyManager.getScreenCaptureDisabled(null, UserHandle.USER_ALL)) {
+ mBgExecutor.execute(() -> {
+ Log.w(TAG, "Skipping screenshot because an IT admin has disabled "
+ + "screenshots on the device");
+ String blockedByAdminText = mDevicePolicyManager.getResources().getString(
+ SCREENSHOT_BLOCKED_BY_ADMIN,
+ () -> mContext.getString(R.string.screenshot_blocked_by_admin));
+ mHandler.post(() ->
+ Toast.makeText(mContext, blockedByAdminText, Toast.LENGTH_SHORT).show());
+ requestCallback.reportError();
+ });
return true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/TimeoutHandler.java b/packages/SystemUI/src/com/android/systemui/screenshot/TimeoutHandler.java
index 9156601..71c2cb4 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/TimeoutHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/TimeoutHandler.java
@@ -72,6 +72,10 @@
mDefaultTimeout = timeout;
}
+ int getDefaultTimeoutMillis() {
+ return mDefaultTimeout;
+ }
+
/**
* Cancel the current timeout, if any. To reset the delayed runnable use resetTimeout instead.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/scrim/ScrimView.java b/packages/SystemUI/src/com/android/systemui/scrim/ScrimView.java
index 7530681..f68e042 100644
--- a/packages/SystemUI/src/com/android/systemui/scrim/ScrimView.java
+++ b/packages/SystemUI/src/com/android/systemui/scrim/ScrimView.java
@@ -58,6 +58,7 @@
private Drawable mDrawable;
private PorterDuffColorFilter mColorFilter;
private int mTintColor;
+ private boolean mBlendWithMainColor = true;
private Runnable mChangeRunnable;
private Executor mChangeRunnableExecutor;
private Executor mExecutor;
@@ -192,6 +193,19 @@
}
/**
+ * The call to {@link #setTint} will blend with the main color, with the amount
+ * determined by the alpha of the tint. Set to false to avoid this blend.
+ */
+ public void setBlendWithMainColor(boolean blend) {
+ mBlendWithMainColor = blend;
+ }
+
+ /** @return true if blending tint color with main color */
+ public boolean shouldBlendWithMainColor() {
+ return mBlendWithMainColor;
+ }
+
+ /**
* Tints this view, optionally animating it.
* @param color The color.
* @param animated If we should animate.
@@ -211,8 +225,11 @@
// Optimization to blend colors and avoid a color filter
ScrimDrawable drawable = (ScrimDrawable) mDrawable;
float tintAmount = Color.alpha(mTintColor) / 255f;
- int mainTinted = ColorUtils.blendARGB(mColors.getMainColor(), mTintColor,
- tintAmount);
+
+ int mainTinted = mTintColor;
+ if (mBlendWithMainColor) {
+ mainTinted = ColorUtils.blendARGB(mColors.getMainColor(), mTintColor, tintAmount);
+ }
drawable.setColor(mainTinted, animated);
} else {
boolean hasAlpha = Color.alpha(mTintColor) != 0;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java
index 4d933d9..e44d334 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java
@@ -29,7 +29,6 @@
import com.android.systemui.R;
import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry.OnSensitivityChangedListener;
import java.util.ArrayList;
@@ -49,6 +48,7 @@
private TextView mTextView;
private NotificationEntry mShowingEntry;
private Runnable mOnDrawingRectChangedListener;
+ private boolean mRedactSensitiveContent;
public HeadsUpStatusBarView(Context context) {
this(context, null);
@@ -111,29 +111,28 @@
}
public void setEntry(NotificationEntry entry) {
- if (mShowingEntry != null) {
- mShowingEntry.removeOnSensitivityChangedListener(mOnSensitivityChangedListener);
- }
mShowingEntry = entry;
-
if (mShowingEntry != null) {
CharSequence text = entry.headsUpStatusBarText;
- if (entry.isSensitive()) {
+ if (mRedactSensitiveContent && entry.hasSensitiveContents()) {
text = entry.headsUpStatusBarTextPublic;
}
mTextView.setText(text);
- mShowingEntry.addOnSensitivityChangedListener(mOnSensitivityChangedListener);
}
}
- private final OnSensitivityChangedListener mOnSensitivityChangedListener = entry -> {
- if (entry != mShowingEntry) {
- throw new IllegalStateException("Got a sensitivity change for " + entry
- + " but mShowingEntry is " + mShowingEntry);
+ public void setRedactSensitiveContent(boolean redactSensitiveContent) {
+ if (mRedactSensitiveContent == redactSensitiveContent) {
+ return;
}
- // Update the text
- setEntry(entry);
- };
+ mRedactSensitiveContent = redactSensitiveContent;
+ if (mShowingEntry != null && mShowingEntry.hasSensitiveContents()) {
+ mTextView.setText(
+ mRedactSensitiveContent
+ ? mShowingEntry.headsUpStatusBarTextPublic
+ : mShowingEntry.headsUpStatusBarText);
+ }
+ }
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
index c1ea6bf..cbe722b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
@@ -386,7 +386,7 @@
}
if (view is ExpandableNotificationRow) {
// Only drag down on sensitive views, otherwise the ExpandHelper will take this
- return view.entry.isSensitive
+ return lockScreenUserManager.notifNeedsRedactionInPublic(view.entry)
}
}
return false
@@ -552,7 +552,8 @@
logger.logShadeDisabledOnGoToLockedShade()
return
}
- var userId: Int = lockScreenUserManager.getCurrentUserId()
+ val currentUser = lockScreenUserManager.currentUserId
+ var userId: Int = currentUser
var entry: NotificationEntry? = null
if (expandView is ExpandableNotificationRow) {
entry = expandView.entry
@@ -562,12 +563,18 @@
entry.setGroupExpansionChanging(true)
userId = entry.sbn.userId
}
- var fullShadeNeedsBouncer = (!lockScreenUserManager.userAllowsPrivateNotificationsInPublic(
- lockScreenUserManager.getCurrentUserId()) ||
- !lockScreenUserManager.shouldShowLockscreenNotifications() ||
- falsingCollector.shouldEnforceBouncer())
- if (keyguardBypassController.bypassEnabled) {
- fullShadeNeedsBouncer = false
+ val fullShadeNeedsBouncer = when {
+ // No bouncer necessary if we're bypassing
+ keyguardBypassController.bypassEnabled -> false
+ // Redacted notificationss are present, bouncer should be shown before un-redacting in
+ // the full shade
+ lockScreenUserManager.sensitiveNotifsNeedRedactionInPublic(currentUser) -> true
+ // Notifications are hidden in public, bouncer should be shown before showing them in
+ // the full shade
+ !lockScreenUserManager.shouldShowLockscreenNotifications() -> true
+ // Bouncer is being enforced, so we need to show it
+ falsingCollector.shouldEnforceBouncer() -> true
+ else -> false
}
if (lockScreenUserManager.isLockscreenPublicMode(userId) && fullShadeNeedsBouncer) {
statusBarStateController.setLeaveOpenOnKeyguardHide(true)
@@ -911,4 +918,4 @@
host.getLocationOnScreen(temp2)
return expandCallback.getChildAtRawPosition(x + temp2[0], y + temp2[1])
}
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
index 9a1a144..512230e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
@@ -71,17 +71,22 @@
boolean shouldHideNotifications(String key);
boolean shouldShowOnKeyguard(NotificationEntry entry);
+ void addOnNeedsRedactionInPublicChangedListener(Runnable listener);
+
+ void removeOnNeedsRedactionInPublicChangedListener(Runnable listener);
+
boolean isAnyProfilePublicMode();
void updatePublicMode();
- boolean needsRedaction(NotificationEntry entry);
+ /** Does this notification require redaction if it is displayed when the device is public? */
+ boolean notifNeedsRedactionInPublic(NotificationEntry entry);
/**
- * Has the given user chosen to allow their private (full) notifications to be shown even
- * when the lockscreen is in "public" (secure & locked) mode?
+ * Do all sensitive notifications belonging to the given user require redaction when they are
+ * displayed in public?
*/
- boolean userAllowsPrivateNotificationsInPublic(int currentUserId);
+ boolean sensitiveNotifsNeedRedactionInPublic(int userId);
/**
* Has the given user chosen to allow notifications to be shown even when the lockscreen is in
@@ -93,6 +98,7 @@
interface UserChangedListener {
default void onUserChanged(int userId) {}
default void onCurrentProfilesChanged(SparseArray<UserInfo> currentProfiles) {}
+ default void onUserRemoved(int userId) {}
}
/** Used to hide notifications on the lockscreen */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
index 56e09f0..0394724 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
@@ -24,7 +24,6 @@
import android.app.ActivityManager;
import android.app.KeyguardManager;
-import android.app.Notification;
import android.app.NotificationManager;
import android.app.admin.DevicePolicyManager;
import android.content.BroadcastReceiver;
@@ -45,7 +44,6 @@
import com.android.internal.statusbar.NotificationVisibility;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.systemui.Dependency;
import com.android.systemui.Dumpable;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.SysUISingleton;
@@ -60,6 +58,7 @@
import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.util.ListenerSet;
import com.android.systemui.util.settings.SecureSettings;
import java.io.PrintWriter;
@@ -85,13 +84,12 @@
private final DeviceProvisionedController mDeviceProvisionedController;
private final KeyguardStateController mKeyguardStateController;
private final SecureSettings mSecureSettings;
+ private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ private final Lazy<OverviewProxyService> mOverviewProxyService;
private final Object mLock = new Object();
-
- // Lazy
- private NotificationEntryManager mEntryManager;
-
private final Lazy<NotificationVisibilityProvider> mVisibilityProviderLazy;
private final Lazy<CommonNotifCollection> mCommonNotifCollectionLazy;
+ private final Lazy<NotificationEntryManager> mEntryManagerLazy;
private final DevicePolicyManager mDevicePolicyManager;
private final SparseBooleanArray mLockscreenPublicMode = new SparseBooleanArray();
private final SparseBooleanArray mUsersWithSeparateWorkChallenge = new SparseBooleanArray();
@@ -103,13 +101,14 @@
private final List<UserChangedListener> mListeners = new ArrayList<>();
private final BroadcastDispatcher mBroadcastDispatcher;
private final NotificationClickNotifier mClickNotifier;
-
- private boolean mShowLockscreenNotifications;
- private boolean mAllowLockscreenRemoteInput;
- private LockPatternUtils mLockPatternUtils;
- protected KeyguardManager mKeyguardManager;
- private int mState = StatusBarState.SHADE;
- private List<KeyguardNotificationSuppressor> mKeyguardSuppressors = new ArrayList<>();
+ private final LockPatternUtils mLockPatternUtils;
+ private final List<KeyguardNotificationSuppressor> mKeyguardSuppressors = new ArrayList<>();
+ protected final Context mContext;
+ private final Handler mMainHandler;
+ protected final SparseArray<UserInfo> mCurrentProfiles = new SparseArray<>();
+ protected final SparseArray<UserInfo> mCurrentManagedProfiles = new SparseArray<>();
+ private final ListenerSet<Runnable> mOnSensitiveContentRedactionChangeListeners =
+ new ListenerSet<>();
protected final BroadcastReceiver mAllUsersReceiver = new BroadcastReceiver() {
@Override
@@ -120,7 +119,11 @@
isCurrentProfile(getSendingUserId())) {
mUsersAllowingPrivateNotifications.clear();
updateLockscreenNotificationSetting();
- getEntryManager().updateNotifications("ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED");
+ for (Runnable listener : mOnSensitiveContentRedactionChangeListeners) {
+ listener.run();
+ }
+ mEntryManagerLazy.get()
+ .updateNotifications("ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED");
}
}
};
@@ -142,13 +145,22 @@
// 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");
+ mEntryManagerLazy.get().reapplyFilterAndSort("user switched");
mPresenter.onUserSwitched(mCurrentUserId);
for (UserChangedListener listener : mListeners) {
listener.onUserChanged(mCurrentUserId);
}
break;
+ case Intent.ACTION_USER_REMOVED:
+ int removedUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
+ if (removedUserId != -1) {
+ for (UserChangedListener listener : mListeners) {
+ listener.onUserRemoved(removedUserId);
+ }
+ }
+ updateCurrentProfilesCache();
+ break;
case Intent.ACTION_USER_ADDED:
case Intent.ACTION_MANAGED_PROFILE_AVAILABLE:
case Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE:
@@ -156,7 +168,7 @@
break;
case Intent.ACTION_USER_UNLOCKED:
// Start the overview connection to the launcher service
- Dependency.get(OverviewProxyService.class).startConnectionToCurrentUser();
+ mOverviewProxyService.get().startConnectionToCurrentUser();
break;
case NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION:
final IntentSender intentSender = intent.getParcelableExtra(
@@ -179,28 +191,26 @@
}
};
- protected final Context mContext;
- private final Handler mMainHandler;
- protected final SparseArray<UserInfo> mCurrentProfiles = new SparseArray<>();
- protected final SparseArray<UserInfo> mCurrentManagedProfiles = new SparseArray<>();
-
- protected int mCurrentUserId = 0;
+ // Late-init
protected NotificationPresenter mPresenter;
protected ContentObserver mLockscreenSettingsObserver;
protected ContentObserver mSettingsObserver;
- private boolean mHideSilentNotificationsOnLockscreen;
+ protected KeyguardManager mKeyguardManager;
- private NotificationEntryManager getEntryManager() {
- if (mEntryManager == null) {
- mEntryManager = Dependency.get(NotificationEntryManager.class);
- }
- return mEntryManager;
- }
+ protected int mCurrentUserId = 0;
+ private int mState = StatusBarState.SHADE;
+ private boolean mHideSilentNotificationsOnLockscreen;
+ private boolean mShowLockscreenNotifications;
+ private boolean mAllowLockscreenRemoteInput;
@Inject
- public NotificationLockscreenUserManagerImpl(Context context,
+ public NotificationLockscreenUserManagerImpl(
+ Context context,
BroadcastDispatcher broadcastDispatcher,
DevicePolicyManager devicePolicyManager,
+ KeyguardUpdateMonitor keyguardUpdateMonitor,
+ Lazy<NotificationEntryManager> notificationEntryManagerLazy,
+ Lazy<OverviewProxyService> overviewProxyServiceLazy,
UserManager userManager,
Lazy<NotificationVisibilityProvider> visibilityProviderLazy,
Lazy<CommonNotifCollection> commonNotifCollectionLazy,
@@ -216,9 +226,11 @@
mMainHandler = mainHandler;
mDevicePolicyManager = devicePolicyManager;
mUserManager = userManager;
+ mOverviewProxyService = overviewProxyServiceLazy;
mCurrentUserId = ActivityManager.getCurrentUser();
mVisibilityProviderLazy = visibilityProviderLazy;
mCommonNotifCollectionLazy = commonNotifCollectionLazy;
+ mEntryManagerLazy = notificationEntryManagerLazy;
mClickNotifier = clickNotifier;
statusBarStateController.addCallback(this);
mLockPatternUtils = new LockPatternUtils(context);
@@ -227,10 +239,12 @@
mDeviceProvisionedController = deviceProvisionedController;
mSecureSettings = secureSettings;
mKeyguardStateController = keyguardStateController;
+ mKeyguardUpdateMonitor = keyguardUpdateMonitor;
dumpManager.registerDumpable(this);
}
+ @Override
public void setUpWithPresenter(NotificationPresenter presenter) {
mPresenter = presenter;
@@ -243,7 +257,10 @@
mUsersAllowingNotifications.clear();
// ... and refresh all the notifications
updateLockscreenNotificationSetting();
- getEntryManager().updateNotifications("LOCK_SCREEN_SHOW_NOTIFICATIONS,"
+ for (Runnable listener : mOnSensitiveContentRedactionChangeListeners) {
+ listener.run();
+ }
+ mEntryManagerLazy.get().updateNotifications("LOCK_SCREEN_SHOW_NOTIFICATIONS,"
+ " or LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS change");
}
};
@@ -253,7 +270,7 @@
public void onChange(boolean selfChange) {
updateLockscreenNotificationSetting();
if (mDeviceProvisionedController.isDeviceProvisioned()) {
- getEntryManager().updateNotifications("LOCK_SCREEN_ALLOW_REMOTE_INPUT"
+ mEntryManagerLazy.get().updateNotifications("LOCK_SCREEN_ALLOW_REMOTE_INPUT"
+ " or ZEN_MODE change");
}
}
@@ -295,6 +312,7 @@
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_USER_SWITCHED);
filter.addAction(Intent.ACTION_USER_ADDED);
+ filter.addAction(Intent.ACTION_USER_REMOVED);
filter.addAction(Intent.ACTION_USER_UNLOCKED);
filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE);
filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
@@ -312,14 +330,17 @@
mSettingsObserver.onChange(false); // set up
}
+ @Override
public boolean shouldShowLockscreenNotifications() {
return mShowLockscreenNotifications;
}
+ @Override
public boolean shouldAllowLockscreenRemoteInput() {
return mAllowLockscreenRemoteInput;
}
+ @Override
public boolean isCurrentProfile(int userId) {
synchronized (mLock) {
return userId == UserHandle.USER_ALL || mCurrentProfiles.get(userId) != null;
@@ -334,7 +355,7 @@
if (userId == UserHandle.USER_ALL) {
userId = mCurrentUserId;
}
- boolean inLockdown = Dependency.get(KeyguardUpdateMonitor.class).isUserInLockdown(userId);
+ boolean inLockdown = mKeyguardUpdateMonitor.isUserInLockdown(userId);
mUsersInLockdownLatestResult.put(userId, inLockdown);
return inLockdown;
}
@@ -343,6 +364,7 @@
* Returns true if we're on a secure lockscreen and the user wants to hide notification data.
* If so, notifications should be hidden.
*/
+ @Override
public boolean shouldHideNotifications(int userId) {
boolean hide = isLockscreenPublicMode(userId) && !userAllowsNotificationsInPublic(userId)
|| (userId != mCurrentUserId && shouldHideNotifications(mCurrentUserId))
@@ -355,6 +377,7 @@
* Returns true if we're on a secure lockscreen and the user wants to hide notifications via
* package-specific override.
*/
+ @Override
public boolean shouldHideNotifications(String key) {
if (mCommonNotifCollectionLazy.get() == null) {
Log.wtf(TAG, "mCommonNotifCollectionLazy was null!", new Throwable());
@@ -365,6 +388,7 @@
&& visibleEntry.getRanking().getLockscreenVisibilityOverride() == VISIBILITY_SECRET;
}
+ @Override
public boolean shouldShowOnKeyguard(NotificationEntry entry) {
if (mCommonNotifCollectionLazy.get() == null) {
Log.wtf(TAG, "mCommonNotifCollectionLazy was null!", new Throwable());
@@ -387,14 +411,6 @@
return mShowLockscreenNotifications && exceedsPriorityThreshold;
}
- private void setShowLockscreenNotifications(boolean show) {
- mShowLockscreenNotifications = show;
- }
-
- private void setLockscreenAllowRemoteInput(boolean allowLockscreenRemoteInput) {
- mAllowLockscreenRemoteInput = allowLockscreenRemoteInput;
- }
-
protected void updateLockscreenNotificationSetting() {
final boolean show = mSecureSettings.getIntForUser(
Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS,
@@ -408,7 +424,7 @@
mHideSilentNotificationsOnLockscreen = mSecureSettings.getIntForUser(
Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, 1, mCurrentUserId) == 0;
- setShowLockscreenNotifications(show && allowedByDpm);
+ mShowLockscreenNotifications = show && allowedByDpm;
if (ENABLE_LOCK_SCREEN_ALLOW_REMOTE_INPUT) {
final boolean remoteInput = mSecureSettings.getIntForUser(
@@ -418,9 +434,9 @@
final boolean remoteInputDpm =
(dpmFlags & DevicePolicyManager.KEYGUARD_DISABLE_REMOTE_INPUT) == 0;
- setLockscreenAllowRemoteInput(remoteInput && remoteInputDpm);
+ mAllowLockscreenRemoteInput = remoteInput && remoteInputDpm;
} else {
- setLockscreenAllowRemoteInput(false);
+ mAllowLockscreenRemoteInput = false;
}
}
@@ -428,7 +444,7 @@
* Has the given user chosen to allow their private (full) notifications to be shown even
* when the lockscreen is in "public" (secure & locked) mode?
*/
- public boolean userAllowsPrivateNotificationsInPublic(int userHandle) {
+ protected boolean userAllowsPrivateNotificationsInPublic(int userHandle) {
if (userHandle == UserHandle.USER_ALL) {
return true;
}
@@ -473,10 +489,12 @@
/**
* Save the current "public" (locked and secure) state of the lockscreen.
*/
+ @Override
public void setLockscreenPublicMode(boolean publicMode, int userId) {
mLockscreenPublicMode.put(userId, publicMode);
}
+ @Override
public boolean isLockscreenPublicMode(int userId) {
if (userId == UserHandle.USER_ALL) {
return mLockscreenPublicMode.get(mCurrentUserId, false);
@@ -493,6 +511,7 @@
* Has the given user chosen to allow notifications to be shown even when the lockscreen is in
* "public" (secure & locked) mode?
*/
+ @Override
public boolean userAllowsNotificationsInPublic(int userHandle) {
if (isCurrentProfile(userHandle) && userHandle != mCurrentUserId) {
return true;
@@ -513,36 +532,37 @@
}
/** @return true if the entry needs redaction when on the lockscreen. */
- public boolean needsRedaction(NotificationEntry ent) {
+ @Override
+ public boolean notifNeedsRedactionInPublic(NotificationEntry ent) {
int userId = ent.getSbn().getUserId();
+ return ent.hasSensitiveContents() && sensitiveNotifsNeedRedactionInPublic(userId);
+ }
+ @Override
+ public boolean sensitiveNotifsNeedRedactionInPublic(int userId) {
boolean isCurrentUserRedactingNotifs =
!userAllowsPrivateNotificationsInPublic(mCurrentUserId);
+ if (userId == mCurrentUserId) {
+ return isCurrentUserRedactingNotifs;
+ }
+
boolean isNotifForManagedProfile = mCurrentManagedProfiles.contains(userId);
boolean isNotifUserRedacted = !userAllowsPrivateNotificationsInPublic(userId);
// redact notifications if the current user is redacting notifications; however if the
// notification is associated with a managed profile, we rely on the managed profile
// setting to determine whether to redact it
- boolean isNotifRedacted = (!isNotifForManagedProfile && isCurrentUserRedactingNotifs)
- || isNotifUserRedacted;
-
- boolean notificationRequestsRedaction =
- ent.getSbn().getNotification().visibility == Notification.VISIBILITY_PRIVATE;
- boolean userForcesRedaction = packageHasVisibilityOverride(ent.getSbn().getKey());
-
- return userForcesRedaction || notificationRequestsRedaction && isNotifRedacted;
+ return (!isNotifForManagedProfile && isCurrentUserRedactingNotifs) || isNotifUserRedacted;
}
- private boolean packageHasVisibilityOverride(String key) {
- if (mCommonNotifCollectionLazy.get() == null) {
- Log.wtf(TAG, "mEntryManager was null!", new Throwable());
- return true;
- }
- NotificationEntry entry = mCommonNotifCollectionLazy.get().getEntry(key);
- return entry != null
- && entry.getRanking().getLockscreenVisibilityOverride()
- == Notification.VISIBILITY_PRIVATE;
+ @Override
+ public void addOnNeedsRedactionInPublicChangedListener(Runnable listener) {
+ mOnSensitiveContentRedactionChangeListeners.addIfAbsent(listener);
+ }
+
+ @Override
+ public void removeOnNeedsRedactionInPublicChangedListener(Runnable listener) {
+ mOnSensitiveContentRedactionChangeListeners.remove(listener);
}
private void updateCurrentProfilesCache() {
@@ -562,12 +582,16 @@
for (UserChangedListener listener : mListeners) {
listener.onCurrentProfilesChanged(mCurrentProfiles);
}
+ for (Runnable listener : mOnSensitiveContentRedactionChangeListeners) {
+ listener.run();
+ }
});
}
/**
* If any of the profiles are in public mode.
*/
+ @Override
public boolean isAnyProfilePublicMode() {
synchronized (mLock) {
for (int i = mCurrentProfiles.size() - 1; i >= 0; i--) {
@@ -596,10 +620,12 @@
/**
* Returns the current user id. This can change if the user is switched.
*/
+ @Override
public int getCurrentUserId() {
return mCurrentUserId;
}
+ @Override
public SparseArray<UserInfo> getCurrentProfiles() {
return mCurrentProfiles;
}
@@ -640,7 +666,8 @@
setLockscreenPublicMode(isProfilePublic, userId);
mUsersWithSeparateWorkChallenge.put(userId, needsSeparateChallenge);
}
- getEntryManager().updateNotifications("NotificationLockscreenUserManager.updatePublicMode");
+ mEntryManagerLazy.get()
+ .updateNotifications("NotificationLockscreenUserManager.updatePublicMode");
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index 734bc48..0d60401 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -326,9 +326,9 @@
|| child.isPinned();
boolean isLastChild = child == lastChild;
final float viewStart = child.getTranslationY();
-
- final float inShelfAmount = updateShelfTransformation(i, child, scrollingFast,
- expandingAnimated, isLastChild);
+ final float shelfClipStart = getTranslationY() - mPaddingBetweenElements;
+ final float inShelfAmount = getAmountInShelf(i, child, scrollingFast,
+ expandingAnimated, isLastChild, shelfClipStart);
// TODO(b/172289889) scale mPaddingBetweenElements with expansion amount
if ((isLastChild && !child.isInShelf()) || aboveShelf || backgroundForceHidden) {
@@ -609,10 +609,18 @@
}
/**
- * @return the amount how much this notification is in the shelf
+ * @param i Index of the view in the host layout.
+ * @param view The current ExpandableView.
+ * @param scrollingFast Whether we are scrolling fast.
+ * @param expandingAnimated Whether we are expanding a notification.
+ * @param isLastChild Whether this is the last view.
+ * @param shelfClipStart The point at which notifications start getting clipped by the shelf.
+ * @return The amount how much this notification is in the shelf.
+ * 0f is not in shelf. 1f is completely in shelf.
*/
- private float updateShelfTransformation(int i, ExpandableView view, boolean scrollingFast,
- boolean expandingAnimated, boolean isLastChild) {
+ @VisibleForTesting
+ public float getAmountInShelf(int i, ExpandableView view, boolean scrollingFast,
+ boolean expandingAnimated, boolean isLastChild, float shelfClipStart) {
// Let's calculate how much the view is in the shelf
float viewStart = view.getTranslationY();
@@ -635,29 +643,33 @@
float viewEnd = viewStart + fullHeight;
float fullTransitionAmount = 0.0f;
float iconTransitionAmount = 0.0f;
- float shelfStart = getTranslationY() - mPaddingBetweenElements;
+
+ // Don't animate shelf icons during shade expansion.
if (mAmbientState.isExpansionChanging() && !mAmbientState.isOnKeyguard()) {
// TODO(b/172289889) handle icon placement for notification that is clipped by the shelf
if (mIndexOfFirstViewInShelf != -1 && i >= mIndexOfFirstViewInShelf) {
fullTransitionAmount = 1f;
iconTransitionAmount = 1f;
}
- } else if (viewEnd >= shelfStart
+
+ } else if (viewEnd >= shelfClipStart
&& (!mAmbientState.isUnlockHintRunning() || view.isInShelf())
&& (mAmbientState.isShadeExpanded()
|| (!view.isPinned() && !view.isHeadsUpAnimatingAway()))) {
- if (viewStart < shelfStart) {
- float fullAmount = (shelfStart - viewStart) / fullHeight;
+ if (viewStart < shelfClipStart && Math.abs(viewStart - shelfClipStart) > 0.001f) {
+ // Partially clipped by shelf.
+ float fullAmount = (shelfClipStart - viewStart) / fullHeight;
fullAmount = Math.min(1.0f, fullAmount);
fullTransitionAmount = 1.0f - fullAmount;
if (isLastChild) {
// Reduce icon transform distance to completely fade in shelf icon
// by the time the notification icon fades out, and vice versa
- iconTransitionAmount = (shelfStart - viewStart)
+ iconTransitionAmount = (shelfClipStart - viewStart)
/ (iconTransformStart - viewStart);
} else {
- iconTransitionAmount = (shelfStart - iconTransformStart) / transformDistance;
+ iconTransitionAmount = (shelfClipStart - iconTransformStart)
+ / transformDistance;
}
iconTransitionAmount = MathUtils.constrain(iconTransitionAmount, 0.0f, 1.0f);
iconTransitionAmount = 1.0f - iconTransitionAmount;
@@ -772,6 +784,9 @@
}
private NotificationIconContainer.IconState getIconState(StatusBarIconView icon) {
+ if (mShelfIcons == null) {
+ return null;
+ }
return mShelfIcons.getIconState(icon);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
index 054543c..30cb09d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
@@ -53,6 +53,7 @@
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Stack;
@@ -207,12 +208,9 @@
|| !mLockscreenUserManager.needsSeparateWorkChallenge(userId))) {
userPublic = false;
}
- boolean needsRedaction = mLockscreenUserManager.needsRedaction(ent);
+ boolean needsRedaction = mLockscreenUserManager.notifNeedsRedactionInPublic(ent);
boolean sensitive = userPublic && needsRedaction;
- boolean deviceSensitive = devicePublic
- && !mLockscreenUserManager.userAllowsPrivateNotificationsInPublic(
- currentUserId);
- ent.setSensitive(sensitive, deviceSensitive);
+ ent.getRow().setSensitive(sensitive);
ent.getRow().setNeedsRedaction(needsRedaction);
mLowPriorityInflationHelper.recheckLowPriorityViewAndInflate(ent, ent.getRow());
boolean isChildInGroup = mGroupManager.isChildInGroup(ent);
@@ -365,6 +363,8 @@
boolean hasClearableAlertingNotifs = false;
boolean hasNonClearableSilentNotifs = false;
boolean hasClearableSilentNotifs = false;
+ HashSet<Integer> clearableAlertingSensitiveNotifUsers = new HashSet<>();
+ HashSet<Integer> clearableSilentSensitiveNotifUsers = new HashSet<>();
final int childCount = mListContainer.getContainerChildCount();
int visibleTopLevelEntries = 0;
for (int i = 0; i < childCount; i++) {
@@ -376,10 +376,11 @@
continue;
}
final ExpandableNotificationRow row = (ExpandableNotificationRow) child;
- boolean isSilent = row.getEntry().getBucket() == BUCKET_SILENT;
+ NotificationEntry entry = row.getEntry();
+ boolean isSilent = entry.getBucket() == BUCKET_SILENT;
// NOTE: NotificationEntry.isClearable() will internally check group children to ensure
// the group itself definitively clearable.
- boolean isClearable = row.getEntry().isClearable();
+ boolean isClearable = entry.isClearable();
visibleTopLevelEntries++;
if (isSilent) {
if (isClearable) {
@@ -394,13 +395,24 @@
hasNonClearableAlertingNotifs = true;
}
}
+ if (isClearable && entry.hasSensitiveContents()) {
+ int userId = entry.getSbn().getUserId();
+ if (isSilent) {
+ clearableSilentSensitiveNotifUsers.add(userId);
+ } else {
+ clearableAlertingSensitiveNotifUsers.add(userId);
+ }
+ }
}
mStackController.setNotifStats(new NotifStats(
visibleTopLevelEntries /* numActiveNotifs */,
hasNonClearableAlertingNotifs /* hasNonClearableAlertingNotifs */,
hasClearableAlertingNotifs /* hasClearableAlertingNotifs */,
hasNonClearableSilentNotifs /* hasNonClearableSilentNotifs */,
- hasClearableSilentNotifs /* hasClearableSilentNotifs */
+ hasClearableSilentNotifs /* hasClearableSilentNotifs */,
+ clearableAlertingSensitiveNotifUsers /* clearableAlertingSensitiveNotifUsers */,
+ clearableSilentSensitiveNotifUsers /* clearableSilentSensitiveNotifUsers */
+
));
Trace.endSection();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/DynamicPrivacyController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/DynamicPrivacyController.java
index a0ccd57..d16e9e5d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/DynamicPrivacyController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/DynamicPrivacyController.java
@@ -80,7 +80,7 @@
@VisibleForTesting
boolean isDynamicPrivacyEnabled() {
- return !mLockscreenUserManager.userAllowsPrivateNotificationsInPublic(
+ return mLockscreenUserManager.sensitiveNotifsNeedRedactionInPublic(
mLockscreenUserManager.getCurrentUserId());
}
@@ -95,6 +95,10 @@
mListeners.add(listener);
}
+ public void removeListener(Listener listener) {
+ mListeners.remove(listener);
+ }
+
/**
* Is the notification shade currently in a locked down mode where it's fully showing but the
* contents aren't revealed yet?
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java
index df412ed..8cb18a0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java
@@ -260,7 +260,7 @@
Intent browserIntent = getTaskIntent(taskId, userId);
Notification.Builder builder =
- new Notification.Builder(mContext, NotificationChannels.GENERAL);
+ new Notification.Builder(mContext, NotificationChannels.INSTANT);
if (browserIntent != null && browserIntent.isWebIntent()) {
// Make sure that this doesn't resolve back to an instant app
browserIntent
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationActivityStarter.java
index 129fa5a..0c341cc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationActivityStarter.java
@@ -17,7 +17,6 @@
package com.android.systemui.statusbar.notification;
import android.content.Intent;
-import android.service.notification.StatusBarNotification;
import android.view.View;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -29,7 +28,7 @@
*/
public interface NotificationActivityStarter {
/** Called when the user clicks on the surface of a notification. */
- void onNotificationClicked(StatusBarNotification sbn, ExpandableNotificationRow row);
+ void onNotificationClicked(NotificationEntry entry, ExpandableNotificationRow row);
/** Called when the user clicks on a button in the notification guts which fires an intent. */
void startNotificationGutsIntent(Intent intent, int appUid,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java
index 392145a..c3ce593 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java
@@ -104,7 +104,7 @@
mBubblesOptional.get().collapseStack();
}
- mNotificationActivityStarter.onNotificationClicked(entry.getSbn(), row);
+ mNotificationActivityStarter.onNotificationClicked(entry, row);
}
private boolean isMenuVisible(ExpandableNotificationRow row) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClickerLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClickerLogger.kt
index fbf033b..ad3dfed 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClickerLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClickerLogger.kt
@@ -27,7 +27,7 @@
) {
fun logOnClick(entry: NotificationEntry) {
buffer.log(TAG, LogLevel.DEBUG, {
- str1 = entry.key
+ str1 = entry.logKey
str2 = entry.ranking.channel.id
}, {
"CLICK $str1 (channel=$str2)"
@@ -36,7 +36,7 @@
fun logMenuVisible(entry: NotificationEntry) {
buffer.log(TAG, LogLevel.DEBUG, {
- str1 = entry.key
+ str1 = entry.logKey
}, {
"Ignoring click on $str1; menu is visible"
})
@@ -44,7 +44,7 @@
fun logParentMenuVisible(entry: NotificationEntry) {
buffer.log(TAG, LogLevel.DEBUG, {
- str1 = entry.key
+ str1 = entry.logKey
}, {
"Ignoring click on $str1; parent menu is visible"
})
@@ -52,7 +52,7 @@
fun logChildrenExpanded(entry: NotificationEntry) {
buffer.log(TAG, LogLevel.DEBUG, {
- str1 = entry.key
+ str1 = entry.logKey
}, {
"Ignoring click on $str1; children are expanded"
})
@@ -60,7 +60,7 @@
fun logGutsExposed(entry: NotificationEntry) {
buffer.log(TAG, LogLevel.DEBUG, {
- str1 = entry.key
+ str1 = entry.logKey
}, {
"Ignoring click on $str1; guts are exposed"
})
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java
index c3cc97b..7cfb157 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java
@@ -24,7 +24,8 @@
import com.android.internal.util.ContrastColorUtil;
import com.android.systemui.R;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.ListEntry;
+import com.android.systemui.util.Compile;
/**
* A util class for various reusable functions
@@ -74,12 +75,18 @@
return (int) (dimensionPixelSize * factor);
}
+ private static final boolean INCLUDE_HASH_CODE_IN_LIST_ENTRY_LOG_KEY = false;
+
/** Get the notification key, reformatted for logging, for the (optional) entry */
- public static String logKey(NotificationEntry entry) {
+ public static String logKey(ListEntry entry) {
if (entry == null) {
return "null";
}
- return logKey(entry.getKey());
+ if (Compile.IS_DEBUG && INCLUDE_HASH_CODE_IN_LIST_ENTRY_LOG_KEY) {
+ return logKey(entry.getKey()) + "@" + Integer.toHexString(entry.hashCode());
+ } else {
+ return logKey(entry.getKey());
+ }
}
/** Removes newlines from the notification key to prettify apps that have these in the tag */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.kt
new file mode 100644
index 0000000..432bac4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.kt
@@ -0,0 +1,31 @@
+/*
+ * 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
+
+import android.service.notification.StatusBarNotification
+import com.android.systemui.statusbar.notification.collection.ListEntry
+
+/** Get the notification key, reformatted for logging, for the (optional) entry */
+val ListEntry?.logKey: String?
+ get() = this?.let { NotificationUtils.logKey(it) }
+
+/** Get the notification key, reformatted for logging, for the (optional) sbn */
+val StatusBarNotification?.logKey: String?
+ get() = this?.key?.let { NotificationUtils.logKey(it) }
+
+/** Removes newlines from the notification key to prettify apps that have these in the tag */
+fun logKey(key: String?): String? = NotificationUtils.logKey(key)
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListDumper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListDumper.java
index 6be8a49..e98ae8d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListDumper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListDumper.java
@@ -121,6 +121,12 @@
sb.append(" (parent=")
.append(entry.getParent() != null ? entry.getParent().getKey() : null)
.append(")");
+
+ NotificationEntry notifEntry = entry.getRepresentativeEntry();
+ if (notifEntry != null) {
+ sb.append(" rank=")
+ .append(notifEntry.getRanking().getRank());
+ }
}
if (entry.getSection() != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
index bcd8e59..6085096 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
@@ -18,9 +18,12 @@
import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL;
import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL_ALL;
+import static android.service.notification.NotificationListenerService.REASON_ASSISTANT_CANCEL;
import static android.service.notification.NotificationListenerService.REASON_CANCEL;
import static android.service.notification.NotificationListenerService.REASON_CANCEL_ALL;
import static android.service.notification.NotificationListenerService.REASON_CHANNEL_BANNED;
+import static android.service.notification.NotificationListenerService.REASON_CHANNEL_REMOVED;
+import static android.service.notification.NotificationListenerService.REASON_CLEAR_DATA;
import static android.service.notification.NotificationListenerService.REASON_CLICK;
import static android.service.notification.NotificationListenerService.REASON_ERROR;
import static android.service.notification.NotificationListenerService.REASON_GROUP_OPTIMIZATION;
@@ -36,9 +39,11 @@
import static android.service.notification.NotificationListenerService.REASON_UNAUTOBUNDLED;
import static android.service.notification.NotificationListenerService.REASON_USER_STOPPED;
+import static com.android.systemui.statusbar.notification.NotificationUtils.logKey;
import static com.android.systemui.statusbar.notification.collection.NotificationEntry.DismissState.DISMISSED;
import static com.android.systemui.statusbar.notification.collection.NotificationEntry.DismissState.NOT_DISMISSED;
import static com.android.systemui.statusbar.notification.collection.NotificationEntry.DismissState.PARENT_DISMISSED;
+import static com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionLoggerKt.cancellationReasonDebugString;
import static java.util.Objects.requireNonNull;
@@ -99,6 +104,7 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -143,6 +149,7 @@
private final Map<String, NotificationEntry> mNotificationSet = new ArrayMap<>();
private final Collection<NotificationEntry> mReadOnlyNotificationSet =
Collections.unmodifiableCollection(mNotificationSet.values());
+ private final HashMap<String, FutureDismissal> mFutureDismissals = new HashMap<>();
@Nullable private CollectionReadyForBuildListener mBuildListener;
private final List<NotifCollectionListener> mNotifCollectionListeners = new ArrayList<>();
@@ -511,6 +518,7 @@
cancelDismissInterception(entry);
mEventQueue.add(new EntryRemovedEvent(entry, entry.mCancellationReason));
mEventQueue.add(new CleanUpEntryEvent(entry));
+ handleFutureDismissal(entry);
return true;
} else {
return false;
@@ -519,31 +527,32 @@
/**
* Get the group summary entry
- * @param group
+ * @param groupKey
* @return
*/
@Nullable
- public NotificationEntry getGroupSummary(String group) {
+ public NotificationEntry getGroupSummary(String groupKey) {
return mNotificationSet
.values()
.stream()
- .filter(it -> Objects.equals(it.getSbn().getGroup(), group))
+ .filter(it -> Objects.equals(it.getSbn().getGroupKey(), groupKey))
.filter(it -> it.getSbn().getNotification().isGroupSummary())
.findFirst().orElse(null);
}
/**
- * Checks if the entry is the only child in the logical group
- * @param entry
- * @return
+ * Checks if the entry is the only child in the logical group;
+ * it need not have a summary to qualify
+ *
+ * @param entry the entry to check
*/
public boolean isOnlyChildInGroup(NotificationEntry entry) {
- String group = entry.getSbn().getGroup();
+ String groupKey = entry.getSbn().getGroupKey();
return mNotificationSet.get(entry.getKey()) == entry
&& mNotificationSet
.values()
.stream()
- .filter(it -> Objects.equals(it.getSbn().getGroup(), group))
+ .filter(it -> Objects.equals(it.getSbn().getGroupKey(), groupKey))
.filter(it -> !it.getSbn().getNotification().isGroupSummary())
.count() == 1;
}
@@ -916,10 +925,139 @@
dispatchEventsAndRebuildList();
}
+ /**
+ * A method to alert the collection that an async operation is happening, at the end of which a
+ * dismissal request will be made. This method has the additional guarantee that if a parent
+ * notification exists for a single child, then that notification will also be dismissed.
+ *
+ * The runnable returned must be run at the end of the async operation to enact the cancellation
+ *
+ * @param entry the notification we want to dismiss
+ * @param cancellationReason the reason for the cancellation
+ * @param statsCreator the callback for generating the stats for an entry
+ * @return the runnable to be run when the dismissal is ready to happen
+ */
+ public Runnable registerFutureDismissal(NotificationEntry entry, int cancellationReason,
+ DismissedByUserStatsCreator statsCreator) {
+ FutureDismissal dismissal = mFutureDismissals.get(entry.getKey());
+ if (dismissal != null) {
+ mLogger.logFutureDismissalReused(dismissal);
+ return dismissal;
+ }
+ dismissal = new FutureDismissal(entry, cancellationReason, statsCreator);
+ mFutureDismissals.put(entry.getKey(), dismissal);
+ mLogger.logFutureDismissalRegistered(dismissal);
+ return dismissal;
+ }
+
+ private void handleFutureDismissal(NotificationEntry entry) {
+ final FutureDismissal futureDismissal = mFutureDismissals.remove(entry.getKey());
+ if (futureDismissal != null) {
+ futureDismissal.onSystemServerCancel(entry.mCancellationReason);
+ }
+ }
+
+ /** A single method interface that callers can pass in when registering future dismissals */
+ public interface DismissedByUserStatsCreator {
+ DismissedByUserStats createDismissedByUserStats(NotificationEntry entry);
+ }
+
+ /** A class which tracks the double dismissal events coming in from both the system server and
+ * the ui */
+ public class FutureDismissal implements Runnable {
+ private final NotificationEntry mEntry;
+ private final DismissedByUserStatsCreator mStatsCreator;
+ @Nullable
+ private final NotificationEntry mSummaryToDismiss;
+ private final String mLabel;
+
+ private boolean mDidRun;
+ private boolean mDidSystemServerCancel;
+
+ private FutureDismissal(NotificationEntry entry, @CancellationReason int cancellationReason,
+ DismissedByUserStatsCreator statsCreator) {
+ mEntry = entry;
+ mStatsCreator = statsCreator;
+ mSummaryToDismiss = fetchSummaryToDismiss(entry);
+ mLabel = "<FutureDismissal@" + Integer.toHexString(hashCode())
+ + " entry=" + logKey(mEntry)
+ + " reason=" + cancellationReasonDebugString(cancellationReason)
+ + " summary=" + logKey(mSummaryToDismiss)
+ + ">";
+ }
+
+ @Nullable
+ private NotificationEntry fetchSummaryToDismiss(NotificationEntry entry) {
+ if (isOnlyChildInGroup(entry)) {
+ String group = entry.getSbn().getGroupKey();
+ NotificationEntry summary = getGroupSummary(group);
+ if (summary != null && summary.isDismissable()) return summary;
+ }
+ return null;
+ }
+
+ /** called when the entry has been removed from the collection */
+ public void onSystemServerCancel(@CancellationReason int cancellationReason) {
+ Assert.isMainThread();
+ if (mDidSystemServerCancel) {
+ mLogger.logFutureDismissalDoubleCancelledByServer(this);
+ return;
+ }
+ mLogger.logFutureDismissalGotSystemServerCancel(this, cancellationReason);
+ mDidSystemServerCancel = true;
+ // TODO: Internally dismiss the summary now instead of waiting for onUiCancel
+ }
+
+ private void onUiCancel() {
+ mFutureDismissals.remove(mEntry.getKey());
+ final NotificationEntry currentEntry = getEntry(mEntry.getKey());
+ // generate stats for the entry before dismissing summary, which could affect state
+ final DismissedByUserStats stats = mStatsCreator.createDismissedByUserStats(mEntry);
+ // dismiss the summary (if it exists)
+ if (mSummaryToDismiss != null) {
+ final NotificationEntry currentSummary = getEntry(mSummaryToDismiss.getKey());
+ if (currentSummary == mSummaryToDismiss) {
+ mLogger.logFutureDismissalDismissing(this, "summary");
+ dismissNotification(mSummaryToDismiss,
+ mStatsCreator.createDismissedByUserStats(mSummaryToDismiss));
+ } else {
+ mLogger.logFutureDismissalMismatchedEntry(this, "summary", currentSummary);
+ }
+ }
+ // dismiss this entry (if it is still around)
+ if (mDidSystemServerCancel) {
+ mLogger.logFutureDismissalAlreadyCancelledByServer(this);
+ } else if (currentEntry == mEntry) {
+ mLogger.logFutureDismissalDismissing(this, "entry");
+ dismissNotification(mEntry, stats);
+ } else {
+ mLogger.logFutureDismissalMismatchedEntry(this, "entry", currentEntry);
+ }
+ }
+
+ /** called when the dismissal should be completed */
+ @Override
+ public void run() {
+ Assert.isMainThread();
+ if (mDidRun) {
+ mLogger.logFutureDismissalDoubleRun(this);
+ return;
+ }
+ mDidRun = true;
+ onUiCancel();
+ }
+
+ /** provides a debug label for this instance */
+ public String getLabel() {
+ return mLabel;
+ }
+ }
+
@IntDef(prefix = { "REASON_" }, value = {
REASON_NOT_CANCELED,
REASON_UNKNOWN,
REASON_CLICK,
+ REASON_CANCEL,
REASON_CANCEL_ALL,
REASON_ERROR,
REASON_PACKAGE_CHANGED,
@@ -937,6 +1075,9 @@
REASON_CHANNEL_BANNED,
REASON_SNOOZED,
REASON_TIMEOUT,
+ REASON_CHANNEL_REMOVED,
+ REASON_CLEAR_DATA,
+ REASON_ASSISTANT_CANCEL,
})
@Retention(RetentionPolicy.SOURCE)
public @interface CancellationReason {}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterImpl.java
index 4daed77..6a3799b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterImpl.java
@@ -79,6 +79,11 @@
entry.abortTask();
}
+ @Override
+ public void releaseViews(@NonNull NotificationEntry entry) {
+ requireBinder().releaseViews(entry);
+ }
+
private NotificationContentInflater.InflationCallback wrapInflationCallback(
InflationCallback callback) {
return new NotificationContentInflater.InflationCallback() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
index 4fc347a..e3c39dd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
@@ -169,9 +169,6 @@
*/
private boolean hasSentReply;
- private boolean mSensitive = true;
- private List<OnSensitivityChangedListener> mOnSensitivityChangedListeners = new ArrayList<>();
-
private boolean mAutoHeadsUp;
private boolean mPulseSupressed;
private int mBucket = BUCKET_ALERTING;
@@ -867,33 +864,29 @@
}
/**
- * Set this notification to be sensitive.
- *
- * @param sensitive true if the content of this notification is sensitive right now
- * @param deviceSensitive true if the device in general is sensitive right now
+ * Returns the visibility of this notification on the lockscreen, taking into account both the
+ * notification's defined visibility, as well as the visibility override as determined by the
+ * device policy.
*/
- public void setSensitive(boolean sensitive, boolean deviceSensitive) {
- getRow().setSensitive(sensitive, deviceSensitive);
- if (sensitive != mSensitive) {
- mSensitive = sensitive;
- for (int i = 0; i < mOnSensitivityChangedListeners.size(); i++) {
- mOnSensitivityChangedListeners.get(i).onSensitivityChanged(this);
- }
+ public int getLockscreenVisibility() {
+ int setting = mRanking.getLockscreenVisibilityOverride();
+ if (setting == Ranking.VISIBILITY_NO_OVERRIDE) {
+ setting = mSbn.getNotification().visibility;
}
+ return setting;
}
- public boolean isSensitive() {
- return mSensitive;
- }
-
- /** Add a listener to be notified when the entry's sensitivity changes. */
- public void addOnSensitivityChangedListener(OnSensitivityChangedListener listener) {
- mOnSensitivityChangedListeners.add(listener);
- }
-
- /** Remove a listener that was registered above. */
- public void removeOnSensitivityChangedListener(OnSensitivityChangedListener listener) {
- mOnSensitivityChangedListeners.remove(listener);
+ /**
+ * Does this notification contain sensitive content? If the user's settings specify, then this
+ * content would need to be redacted when the device this public.
+ *
+ * NOTE: If the notification's visibility setting is VISIBILITY_SECRET, then this will return
+ * false; SECRET notifications are omitted entirely when the device is public, so effectively
+ * the contents of the notification are not sensitive whenever the notification is actually
+ * visible.
+ */
+ public boolean hasSensitiveContents() {
+ return getLockscreenVisibility() == Notification.VISIBILITY_PRIVATE;
}
public boolean isPulseSuppressed() {
@@ -954,12 +947,6 @@
}
}
- /** Listener interface for {@link #addOnSensitivityChangedListener} */
- public interface OnSensitivityChangedListener {
- /** Called when the sensitivity changes */
- void onSensitivityChanged(@NonNull NotificationEntry entry);
- }
-
/** @see #getDismissState() */
public enum DismissState {
/** User has not dismissed this notif or its parent */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
index 1b5e52d..2a8a672 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
@@ -93,6 +93,7 @@
private final NotificationInteractionTracker mInteractionTracker;
private final DumpManager mDumpManager;
// used exclusivly by ShadeListBuilder#notifySectionEntriesUpdated
+ // TODO replace temp with collection pool for readability
private final ArrayList<ListEntry> mTempSectionMembers = new ArrayList<>();
private final boolean mAlwaysLogList;
@@ -230,13 +231,7 @@
mPipelineState.requireState(STATE_IDLE);
mNotifSections.clear();
- NotifSectioner lastSection = null;
for (NotifSectioner sectioner : sectioners) {
- if (lastSection != null && lastSection.getBucket() > sectioner.getBucket()) {
- throw new IllegalArgumentException("setSectioners with non contiguous sections "
- + lastSection.getName() + " - " + lastSection.getBucket() + " & "
- + sectioner.getName() + " - " + sectioner.getBucket());
- }
final NotifSection section = new NotifSection(sectioner, mNotifSections.size());
final NotifComparator sectionComparator = section.getComparator();
mNotifSections.add(section);
@@ -244,10 +239,23 @@
if (sectionComparator != null) {
sectionComparator.setInvalidationListener(this::onNotifComparatorInvalidated);
}
- lastSection = sectioner;
}
mNotifSections.add(new NotifSection(DEFAULT_SECTIONER, mNotifSections.size()));
+
+ // validate sections
+ final ArraySet<Integer> seenBuckets = new ArraySet<>();
+ int lastBucket = mNotifSections.size() > 0
+ ? mNotifSections.get(0).getBucket()
+ : 0;
+ for (NotifSection section : mNotifSections) {
+ if (lastBucket != section.getBucket() && seenBuckets.contains(section.getBucket())) {
+ throw new IllegalStateException("setSectioners with non contiguous sections "
+ + section.getLabel() + " has an already seen bucket");
+ }
+ lastBucket = section.getBucket();
+ seenBuckets.add(lastBucket);
+ }
}
void setNotifStabilityManager(@NonNull NotifStabilityManager notifStabilityManager) {
@@ -982,7 +990,7 @@
// Check for suppressed order changes
if (!getStabilityManager().isEveryChangeAllowed()) {
mForceReorderable = true;
- boolean isSorted = isSorted(mNotifList, mTopLevelComparator);
+ boolean isSorted = isShadeSorted();
mForceReorderable = false;
if (!isSorted) {
getStabilityManager().onEntryReorderSuppressed();
@@ -991,9 +999,23 @@
Trace.endSection();
}
+ private boolean isShadeSorted() {
+ if (!isSorted(mNotifList, mTopLevelComparator)) {
+ return false;
+ }
+ for (ListEntry entry : mNotifList) {
+ if (entry instanceof GroupEntry) {
+ if (!isSorted(((GroupEntry) entry).getChildren(), mGroupChildrenComparator)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
/** Determine whether the items in the list are sorted according to the comparator */
@VisibleForTesting
- public static <T> boolean isSorted(List<T> items, Comparator<T> comparator) {
+ public static <T> boolean isSorted(List<T> items, Comparator<? super T> comparator) {
if (items.size() <= 1) {
return true;
}
@@ -1201,7 +1223,7 @@
};
- private final Comparator<ListEntry> mGroupChildrenComparator = (o1, o2) -> {
+ private final Comparator<NotificationEntry> mGroupChildrenComparator = (o1, o2) -> {
int index1 = canReorder(o1) ? -1 : o1.getPreviousAttachState().getStableIndex();
int index2 = canReorder(o2) ? -1 : o2.getPreviousAttachState().getStableIndex();
int cmp = Integer.compare(index1, index2);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ActivityLaunchAnimCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ActivityLaunchAnimCoordinator.kt
deleted file mode 100644
index b54163d..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ActivityLaunchAnimCoordinator.kt
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.notification.collection.coordinator
-
-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
-import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender
-import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender.OnEndLifetimeExtensionCallback
-import com.android.systemui.statusbar.phone.NotifActivityLaunchEvents
-import dagger.Binds
-import dagger.Module
-import javax.inject.Inject
-
-/** Extends the lifetime of notifications while their activity launch animation is playing. */
-interface ActivityLaunchAnimCoordinator : Coordinator
-
-/** Provides an [ActivityLaunchAnimCoordinator] to [CoordinatorScope]. */
-@Module(includes = [PrivateActivityStarterCoordinatorModule::class])
-object ActivityLaunchAnimCoordinatorModule
-
-@Module
-private interface PrivateActivityStarterCoordinatorModule {
- @Binds
- fun bindCoordinator(impl: ActivityLaunchAnimCoordinatorImpl): ActivityLaunchAnimCoordinator
-}
-
-/**
- * Listens for [NotifActivityLaunchEvents], and then extends the lifetimes of any notifs while their
- * launch animation is playing.
- */
-@CoordinatorScope
-private class ActivityLaunchAnimCoordinatorImpl @Inject constructor(
- private val activityLaunchEvents: NotifActivityLaunchEvents
-) : ActivityLaunchAnimCoordinator {
- // Tracks notification launches, and whether or not their lifetimes are extended.
- private val notifsLaunchingActivities = mutableMapOf<String, Boolean>()
-
- private var onEndLifetimeExtensionCallback: OnEndLifetimeExtensionCallback? = null
-
- override fun attach(pipeline: NotifPipeline) {
- activityLaunchEvents.registerListener(activityStartEventListener)
- pipeline.addNotificationLifetimeExtender(extender)
- }
-
- private val activityStartEventListener = object : NotifActivityLaunchEvents.Listener {
- override fun onStartLaunchNotifActivity(entry: NotificationEntry) {
- notifsLaunchingActivities[entry.key] = false
- }
-
- override fun onFinishLaunchNotifActivity(entry: NotificationEntry) {
- if (notifsLaunchingActivities.remove(entry.key) == true) {
- // If we were extending the lifetime of this notification, stop.
- onEndLifetimeExtensionCallback?.onEndLifetimeExtension(extender, entry)
- }
- }
- }
-
- private val extender = object : NotifLifetimeExtender {
- override fun getName(): String = "ActivityStarterCoordinator"
-
- override fun setCallback(callback: OnEndLifetimeExtensionCallback) {
- onEndLifetimeExtensionCallback = callback
- }
-
- override fun maybeExtendLifetime(entry: NotificationEntry, reason: Int): Boolean {
- if (entry.key in notifsLaunchingActivities) {
- // Track that we're now extending this notif
- notifsLaunchingActivities[entry.key] = true
- return true
- }
- return false
- }
-
- override fun cancelLifetimeExtension(entry: NotificationEntry) {
- if (entry.key in notifsLaunchingActivities) {
- notifsLaunchingActivities[entry.key] = false
- }
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt
index da0169b..d959a24 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt
@@ -503,6 +503,7 @@
private val mOnHeadsUpChangedListener = object : OnHeadsUpChangedListener {
override fun onHeadsUpStateChanged(entry: NotificationEntry, isHeadsUp: Boolean) {
if (!isHeadsUp) {
+ mNotifPromoter.invalidateList()
mHeadsUpViewBinder.unbindHeadsUpView(entry)
endNotifLifetimeExtensionIfExtended(entry)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt
index 3516625..0b3a0dc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt
@@ -56,8 +56,6 @@
smartspaceDedupingCoordinator: SmartspaceDedupingCoordinator,
viewConfigCoordinator: ViewConfigCoordinator,
visualStabilityCoordinator: VisualStabilityCoordinator,
- sensitiveContentCoordinator: SensitiveContentCoordinator,
- activityLaunchAnimCoordinator: ActivityLaunchAnimCoordinator
) : NotifCoordinators {
private val mCoordinators: MutableList<Coordinator> = ArrayList()
@@ -94,8 +92,6 @@
mCoordinators.add(shadeEventCoordinator)
mCoordinators.add(viewConfigCoordinator)
mCoordinators.add(visualStabilityCoordinator)
- mCoordinators.add(sensitiveContentCoordinator)
- mCoordinators.add(activityLaunchAnimCoordinator)
if (notifPipelineFlags.isSmartspaceDedupingEnabled()) {
mCoordinators.add(smartspaceDedupingCoordinator)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java
index 35fe0ee..457e8c9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java
@@ -375,6 +375,7 @@
private void freeNotifViews(NotificationEntry entry) {
mViewBarn.removeViewForEntry(entry);
+ mNotifInflater.releaseViews(entry);
// TODO: clear the entry's row here, or even better, stop setting the row on the entry!
mInflationStates.put(entry, STATE_UNINFLATED);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java
index 5ac4813..57652f3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java
@@ -16,7 +16,6 @@
package com.android.systemui.statusbar.notification.collection.coordinator;
-import android.annotation.NonNull;
import android.annotation.Nullable;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -29,13 +28,11 @@
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
import com.android.systemui.statusbar.notification.collection.provider.SectionStyleProvider;
import com.android.systemui.statusbar.notification.collection.render.NodeController;
-import com.android.systemui.statusbar.notification.collection.render.SectionHeaderController;
import com.android.systemui.statusbar.notification.dagger.AlertingHeader;
import com.android.systemui.statusbar.notification.dagger.SilentHeader;
import com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt;
import java.util.Collections;
-import java.util.List;
import javax.inject.Inject;
@@ -53,10 +50,10 @@
private final HighPriorityProvider mHighPriorityProvider;
private final SectionStyleProvider mSectionStyleProvider;
private final NodeController mSilentNodeController;
- private final SectionHeaderController mSilentHeaderController;
private final NodeController mAlertingHeaderController;
- private boolean mHasSilentEntries;
- private boolean mHasMinimizedEntries;
+ private final AlertingNotifSectioner mAlertingNotifSectioner = new AlertingNotifSectioner();
+ private final SilentNotifSectioner mSilentNotifSectioner = new SilentNotifSectioner();
+ private final MinimizedNotifSectioner mMinimizedNotifSectioner = new MinimizedNotifSectioner();
@Inject
public RankingCoordinator(
@@ -64,14 +61,12 @@
HighPriorityProvider highPriorityProvider,
SectionStyleProvider sectionStyleProvider,
@AlertingHeader NodeController alertingHeaderController,
- @SilentHeader SectionHeaderController silentHeaderController,
@SilentHeader NodeController silentNodeController) {
mStatusBarStateController = statusBarStateController;
mHighPriorityProvider = highPriorityProvider;
mSectionStyleProvider = sectionStyleProvider;
mAlertingHeaderController = alertingHeaderController;
mSilentNodeController = silentNodeController;
- mSilentHeaderController = silentHeaderController;
}
@Override
@@ -95,82 +90,6 @@
return mMinimizedNotifSectioner;
}
- private final NotifSectioner mAlertingNotifSectioner = new NotifSectioner("Alerting",
- NotificationPriorityBucketKt.BUCKET_ALERTING) {
- @Override
- public boolean isInSection(ListEntry entry) {
- return mHighPriorityProvider.isHighPriority(entry);
- }
-
- @Nullable
- @Override
- public NodeController getHeaderNodeController() {
- // TODO: remove SHOW_ALL_SECTIONS, this redundant method, and mAlertingHeaderController
- if (SHOW_ALL_SECTIONS) {
- return mAlertingHeaderController;
- }
- return null;
- }
- };
-
- private final NotifSectioner mSilentNotifSectioner = new NotifSectioner("Silent",
- NotificationPriorityBucketKt.BUCKET_SILENT) {
- @Override
- public boolean isInSection(ListEntry entry) {
- return !mHighPriorityProvider.isHighPriority(entry)
- && !entry.getRepresentativeEntry().isAmbient();
- }
-
- @Nullable
- @Override
- public NodeController getHeaderNodeController() {
- return mSilentNodeController;
- }
-
- @Nullable
- @Override
- public void onEntriesUpdated(@NonNull List<ListEntry> entries) {
- mHasSilentEntries = false;
- for (int i = 0; i < entries.size(); i++) {
- if (entries.get(i).getRepresentativeEntry().getSbn().isClearable()) {
- mHasSilentEntries = true;
- break;
- }
- }
- mSilentHeaderController.setClearSectionEnabled(
- mHasSilentEntries | mHasMinimizedEntries);
- }
- };
-
- private final NotifSectioner mMinimizedNotifSectioner = new NotifSectioner("Minimized",
- NotificationPriorityBucketKt.BUCKET_SILENT) {
- @Override
- public boolean isInSection(ListEntry entry) {
- return !mHighPriorityProvider.isHighPriority(entry)
- && entry.getRepresentativeEntry().isAmbient();
- }
-
- @Nullable
- @Override
- public NodeController getHeaderNodeController() {
- return mSilentNodeController;
- }
-
- @Nullable
- @Override
- public void onEntriesUpdated(@NonNull List<ListEntry> entries) {
- mHasMinimizedEntries = false;
- for (int i = 0; i < entries.size(); i++) {
- if (entries.get(i).getRepresentativeEntry().getSbn().isClearable()) {
- mHasMinimizedEntries = true;
- break;
- }
- }
- mSilentHeaderController.setClearSectionEnabled(
- mHasSilentEntries | mHasMinimizedEntries);
- }
- };
-
/**
* Checks whether to filter out the given notification based the notification's Ranking object.
* NotifListBuilder invalidates the notification list each time the ranking is updated,
@@ -202,4 +121,64 @@
mDndVisualEffectsFilter.invalidateList();
}
};
+
+ private class AlertingNotifSectioner extends NotifSectioner {
+
+ AlertingNotifSectioner() {
+ super("Alerting", NotificationPriorityBucketKt.BUCKET_ALERTING);
+ }
+
+ @Override
+ public boolean isInSection(ListEntry entry) {
+ return mHighPriorityProvider.isHighPriority(entry);
+ }
+
+ @Nullable
+ @Override
+ public NodeController getHeaderNodeController() {
+ // TODO: remove SHOW_ALL_SECTIONS, this redundant method, and mAlertingHeaderController
+ if (SHOW_ALL_SECTIONS) {
+ return mAlertingHeaderController;
+ }
+ return null;
+ }
+ }
+
+ private class SilentNotifSectioner extends NotifSectioner {
+
+ SilentNotifSectioner() {
+ super("Silent", NotificationPriorityBucketKt.BUCKET_SILENT);
+ }
+
+ @Override
+ public boolean isInSection(ListEntry entry) {
+ return !mHighPriorityProvider.isHighPriority(entry)
+ && !entry.getRepresentativeEntry().isAmbient();
+ }
+
+ @Nullable
+ @Override
+ public NodeController getHeaderNodeController() {
+ return mSilentNodeController;
+ }
+ }
+
+ private class MinimizedNotifSectioner extends NotifSectioner {
+
+ MinimizedNotifSectioner() {
+ super("Minimized", NotificationPriorityBucketKt.BUCKET_SILENT);
+ }
+
+ @Override
+ public boolean isInSection(ListEntry entry) {
+ return !mHighPriorityProvider.isHighPriority(entry)
+ && entry.getRepresentativeEntry().isAmbient();
+ }
+
+ @Nullable
+ @Override
+ public NodeController getHeaderNodeController() {
+ return mSilentNodeController;
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinator.kt
deleted file mode 100644
index 3f8a39f..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinator.kt
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.notification.collection.coordinator
-
-import android.os.UserHandle
-import com.android.keyguard.KeyguardUpdateMonitor
-import com.android.systemui.plugins.statusbar.StatusBarStateController
-import com.android.systemui.statusbar.NotificationLockscreenUserManager
-import com.android.systemui.statusbar.StatusBarState
-import com.android.systemui.statusbar.notification.DynamicPrivacyController
-import com.android.systemui.statusbar.notification.collection.GroupEntry
-import com.android.systemui.statusbar.notification.collection.ListEntry
-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
-import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeRenderListListener
-import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Invalidator
-import com.android.systemui.statusbar.policy.KeyguardStateController
-import dagger.Binds
-import dagger.Module
-import javax.inject.Inject
-
-@Module(includes = [PrivateSensitiveContentCoordinatorModule::class])
-interface SensitiveContentCoordinatorModule
-
-@Module
-private interface PrivateSensitiveContentCoordinatorModule {
- @Binds
- fun bindCoordinator(impl: SensitiveContentCoordinatorImpl): SensitiveContentCoordinator
-}
-
-/** Coordinates re-inflation and post-processing of sensitive notification content. */
-interface SensitiveContentCoordinator : Coordinator
-
-@CoordinatorScope
-private class SensitiveContentCoordinatorImpl @Inject constructor(
- private val dynamicPrivacyController: DynamicPrivacyController,
- private val lockscreenUserManager: NotificationLockscreenUserManager,
- private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
- private val statusBarStateController: StatusBarStateController,
- private val keyguardStateController: KeyguardStateController
-) : Invalidator("SensitiveContentInvalidator"),
- SensitiveContentCoordinator,
- DynamicPrivacyController.Listener,
- OnBeforeRenderListListener {
-
- override fun attach(pipeline: NotifPipeline) {
- dynamicPrivacyController.addListener(this)
- pipeline.addOnBeforeRenderListListener(this)
- pipeline.addPreRenderInvalidator(this)
- }
-
- override fun onDynamicPrivacyChanged(): Unit = invalidateList()
-
- override fun onBeforeRenderList(entries: List<ListEntry>) {
- if (keyguardStateController.isKeyguardGoingAway() ||
- statusBarStateController.getState() == StatusBarState.KEYGUARD &&
- keyguardUpdateMonitor.getUserUnlockedWithBiometricAndIsBypassing(
- KeyguardUpdateMonitor.getCurrentUser())) {
- // don't update yet if:
- // - the keyguard is currently going away
- // - LS is about to be dismissed by a biometric that bypasses LS (avoid notif flash)
-
- // TODO(b/206118999): merge this class with KeyguardCoordinator which ensures the
- // dependent state changes invalidate the pipeline
- return
- }
-
- val currentUserId = lockscreenUserManager.currentUserId
- val devicePublic = lockscreenUserManager.isLockscreenPublicMode(currentUserId)
- val deviceSensitive = devicePublic &&
- !lockscreenUserManager.userAllowsPrivateNotificationsInPublic(currentUserId)
- val dynamicallyUnlocked = dynamicPrivacyController.isDynamicallyUnlocked
- for (entry in extractAllRepresentativeEntries(entries).filter { it.rowExists() }) {
- val notifUserId = entry.sbn.user.identifier
- val userLockscreen = devicePublic ||
- lockscreenUserManager.isLockscreenPublicMode(notifUserId)
- val userPublic = when {
- // if we're not on the lockscreen, we're definitely private
- !userLockscreen -> false
- // we are on the lockscreen, so unless we're dynamically unlocked, we're
- // definitely public
- !dynamicallyUnlocked -> true
- // we're dynamically unlocked, but check if the notification needs
- // a separate challenge if it's from a work profile
- else -> when (notifUserId) {
- currentUserId -> false
- UserHandle.USER_ALL -> false
- else -> lockscreenUserManager.needsSeparateWorkChallenge(notifUserId)
- }
- }
- val needsRedaction = lockscreenUserManager.needsRedaction(entry)
- val isSensitive = userPublic && needsRedaction
- entry.setSensitive(isSensitive, deviceSensitive)
- }
- }
-}
-
-private fun extractAllRepresentativeEntries(
- entries: List<ListEntry>
-): Sequence<NotificationEntry> =
- entries.asSequence().flatMap(::extractAllRepresentativeEntries)
-
-private fun extractAllRepresentativeEntries(listEntry: ListEntry): Sequence<NotificationEntry> =
- sequence {
- listEntry.representativeEntry?.let { yield(it) }
- if (listEntry is GroupEntry) {
- yieldAll(extractAllRepresentativeEntries(listEntry.children))
- }
- }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinator.kt
index 1c96e8c..2374e9c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinator.kt
@@ -50,6 +50,8 @@
var hasClearableAlertingNotifs = false
var hasNonClearableSilentNotifs = false
var hasClearableSilentNotifs = false
+ val clearableAlertingSensitiveNotifUsers = mutableSetOf<Int>()
+ val clearableSilentSensitiveNotifUsers = mutableSetOf<Int>()
entries.forEach {
val section = checkNotNull(it.section) { "Null section for ${it.key}" }
val entry = checkNotNull(it.representativeEntry) { "Null notif entry for ${it.key}" }
@@ -63,13 +65,22 @@
!isSilent && isClearable -> hasClearableAlertingNotifs = true
!isSilent && !isClearable -> hasNonClearableAlertingNotifs = true
}
+ if (isClearable && entry.hasSensitiveContents()) {
+ if (isSilent) {
+ clearableSilentSensitiveNotifUsers.add(entry.sbn.userId)
+ } else {
+ clearableAlertingSensitiveNotifUsers.add(entry.sbn.userId)
+ }
+ }
}
return NotifStats(
numActiveNotifs = entries.size,
hasNonClearableAlertingNotifs = hasNonClearableAlertingNotifs,
hasClearableAlertingNotifs = hasClearableAlertingNotifs,
hasNonClearableSilentNotifs = hasNonClearableSilentNotifs,
- hasClearableSilentNotifs = hasClearableSilentNotifs
+ hasClearableSilentNotifs = hasClearableSilentNotifs,
+ clearableAlertingSensitiveNotifUsers = clearableAlertingSensitiveNotifUsers,
+ clearableSilentSensitiveNotifUsers = clearableSilentSensitiveNotifUsers
)
}
}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/dagger/CoordinatorsModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/dagger/CoordinatorsModule.kt
index 274affd..839cf0d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/dagger/CoordinatorsModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/dagger/CoordinatorsModule.kt
@@ -17,10 +17,8 @@
package com.android.systemui.statusbar.notification.collection.coordinator.dagger
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.statusbar.notification.collection.coordinator.ActivityLaunchAnimCoordinatorModule
import com.android.systemui.statusbar.notification.collection.coordinator.NotifCoordinators
import com.android.systemui.statusbar.notification.collection.coordinator.NotifCoordinatorsImpl
-import com.android.systemui.statusbar.notification.collection.coordinator.SensitiveContentCoordinatorModule
import dagger.Binds
import dagger.Module
import dagger.Provides
@@ -49,8 +47,6 @@
}
@Module(includes = [
- ActivityLaunchAnimCoordinatorModule::class,
- SensitiveContentCoordinatorModule::class,
])
private abstract class InternalCoordinatorsModule {
@Binds
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifInflater.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifInflater.kt
index d98e7f7..567ec85 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifInflater.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifInflater.kt
@@ -47,6 +47,11 @@
fun abortInflation(entry: NotificationEntry)
/**
+ * Called to let the system remove the content views from the notification row.
+ */
+ fun releaseViews(entry: NotificationEntry)
+
+ /**
* Callback once all the views are inflated and bound for a given NotificationEntry.
*/
interface InflationCallback {
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 3a4701c..46b467e 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
@@ -50,4 +50,9 @@
NotificationUiAdjustment oldAdjustment,
NotificationUiAdjustment newAdjustment,
NotificationRowContentBinder.InflationCallback callback);
+
+ /**
+ * Called when a notification is no longer likely to be displayed and can have its views freed.
+ */
+ void releaseViews(NotificationEntry entry);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
index 4c7b2bb..8b79b8a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
@@ -16,6 +16,10 @@
package com.android.systemui.statusbar.notification.collection.inflation;
+import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED;
+import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_EXPANDED;
+import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_PUBLIC;
+
import static java.util.Objects.requireNonNull;
import android.annotation.Nullable;
@@ -159,6 +163,18 @@
}
}
+ @Override
+ public void releaseViews(NotificationEntry entry) {
+ if (!entry.rowExists()) {
+ return;
+ }
+ final RowContentBindParams params = mRowContentBindStage.getStageParams(entry);
+ params.markContentViewsFreeable(FLAG_CONTENT_VIEW_CONTRACTED);
+ params.markContentViewsFreeable(FLAG_CONTENT_VIEW_EXPANDED);
+ params.markContentViewsFreeable(FLAG_CONTENT_VIEW_PUBLIC);
+ mRowContentBindStage.requestRebind(entry, null);
+ }
+
/**
* Bind row to various controllers and managers. This is only called when the row is first
* created.
@@ -247,12 +263,17 @@
}
RowContentBindParams params = mRowContentBindStage.getStageParams(entry);
+ params.requireContentViews(FLAG_CONTENT_VIEW_CONTRACTED);
+ params.requireContentViews(FLAG_CONTENT_VIEW_EXPANDED);
params.setUseIncreasedCollapsedHeight(useIncreasedCollapsedHeight);
params.setUseLowPriority(isLowPriority);
-
- // TODO: Replace this API with RowContentBindParams directly. Also move to a separate
- // redaction controller.
- row.setNeedsRedaction(mNotificationLockscreenUserManager.needsRedaction(entry));
+ boolean needsRedaction =
+ mNotificationLockscreenUserManager.notifNeedsRedactionInPublic(entry);
+ if (needsRedaction) {
+ params.requireContentViews(FLAG_CONTENT_VIEW_PUBLIC);
+ } else {
+ params.markContentViewsFreeable(FLAG_CONTENT_VIEW_PUBLIC);
+ }
params.rebindAllContentViews();
mRowContentBindStage.requestRebind(entry, en -> {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/OnUserInteractionCallbackImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/OnUserInteractionCallbackImpl.java
index 3bd91b5..7dd3672 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/OnUserInteractionCallbackImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/OnUserInteractionCallbackImpl.java
@@ -18,17 +18,17 @@
import static android.service.notification.NotificationStats.DISMISS_SENTIMENT_NEUTRAL;
-import android.annotation.Nullable;
import android.os.SystemClock;
-import android.service.notification.NotificationListenerService;
import android.service.notification.NotificationStats;
+import androidx.annotation.NonNull;
+
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.notification.collection.NotifCollection;
+import com.android.systemui.statusbar.notification.collection.NotifCollection.CancellationReason;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.coordinator.VisualStabilityCoordinator;
import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats;
-import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider;
import com.android.systemui.statusbar.notification.row.OnUserInteractionCallback;
import com.android.systemui.statusbar.policy.HeadsUpManager;
@@ -43,54 +43,33 @@
private final HeadsUpManager mHeadsUpManager;
private final StatusBarStateController mStatusBarStateController;
private final VisualStabilityCoordinator mVisualStabilityCoordinator;
- private final GroupMembershipManager mGroupMembershipManager;
public OnUserInteractionCallbackImpl(
NotificationVisibilityProvider visibilityProvider,
NotifCollection notifCollection,
HeadsUpManager headsUpManager,
StatusBarStateController statusBarStateController,
- VisualStabilityCoordinator visualStabilityCoordinator,
- GroupMembershipManager groupMembershipManager
+ VisualStabilityCoordinator visualStabilityCoordinator
) {
mVisibilityProvider = visibilityProvider;
mNotifCollection = notifCollection;
mHeadsUpManager = headsUpManager;
mStatusBarStateController = statusBarStateController;
mVisualStabilityCoordinator = visualStabilityCoordinator;
- mGroupMembershipManager = groupMembershipManager;
}
- /**
- * Callback triggered when a user:
- * 1. Manually dismisses a notification {@see ExpandableNotificationRow}.
- * 2. Clicks on a notification with flag {@link android.app.Notification#FLAG_AUTO_CANCEL}.
- * {@see StatusBarNotificationActivityStarter}
- */
- @Override
- public void onDismiss(
- NotificationEntry entry,
- @NotificationListenerService.NotificationCancelReason int cancellationReason,
- @Nullable NotificationEntry groupSummaryToDismiss
- ) {
+ @NonNull
+ private DismissedByUserStats getDismissedByUserStats(NotificationEntry entry) {
int dismissalSurface = NotificationStats.DISMISSAL_SHADE;
if (mHeadsUpManager.isAlerting(entry.getKey())) {
dismissalSurface = NotificationStats.DISMISSAL_PEEK;
} else if (mStatusBarStateController.isDozing()) {
dismissalSurface = NotificationStats.DISMISSAL_AOD;
}
-
- if (groupSummaryToDismiss != null) {
- onDismiss(groupSummaryToDismiss, cancellationReason, null);
- }
-
- mNotifCollection.dismissNotification(
- entry,
- new DismissedByUserStats(
- dismissalSurface,
- DISMISS_SENTIMENT_NEUTRAL,
- mVisibilityProvider.obtain(entry, true))
- );
+ return new DismissedByUserStats(
+ dismissalSurface,
+ DISMISS_SENTIMENT_NEUTRAL,
+ mVisibilityProvider.obtain(entry, true));
}
@Override
@@ -100,19 +79,11 @@
SystemClock.uptimeMillis());
}
- /**
- * @param entry that is being dismissed
- * @return the group summary to dismiss along with this entry if this is the last entry in
- * the group. Else, returns null.
- */
+ @NonNull
@Override
- @Nullable
- public NotificationEntry getGroupSummaryToDismiss(NotificationEntry entry) {
- String group = entry.getSbn().getGroup();
- if (mNotifCollection.isOnlyChildInGroup(entry)) {
- NotificationEntry summary = mNotifCollection.getGroupSummary(group);
- if (summary != null && summary.isDismissable()) return summary;
- }
- return null;
+ public Runnable registerFutureDismissal(@NonNull NotificationEntry entry,
+ @CancellationReason int cancellationReason) {
+ return mNotifCollection.registerFutureDismissal(
+ entry, cancellationReason, this::getDismissedByUserStats);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/OnUserInteractionCallbackImplLegacy.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/OnUserInteractionCallbackImplLegacy.java
index 8daf8be..103b14b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/OnUserInteractionCallbackImplLegacy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/OnUserInteractionCallbackImplLegacy.java
@@ -18,12 +18,15 @@
import static android.service.notification.NotificationStats.DISMISS_SENTIMENT_NEUTRAL;
-import android.annotation.Nullable;
import android.service.notification.NotificationListenerService;
import android.service.notification.NotificationStats;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.NotifCollection.CancellationReason;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats;
import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
@@ -68,8 +71,7 @@
* along with this dismissal. If null, does not additionally
* dismiss any notifications.
*/
- @Override
- public void onDismiss(
+ private void onDismiss(
NotificationEntry entry,
@NotificationListenerService.NotificationCancelReason int cancellationReason,
@Nullable NotificationEntry groupSummaryToDismiss
@@ -106,14 +108,21 @@
* @return the group summary to dismiss along with this entry if this is the last entry in
* the group. Else, returns null.
*/
- @Override
@Nullable
- public NotificationEntry getGroupSummaryToDismiss(NotificationEntry entry) {
+ private NotificationEntry getGroupSummaryToDismiss(NotificationEntry entry) {
if (mGroupMembershipManager.isOnlyChildInGroup(entry)) {
NotificationEntry groupSummary = mGroupMembershipManager.getLogicalGroupSummary(entry);
return groupSummary.isDismissable() ? groupSummary : null;
}
return null;
}
+
+ @Override
+ @NonNull
+ public Runnable registerFutureDismissal(@NonNull NotificationEntry entry,
+ @CancellationReason int cancellationReason) {
+ NotificationEntry groupSummaryToDismiss = getGroupSummaryToDismiss(entry);
+ return () -> onDismiss(entry, cancellationReason, groupSummaryToDismiss);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/NotifSection.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/NotifSection.kt
index 263737e..ea66f3b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/NotifSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/NotifSection.kt
@@ -25,12 +25,9 @@
val sectioner: NotifSectioner,
val index: Int
) {
- val label: String
- get() = "Section($index, $bucket, \"${sectioner.name}\")"
-
+ @PriorityBucket
+ val bucket: Int = sectioner.bucket
+ val label: String = "$index:$bucket:${sectioner.name}"
val headerController: NodeController? = sectioner.headerNodeController
-
val comparator: NotifComparator? = sectioner.comparator
-
- @PriorityBucket val bucket: Int = sectioner.bucket
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionLogger.kt
index 7302de5..7e79367 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionLogger.kt
@@ -28,7 +28,9 @@
import com.android.systemui.log.dagger.NotificationLog
import com.android.systemui.statusbar.notification.collection.NotifCollection
import com.android.systemui.statusbar.notification.collection.NotifCollection.CancellationReason
+import com.android.systemui.statusbar.notification.collection.NotifCollection.FutureDismissal
import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.logKey
import javax.inject.Inject
fun cancellationReasonDebugString(@CancellationReason reason: Int) =
@@ -36,6 +38,7 @@
-1 -> "REASON_NOT_CANCELED" // NotifCollection.REASON_NOT_CANCELED
NotifCollection.REASON_UNKNOWN -> "REASON_UNKNOWN"
NotificationListenerService.REASON_CLICK -> "REASON_CLICK"
+ NotificationListenerService.REASON_CANCEL -> "REASON_CANCEL"
NotificationListenerService.REASON_CANCEL_ALL -> "REASON_CANCEL_ALL"
NotificationListenerService.REASON_ERROR -> "REASON_ERROR"
NotificationListenerService.REASON_PACKAGE_CHANGED -> "REASON_PACKAGE_CHANGED"
@@ -53,6 +56,9 @@
NotificationListenerService.REASON_CHANNEL_BANNED -> "REASON_CHANNEL_BANNED"
NotificationListenerService.REASON_SNOOZED -> "REASON_SNOOZED"
NotificationListenerService.REASON_TIMEOUT -> "REASON_TIMEOUT"
+ NotificationListenerService.REASON_CHANNEL_REMOVED -> "REASON_CHANNEL_REMOVED"
+ NotificationListenerService.REASON_CLEAR_DATA -> "REASON_CLEAR_DATA"
+ NotificationListenerService.REASON_ASSISTANT_CANCEL -> "REASON_ASSISTANT_CANCEL"
else -> "unknown"
}
@@ -241,6 +247,81 @@
"ERROR suppressed due to initialization forgiveness: $str1"
})
}
+
+ fun logFutureDismissalReused(dismissal: FutureDismissal) {
+ buffer.log(TAG, INFO, {
+ str1 = dismissal.label
+ }, {
+ "Reusing existing registration: $str1"
+ })
+ }
+
+ fun logFutureDismissalRegistered(dismissal: FutureDismissal) {
+ buffer.log(TAG, DEBUG, {
+ str1 = dismissal.label
+ }, {
+ "Registered: $str1"
+ })
+ }
+
+ fun logFutureDismissalDoubleCancelledByServer(dismissal: FutureDismissal) {
+ buffer.log(TAG, WARNING, {
+ str1 = dismissal.label
+ }, {
+ "System server double cancelled: $str1"
+ })
+ }
+
+ fun logFutureDismissalDoubleRun(dismissal: FutureDismissal) {
+ buffer.log(TAG, WARNING, {
+ str1 = dismissal.label
+ }, {
+ "Double run: $str1"
+ })
+ }
+
+ fun logFutureDismissalAlreadyCancelledByServer(dismissal: FutureDismissal) {
+ buffer.log(TAG, DEBUG, {
+ str1 = dismissal.label
+ }, {
+ "Ignoring: entry already cancelled by server: $str1"
+ })
+ }
+
+ fun logFutureDismissalGotSystemServerCancel(
+ dismissal: FutureDismissal,
+ @CancellationReason cancellationReason: Int
+ ) {
+ buffer.log(TAG, DEBUG, {
+ str1 = dismissal.label
+ int1 = cancellationReason
+ }, {
+ "SystemServer cancelled: $str1 reason=${cancellationReasonDebugString(int1)}"
+ })
+ }
+
+ fun logFutureDismissalDismissing(dismissal: FutureDismissal, type: String) {
+ buffer.log(TAG, DEBUG, {
+ str1 = dismissal.label
+ str2 = type
+ }, {
+ "Dismissing $str2 for: $str1"
+ })
+ }
+
+ fun logFutureDismissalMismatchedEntry(
+ dismissal: FutureDismissal,
+ type: String,
+ latestEntry: NotificationEntry?
+ ) {
+ buffer.log(TAG, WARNING, {
+ str1 = dismissal.label
+ str2 = type
+ str3 = latestEntry.logKey
+ }, {
+ "Mismatch: current $str2 is $str3 for: $str1"
+ })
+ }
}
private const val TAG = "NotifCollection"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilder.kt
index 75a71af..34d25cf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilder.kt
@@ -57,7 +57,6 @@
var currentSection: NotifSection? = null
val prevSections = mutableSetOf<NotifSection?>()
- var lastSection: NotifSection? = null
val showHeaders = sectionHeaderVisibilityProvider.sectionHeadersVisible
val sectionOrder = mutableListOf<NotifSection?>()
val sectionHeaders = mutableMapOf<NotifSection?, NodeController?>()
@@ -65,15 +64,6 @@
for (entry in notifList) {
val section = entry.section!!
-
- lastSection?.let {
- if (it.bucket > section.bucket) {
- throw IllegalStateException("buildNodeSpec with non contiguous section " +
- "buckets ${it.sectioner.name} - ${it.bucket} & " +
- "${it.sectioner.name} - ${it.bucket}")
- }
- }
- lastSection = section
if (prevSections.contains(section)) {
throw java.lang.RuntimeException("Section ${section.label} has been duplicated")
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifStackController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifStackController.kt
index b6278d1..580d853 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifStackController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifStackController.kt
@@ -28,11 +28,21 @@
val hasNonClearableAlertingNotifs: Boolean,
val hasClearableAlertingNotifs: Boolean,
val hasNonClearableSilentNotifs: Boolean,
- val hasClearableSilentNotifs: Boolean
+ val hasClearableSilentNotifs: Boolean,
+ val clearableAlertingSensitiveNotifUsers: Set<Int>,
+ val clearableSilentSensitiveNotifUsers: Set<Int>
) {
companion object {
@JvmStatic
- val empty = NotifStats(0, false, false, false, false)
+ val empty = NotifStats(
+ numActiveNotifs = 0,
+ hasNonClearableAlertingNotifs = false,
+ hasClearableAlertingNotifs = false,
+ hasNonClearableSilentNotifs = false,
+ hasClearableSilentNotifs = false,
+ clearableAlertingSensitiveNotifUsers = emptySet(),
+ clearableSilentSensitiveNotifUsers = emptySet(),
+ )
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationSectionHeadersModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationSectionHeadersModule.kt
index 2a9cfd0..f58918f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationSectionHeadersModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationSectionHeadersModule.kt
@@ -182,4 +182,4 @@
@Scope
@Retention(AnnotationRetention.BINARY)
-annotation class SectionHeaderScope
\ No newline at end of file
+annotation class SectionHeaderScope
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 d96590a..c9c7fe9 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
@@ -88,7 +88,6 @@
import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm;
import com.android.systemui.statusbar.phone.CentralSurfaces;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
-import com.android.systemui.statusbar.phone.NotifActivityLaunchEventsModule;
import com.android.systemui.statusbar.phone.NotifPanelEventsModule;
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
@@ -111,7 +110,6 @@
@Module(includes = {
CoordinatorsModule.class,
KeyguardNotificationVisibilityProviderModule.class,
- NotifActivityLaunchEventsModule.class,
NotifPanelEventsModule.class,
NotifPipelineChoreographerModule.class,
NotificationSectionHeadersModule.class,
@@ -350,8 +348,7 @@
notifCollection.get(),
headsUpManager,
statusBarStateController,
- visualStabilityCoordinator.get(),
- groupMembershipManagerLazy.get())
+ visualStabilityCoordinator.get())
: new OnUserInteractionCallbackImplLegacy(
entryManager,
visibilityProvider.get(),
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconManager.kt
index d896541..015e3d8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconManager.kt
@@ -28,6 +28,7 @@
import com.android.internal.statusbar.StatusBarIcon
import com.android.systemui.R
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.NotificationLockscreenUserManager
import com.android.systemui.statusbar.StatusBarIconView
import com.android.systemui.statusbar.notification.InflationException
import com.android.systemui.statusbar.notification.collection.NotificationEntry
@@ -49,31 +50,29 @@
class IconManager @Inject constructor(
private val notifCollection: CommonNotifCollection,
private val launcherApps: LauncherApps,
- private val iconBuilder: IconBuilder
+ private val iconBuilder: IconBuilder,
+ private val notifLockscreenUserManager: NotificationLockscreenUserManager
) : ConversationIconManager {
private var unimportantConversationKeys: Set<String> = emptySet()
fun attach() {
notifCollection.addCollectionListener(entryListener)
+ notifLockscreenUserManager.addOnNeedsRedactionInPublicChangedListener(sensitivityListener)
}
private val entryListener = object : NotifCollectionListener {
- override fun onEntryInit(entry: NotificationEntry) {
- entry.addOnSensitivityChangedListener(sensitivityListener)
- }
-
- override fun onEntryCleanUp(entry: NotificationEntry) {
- entry.removeOnSensitivityChangedListener(sensitivityListener)
- }
-
override fun onRankingApplied() {
// rankings affect whether a conversation is important, which can change the icons
recalculateForImportantConversationChange()
}
}
- private val sensitivityListener = NotificationEntry.OnSensitivityChangedListener {
- entry -> updateIconsSafe(entry)
+ private val sensitivityListener = Runnable {
+ for (entry in notifCollection.allNotifs) {
+ if (entry.hasSensitiveContents()) {
+ updateIconsSafe(entry)
+ }
+ }
}
private fun recalculateForImportantConversationChange() {
@@ -182,12 +181,16 @@
}
}
+ private inline val NotificationEntry.needsRedactionInPublic: Boolean get() =
+ hasSensitiveContents() &&
+ notifLockscreenUserManager.sensitiveNotifsNeedRedactionInPublic(sbn.userId)
+
@Throws(InflationException::class)
private fun getIconDescriptors(
entry: NotificationEntry
): Pair<StatusBarIcon, StatusBarIcon> {
val iconDescriptor = getIconDescriptor(entry, false /* redact */)
- val sensitiveDescriptor = if (entry.isSensitive) {
+ val sensitiveDescriptor = if (entry.needsRedactionInPublic) {
getIconDescriptor(entry, true /* redact */)
} else {
iconDescriptor
@@ -310,7 +313,7 @@
iconView === entry.icons.shelfIcon || iconView === entry.icons.aodIcon
val isSmallIcon = iconDescriptor.icon.equals(entry.sbn.notification.smallIcon)
return isImportantConversation(entry) && !isSmallIcon &&
- (!usedInSensitiveContext || !entry.isSensitive)
+ (!usedInSensitiveContext || !entry.needsRedactionInPublic)
}
private fun isImportantConversation(entry: NotificationEntry): Boolean {
@@ -338,4 +341,4 @@
* of a group from which the priority notification has been removed.
*/
fun setUnimportantConversations(keys: Collection<String>)
-}
\ No newline at end of file
+}
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 dff8c47..d5088ac 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
@@ -17,7 +17,6 @@
package com.android.systemui.statusbar.notification.row;
import static android.app.Notification.Action.SEMANTIC_ACTION_MARK_CONVERSATION_AS_PRIORITY;
-import static android.os.UserHandle.USER_SYSTEM;
import static android.service.notification.NotificationListenerService.REASON_CANCEL;
import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_HEADSUP;
@@ -34,8 +33,6 @@
import android.app.NotificationChannel;
import android.app.role.RoleManager;
import android.content.Context;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Canvas;
@@ -51,7 +48,6 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.Trace;
-import android.provider.Settings;
import android.service.notification.StatusBarNotification;
import android.util.ArraySet;
import android.util.AttributeSet;
@@ -60,6 +56,7 @@
import android.util.Log;
import android.util.MathUtils;
import android.util.Property;
+import android.util.Slog;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
@@ -93,8 +90,8 @@
import com.android.systemui.statusbar.SmartReplyController;
import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.statusbar.notification.AboveShelfChangedListener;
-import com.android.systemui.statusbar.notification.LaunchAnimationParameters;
import com.android.systemui.statusbar.notification.FeedbackIcon;
+import com.android.systemui.statusbar.notification.LaunchAnimationParameters;
import com.android.systemui.statusbar.notification.NotificationFadeAware;
import com.android.systemui.statusbar.notification.NotificationLaunchAnimatorController;
import com.android.systemui.statusbar.notification.NotificationUtils;
@@ -112,7 +109,6 @@
import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainer;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.notification.stack.SwipeableView;
-import com.android.systemui.statusbar.phone.CentralSurfaces;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.InflatedSmartReplyState;
@@ -206,7 +202,6 @@
/** Are we showing the "public" version */
private boolean mShowingPublic;
private boolean mSensitive;
- private boolean mSensitiveHiddenInGeneral;
private boolean mShowingPublicInitialized;
private boolean mHideSensitiveForIntrinsicHeight;
private float mHeaderVisibleAmount = DEFAULT_HEADER_VISIBLE_AMOUNT;
@@ -364,9 +359,6 @@
@Nullable private OnExpansionChangedListener mExpansionChangedListener;
@Nullable private Runnable mOnIntrinsicHeightReachedRunnable;
- private SystemNotificationAsyncTask mSystemNotificationAsyncTask =
- new SystemNotificationAsyncTask();
-
private float mTopRoundnessDuringLaunchAnimation;
private float mBottomRoundnessDuringLaunchAnimation;
@@ -518,45 +510,20 @@
}
/**
- * Caches whether or not this row contains a system notification. Note, this is only cached
- * once per notification as the packageInfo can't technically change for a notification row.
- */
- private void cacheIsSystemNotification() {
- //TODO: This probably shouldn't be in ExpandableNotificationRow
- if (mEntry != null && mEntry.mIsSystemNotification == null) {
- if (mSystemNotificationAsyncTask.getStatus() == AsyncTask.Status.PENDING) {
- // Run async task once, only if it hasn't already been executed. Note this is
- // executed in serial - no need to parallelize this small task.
- mSystemNotificationAsyncTask.execute();
- }
- }
- }
-
- /**
* Returns whether this row is considered non-blockable (i.e. it's a non-blockable system notif
* or is in an allowList).
*/
public boolean getIsNonblockable() {
- // If the SystemNotifAsyncTask hasn't finished running or retrieved a value, we'll try once
- // again, but in-place on the main thread this time. This should rarely ever get called.
- if (mEntry != null && mEntry.mIsSystemNotification == null) {
- if (DEBUG) {
- Log.d(TAG, "Retrieving isSystemNotification on main thread");
- }
- mSystemNotificationAsyncTask.cancel(true /* mayInterruptIfRunning */);
- mEntry.mIsSystemNotification = isSystemNotification(mContext, mEntry.getSbn());
+ if (mEntry == null || mEntry.getChannel() == null) {
+ Log.w(TAG, "missing entry or channel");
+ return true;
+ }
+ if (mEntry.getChannel().isImportanceLockedByCriticalDeviceFunction()
+ && !mEntry.getChannel().isBlockable()) {
+ return true;
}
- boolean isNonblockable = mEntry.getChannel().isImportanceLockedByCriticalDeviceFunction();
-
- if (!isNonblockable && mEntry != null && mEntry.mIsSystemNotification != null) {
- if (mEntry.mIsSystemNotification) {
- if (mEntry.getChannel() != null && !mEntry.getChannel().isBlockable()) {
- isNonblockable = true;
- }
- }
- }
- return isNonblockable;
+ return false;
}
private boolean isConversation() {
@@ -1456,8 +1423,7 @@
dismiss(fromAccessibility);
if (mEntry.isDismissable()) {
if (mOnUserInteractionCallback != null) {
- mOnUserInteractionCallback.onDismiss(mEntry, REASON_CANCEL,
- mOnUserInteractionCallback.getGroupSummaryToDismiss(mEntry));
+ mOnUserInteractionCallback.registerFutureDismissal(mEntry, REASON_CANCEL).run();
}
}
}
@@ -1538,6 +1504,7 @@
mUseIncreasedHeadsUpHeight = use;
}
+ // TODO: remove this method and mNeedsRedaction entirely once the old pipeline is gone
public void setNeedsRedaction(boolean needsRedaction) {
// TODO: Move inflation logic out of this call and remove this method
if (mNeedsRedaction != needsRedaction) {
@@ -1626,8 +1593,6 @@
mBubblesManagerOptional = bubblesManagerOptional;
mNotificationGutsManager = gutsManager;
mMetricsLogger = metricsLogger;
-
- cacheIsSystemNotification();
}
private void initDimens() {
@@ -2622,9 +2587,8 @@
getShowingLayout().requestSelectLayout(needsAnimation || isUserLocked());
}
- public void setSensitive(boolean sensitive, boolean hideSensitive) {
+ public void setSensitive(boolean sensitive) {
mSensitive = sensitive;
- mSensitiveHiddenInGeneral = hideSensitive;
}
@Override
@@ -2714,7 +2678,15 @@
* see {@link NotificationEntry#isDismissable()}.
*/
public boolean canViewBeDismissed() {
- return mEntry.isDismissable() && (!shouldShowPublic() || !mSensitiveHiddenInGeneral);
+ // Entry not dismissable.
+ if (!mEntry.isDismissable()) {
+ return false;
+ }
+ // Entry shouldn't be showing the public layout, it can be dismissed.
+ if (!shouldShowPublic()) {
+ return true;
+ }
+ return false;
}
/**
@@ -2723,7 +2695,7 @@
* clearability see {@link NotificationEntry#isClearable()}.
*/
public boolean canViewBeCleared() {
- return mEntry.isClearable() && (!shouldShowPublic() || !mSensitiveHiddenInGeneral);
+ return mEntry.isClearable() && !shouldShowPublic();
}
private boolean shouldShowPublic() {
@@ -3487,10 +3459,28 @@
pw.print(", translation: " + getTranslation());
pw.print(", removed: " + isRemoved());
pw.print(", expandAnimationRunning: " + mExpandAnimationRunning);
- NotificationContentView showingLayout = getShowingLayout();
- pw.print(", privateShowing: " + (showingLayout == mPrivateLayout));
- pw.println();
- showingLayout.dump(pw, args);
+ pw.print(", sensitive: " + mSensitive);
+ pw.print(", hideSensitiveForIntrinsicHeight: " + mHideSensitiveForIntrinsicHeight);
+ pw.println(", privateShowing: " + !shouldShowPublic());
+ pw.print("privateLayout: ");
+ if (mPrivateLayout != null) {
+ pw.println();
+ DumpUtilsKt.withIncreasedIndent(pw, () -> {
+ mPrivateLayout.dump(pw, args);
+ mPrivateLayout.dumpSmartReplies(pw);
+ });
+ } else {
+ pw.println("null");
+ }
+ pw.print("publicLayout: ");
+ if (mPublicLayout != null) {
+ pw.println();
+ DumpUtilsKt.withIncreasedIndent(pw, () -> {
+ mPublicLayout.dump(pw, args);
+ });
+ } else {
+ pw.println("null");
+ }
if (getViewState() != null) {
getViewState().dump(pw, args);
@@ -3516,31 +3506,10 @@
}
pw.decreaseIndent();
pw.println("}");
- } else if (mPrivateLayout != null) {
- mPrivateLayout.dumpSmartReplies(pw);
}
});
}
- /**
- * Background task for executing IPCs to check if the notification is a system notification. The
- * output is used for both the blocking helper and the notification info.
- */
- private class SystemNotificationAsyncTask extends AsyncTask<Void, Void, Boolean> {
-
- @Override
- protected Boolean doInBackground(Void... voids) {
- return isSystemNotification(mContext, mEntry.getSbn());
- }
-
- @Override
- protected void onPostExecute(Boolean result) {
- if (mEntry != null) {
- mEntry.mIsSystemNotification = result;
- }
- }
- }
-
private void setTargetPoint(Point p) {
mTargetPoint = p;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
index 599039d..a60026c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
@@ -35,6 +35,7 @@
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shared.plugins.PluginManager;
+import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.SmartReplyController;
import com.android.systemui.statusbar.notification.FeedbackIcon;
@@ -69,6 +70,7 @@
public class ExpandableNotificationRowController implements NotifViewController {
private static final String TAG = "NotifRowController";
private final ExpandableNotificationRow mView;
+ private final NotificationLockscreenUserManager mLockscreenUserManager;
private final NotificationListContainer mListContainer;
private final RemoteInputViewSubcomponent.Factory mRemoteInputViewSubcomponentFactory;
private final ActivatableNotificationViewController mActivatableNotificationViewController;
@@ -86,7 +88,6 @@
private final ExpandableNotificationRow.OnExpandClickListener mOnExpandClickListener;
private final StatusBarStateController mStatusBarStateController;
private final MetricsLogger mMetricsLogger;
-
private final ExpandableNotificationRow.ExpansionLogger mExpansionLogger =
this::logNotificationExpansion;
private final ExpandableNotificationRow.CoordinateOnClickListener mOnFeedbackClickListener;
@@ -100,12 +101,12 @@
private final Optional<BubblesManager> mBubblesManagerOptional;
private final SmartReplyConstants mSmartReplyConstants;
private final SmartReplyController mSmartReplyController;
-
private final ExpandableNotificationRowDragController mDragController;
@Inject
public ExpandableNotificationRowController(
ExpandableNotificationRow view,
+ NotificationLockscreenUserManager lockscreenUserManager,
ActivatableNotificationViewController activatableNotificationViewController,
RemoteInputViewSubcomponent.Factory rivSubcomponentFactory,
MetricsLogger metricsLogger,
@@ -135,6 +136,7 @@
Optional<BubblesManager> bubblesManagerOptional,
ExpandableNotificationRowDragController dragController) {
mView = view;
+ mLockscreenUserManager = lockscreenUserManager;
mListContainer = listContainer;
mRemoteInputViewSubcomponentFactory = rivSubcomponentFactory;
mActivatableNotificationViewController = activatableNotificationViewController;
@@ -214,6 +216,10 @@
mView.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
}
+ mLockscreenUserManager
+ .addOnNeedsRedactionInPublicChangedListener(mNeedsRedactionListener);
+ mNeedsRedactionListener.run();
+
mView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
@Override
public void onViewAttachedToWindow(View v) {
@@ -232,6 +238,14 @@
});
}
+ private final Runnable mNeedsRedactionListener = new Runnable() {
+ @Override
+ public void run() {
+ mView.setSensitive(
+ mLockscreenUserManager.notifNeedsRedactionInPublic(mView.getEntry()));
+ }
+ };
+
private final StatusBarStateController.StateListener mStatusBarStateListener =
new StatusBarStateController.StateListener() {
@Override
@@ -333,4 +347,5 @@
public void setFeedbackIcon(@Nullable FeedbackIcon icon) {
mView.setFeedbackIcon(icon);
}
+
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index ba26cfa..a7c6bfb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -61,6 +61,7 @@
import com.android.systemui.statusbar.policy.SmartReplyView;
import com.android.systemui.statusbar.policy.dagger.RemoteInputViewSubcomponent;
import com.android.systemui.util.Compile;
+import com.android.systemui.util.DumpUtilsKt;
import com.android.systemui.wmshell.BubblesManager;
import java.io.PrintWriter;
@@ -1994,22 +1995,33 @@
}
}
- public void dump(PrintWriter pw, String[] args) {
+ public void dump(PrintWriter pwOriginal, String[] args) {
+ IndentingPrintWriter pw = DumpUtilsKt.asIndenting(pwOriginal);
pw.print("contentView visibility: " + getVisibility());
pw.print(", alpha: " + getAlpha());
pw.print(", clipBounds: " + getClipBounds());
pw.print(", contentHeight: " + mContentHeight);
- pw.print(", visibleType: " + mVisibleType);
- View view = getViewForVisibleType(mVisibleType);
- pw.print(", visibleView ");
- if (view != null) {
- pw.print(" visibility: " + view.getVisibility());
- pw.print(", alpha: " + view.getAlpha());
- pw.print(", clipBounds: " + view.getClipBounds());
- } else {
- pw.print("null");
- }
- pw.println();
+ pw.println(", currentVisibleType: " + mVisibleType);
+ DumpUtilsKt.withIncreasedIndent(pw, () -> {
+ int[] visTypes = {
+ VISIBLE_TYPE_CONTRACTED,
+ VISIBLE_TYPE_EXPANDED,
+ VISIBLE_TYPE_HEADSUP,
+ VISIBLE_TYPE_SINGLELINE
+ };
+ for (int visType : visTypes) {
+ pw.print("visType: " + visType + " :: ");
+ View view = getViewForVisibleType(visType);
+ if (view != null) {
+ pw.print("visibility: " + view.getVisibility());
+ pw.print(", alpha: " + view.getAlpha());
+ pw.print(", clipBounds: " + view.getClipBounds());
+ } else {
+ pw.print("null");
+ }
+ pw.println();
+ }
+ });
}
/** Add any existing SmartReplyView to the dump */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/OnUserInteractionCallback.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/OnUserInteractionCallback.java
index 94c5507..98d4353 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/OnUserInteractionCallback.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/OnUserInteractionCallback.java
@@ -16,8 +16,9 @@
package com.android.systemui.statusbar.notification.row;
-import android.service.notification.NotificationListenerService;
+import androidx.annotation.NonNull;
+import com.android.systemui.statusbar.notification.collection.NotifCollection.CancellationReason;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
/**
@@ -26,29 +27,23 @@
public interface OnUserInteractionCallback {
/**
- * Handle a user interaction that triggers a notification dismissal. Called when a user clicks
- * on an auto-cancelled notification or manually swipes to dismiss the notification.
- *
- * @param entry notification being dismissed
- * @param cancellationReason reason for the cancellation
- * @param groupSummaryToDismiss group summary to dismiss with `entry`.
- */
- void onDismiss(
- NotificationEntry entry,
- @NotificationListenerService.NotificationCancelReason int cancellationReason,
- NotificationEntry groupSummaryToDismiss);
-
- /**
* Triggered after a user has changed the importance of the notification via its
* {@link NotificationGuts}.
*/
void onImportanceChanged(NotificationEntry entry);
-
/**
- * @param entry being dismissed by the user
- * @return group summary that should be dismissed along with `entry`. Can be null if no
- * relevant group summary exists or the group summary should not be dismissed with `entry`.
+ * Called once it is known that a dismissal will take place for the given reason.
+ * This returns a Runnable which MUST be invoked when the dismissal is ready to be completed.
+ *
+ * Registering for future dismissal is typically done before notifying the NMS that a
+ * notification was clicked or dismissed, but the local dismissal may happen later.
+ *
+ * @param entry the entry being cancelled
+ * @param cancellationReason the reason for the cancellation
+ * @return the runnable to call when the dismissal can happen
*/
- NotificationEntry getGroupSummaryToDismiss(NotificationEntry entry);
+ @NonNull
+ Runnable registerFutureDismissal(@NonNull NotificationEntry entry,
+ @CancellationReason int cancellationReason);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindParams.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindParams.java
index f26ecc3..a52f638 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindParams.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindParams.java
@@ -102,8 +102,9 @@
* @see InflationFlag
*/
public void markContentViewsFreeable(@InflationFlag int contentViews) {
+ @InflationFlag int existingContentViews = contentViews &= mContentViews;
mContentViews &= ~contentViews;
- mDirtyContentViews &= ~contentViews;
+ mDirtyContentViews |= existingContentViews;
}
public @InflationFlag int getContentViews() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java
index aa3e027..7414bdc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.notification.row;
+import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.content.Context;
import android.util.AttributeSet;
@@ -25,6 +26,8 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.animation.Interpolators;
+import java.util.function.Consumer;
+
/**
* A common base class for all views in the notification stack scroller which don't have a
* background.
@@ -48,7 +51,7 @@
};
private boolean mSecondaryAnimating = false;
- private final Runnable mSecondaryVisibilityEndRunnable = () -> {
+ private final Consumer<Boolean> mSecondaryVisibilityEndRunnable = (cancelled) -> {
mSecondaryAnimating = false;
// If we were on screen, become GONE to avoid touches
if (mSecondaryView == null) return;
@@ -96,18 +99,20 @@
* @param animate True if we should fade to new visibility
* @param runAfter Runnable to run after visibility updates
*/
- public void setContentVisible(boolean visible, boolean animate, Runnable runAfter) {
+ public void setContentVisible(boolean visible, boolean animate, Consumer<Boolean> runAfter) {
if (mContentVisible != visible) {
mContentAnimating = animate;
mContentVisible = visible;
- Runnable endRunnable = runAfter == null ? mContentVisibilityEndRunnable : () -> {
+ Consumer<Boolean> endRunnable = (cancelled) -> {
mContentVisibilityEndRunnable.run();
- runAfter.run();
+ if (runAfter != null) {
+ runAfter.accept(cancelled);
+ }
};
setViewVisible(mContent, visible, animate, endRunnable);
} else if (runAfter != null) {
// Execute the runAfter runnable immediately if there's no animation to perform.
- runAfter.run();
+ runAfter.accept(true);
}
if (!mContentAnimating) {
@@ -119,10 +124,6 @@
return mContentVisible;
}
- public void setVisible(boolean nowVisible, boolean animate) {
- setVisible(nowVisible, animate, null);
- }
-
/**
* Make this view visible. If {@code false} is passed, the view will fade out it's content
* and set the view Visibility to GONE. If only the content should be changed
@@ -131,7 +132,7 @@
* @param nowVisible should the view be visible
* @param animate should the change be animated.
*/
- public void setVisible(boolean nowVisible, boolean animate, Runnable runAfter) {
+ public void setVisible(boolean nowVisible, boolean animate) {
if (mIsVisible != nowVisible) {
mIsVisible = nowVisible;
if (animate) {
@@ -142,10 +143,10 @@
} else {
setWillBeGone(true);
}
- setContentVisible(nowVisible, true /* animate */, runAfter);
+ setContentVisible(nowVisible, true /* animate */, null /* runAfter */);
} else {
setVisibility(nowVisible ? VISIBLE : GONE);
- setContentVisible(nowVisible, false /* animate */, runAfter);
+ setContentVisible(nowVisible, false /* animate */, null /* runAfter */);
setWillBeGone(false);
notifyHeightChanged(false /* needsAnimation */);
}
@@ -166,7 +167,7 @@
}
if (!mSecondaryAnimating) {
- mSecondaryVisibilityEndRunnable.run();
+ mSecondaryVisibilityEndRunnable.accept(true /* cancelled */);
}
}
@@ -195,7 +196,7 @@
* @param endRunnable A runnable that is run when the animation is done.
*/
private void setViewVisible(View view, boolean nowVisible,
- boolean animate, Runnable endRunnable) {
+ boolean animate, Consumer<Boolean> endRunnable) {
if (view == null) {
return;
}
@@ -211,7 +212,7 @@
if (!animate) {
view.setAlpha(endValue);
if (endRunnable != null) {
- endRunnable.run();
+ endRunnable.accept(true);
}
return;
}
@@ -222,7 +223,19 @@
.alpha(endValue)
.setInterpolator(interpolator)
.setDuration(mDuration)
- .withEndAction(endRunnable);
+ .setListener(new AnimatorListenerAdapter() {
+ boolean mCancelled;
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ mCancelled = true;
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ endRunnable.accept(mCancelled);
+ }
+ });
}
@Override
@@ -231,7 +244,7 @@
Runnable onFinishedRunnable,
AnimatorListenerAdapter animationListener) {
// TODO: Use duration
- setContentVisible(false, true /* animate */, onFinishedRunnable);
+ setContentVisible(false, true /* animate */, (cancelled) -> onFinishedRunnable.run());
return 0;
}
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 3ea5e5b..4d325e1 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
@@ -1805,13 +1805,20 @@
}
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
- public void dismissViewAnimated(View child, Runnable endRunnable, int delay, long duration) {
+ public void dismissViewAnimated(
+ View child, Consumer<Boolean> endRunnable, int delay, long duration) {
if (child instanceof SectionHeaderView) {
((StackScrollerDecorView) child).setContentVisible(
false /* visible */, true /* animate */, endRunnable);
return;
}
- mSwipeHelper.dismissChild(child, 0, endRunnable, delay, true, duration,
+ mSwipeHelper.dismissChild(
+ child,
+ 0 /* velocity */,
+ endRunnable,
+ delay,
+ true /* useAccelerateInterpolator */,
+ duration,
true /* isClearAll */);
}
@@ -5196,11 +5203,15 @@
if (mClearAllListener != null) {
mClearAllListener.onClearAll(selection);
}
- final Runnable dismissInBackend = () -> {
- onClearAllAnimationsEnd(rowsToDismissInBackend, selection);
+ final Consumer<Boolean> dismissInBackend = (cancelled) -> {
+ if (cancelled) {
+ post(() -> onClearAllAnimationsEnd(rowsToDismissInBackend, selection));
+ } else {
+ onClearAllAnimationsEnd(rowsToDismissInBackend, selection);
+ }
};
if (viewsToAnimateAway.isEmpty()) {
- dismissInBackend.run();
+ dismissInBackend.accept(true);
return;
}
// Disable normal animations
@@ -5215,7 +5226,7 @@
final int numItems = viewsToAnimateAway.size();
for (int i = numItems - 1; i >= 0; i--) {
View view = viewsToAnimateAway.get(i);
- Runnable endRunnable = null;
+ Consumer<Boolean> endRunnable = null;
if (i == 0) {
endRunnable = dismissInBackend;
}
@@ -5517,6 +5528,7 @@
*/
public void setFractionToShade(float fraction) {
mAmbientState.setFractionToShade(fraction);
+ updateContentHeight(); // Recompute stack height with different section gap.
requestChildrenUpdate();
}
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 2493ccb..6a8f479 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
@@ -216,6 +216,9 @@
mBarState = mStatusBarStateController.getState();
mStatusBarStateController.addCallback(
mStateListener, SysuiStatusBarStateController.RANK_STACK_SCROLLER);
+ mLockscreenUserManager.addOnNeedsRedactionInPublicChangedListener(
+ mOnNeedsRedactionInPublicChangedListener);
+ updateClearButtonVisibility();
}
@Override
@@ -223,6 +226,8 @@
mConfigurationController.removeCallback(mConfigurationListener);
mZenModeController.removeCallback(mZenModeControllerCallback);
mStatusBarStateController.removeCallback(mStateListener);
+ mLockscreenUserManager.removeOnNeedsRedactionInPublicChangedListener(
+ mOnNeedsRedactionInPublicChangedListener);
}
};
@@ -326,6 +331,7 @@
mLockscreenUserManager.isAnyProfilePublicMode());
mView.onStatePostChange(mStatusBarStateController.fromShadeLocked());
mNotificationEntryManager.updateNotifications("CentralSurfaces state changed");
+ updateClearButtonVisibility();
}
};
@@ -338,6 +344,17 @@
}
};
+ private final Runnable mOnNeedsRedactionInPublicChangedListener = new Runnable() {
+ @Override
+ public void run() {
+ // Whether or not the notification needs redaction when in public has changed, but if
+ // we're not actually in public, then we don't need to update anything.
+ if (mLockscreenUserManager.isAnyProfilePublicMode()) {
+ updateClearButtonVisibility();
+ }
+ }
+ };
+
/**
* Set the overexpansion of the panel to be applied to the view.
*/
@@ -1274,12 +1291,44 @@
return hasNotifications(selection, true /* clearable */);
}
+ private boolean hasRedactedClearableSilentNotifs() {
+ if (!mLockscreenUserManager.isAnyProfilePublicMode()) {
+ return false;
+ }
+ for (int userId : mNotifStats.getClearableSilentSensitiveNotifUsers()) {
+ if (mLockscreenUserManager.sensitiveNotifsNeedRedactionInPublic(userId)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean hasClearableSilentNotifs() {
+ return mNotifStats.getHasClearableSilentNotifs() && !hasRedactedClearableSilentNotifs();
+ }
+
+ private boolean hasRedactedClearableAlertingNotifs() {
+ if (!mLockscreenUserManager.isAnyProfilePublicMode()) {
+ return false;
+ }
+ for (int userId : mNotifStats.getClearableAlertingSensitiveNotifUsers()) {
+ if (mLockscreenUserManager.sensitiveNotifsNeedRedactionInPublic(userId)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean hasClearableAlertingNotifs() {
+ return mNotifStats.getHasClearableAlertingNotifs() && !hasRedactedClearableAlertingNotifs();
+ }
+
public boolean hasNotifications(@SelectedRows int selection, boolean isClearable) {
boolean hasAlertingMatchingClearable = isClearable
- ? mNotifStats.getHasClearableAlertingNotifs()
+ ? hasClearableAlertingNotifs()
: mNotifStats.getHasNonClearableAlertingNotifs();
boolean hasSilentMatchingClearable = isClearable
- ? mNotifStats.getHasClearableSilentNotifs()
+ ? hasClearableSilentNotifs()
: mNotifStats.getHasNonClearableSilentNotifs();
switch (selection) {
case ROWS_GENTLE:
@@ -1579,6 +1628,15 @@
mNotificationActivityStarter = activityStarter;
}
+ private void updateClearButtonVisibility() {
+ updateClearSilentButton();
+ updateFooter();
+ }
+
+ private void updateClearSilentButton() {
+ mSilentHeaderController.setClearSectionEnabled(hasClearableSilentNotifs());
+ }
+
/**
* Enum for UiEvent logged from this class
*/
@@ -1904,6 +1962,7 @@
@Override
public void setNotifStats(@NonNull NotifStats notifStats) {
mNotifStats = notifStats;
+ updateClearSilentButton();
updateFooter();
updateShowEmptyShadeView();
}
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 2b79986..799fee5 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
@@ -49,9 +49,10 @@
public static final float START_FRACTION = 0.5f;
- private static final String LOG_TAG = "StackScrollAlgorithm";
- private final ViewGroup mHostView;
+ private static final String TAG = "StackScrollAlgorithm";
+ private static final Boolean DEBUG = false;
+ private final ViewGroup mHostView;
private int mPaddingBetweenElements;
private int mGapHeight;
private int mGapHeightOnLockscreen;
@@ -126,6 +127,37 @@
return getExpansionFractionWithoutShelf(mTempAlgorithmState, ambientState);
}
+ private void log(String s) {
+ if (DEBUG) {
+ android.util.Log.i(TAG, s);
+ }
+ }
+
+ public void logView(View view, String s) {
+ String viewString = "";
+ if (view instanceof ExpandableNotificationRow) {
+ ExpandableNotificationRow row = ((ExpandableNotificationRow) view);
+ if (row.getEntry() == null) {
+ viewString = "ExpandableNotificationRow has null NotificationEntry";
+ } else {
+ viewString = row.getEntry().getSbn().getId() + "";
+ }
+ } else if (view == null) {
+ viewString = "View is null";
+ } else if (view instanceof SectionHeaderView) {
+ viewString = "SectionHeaderView";
+ } else if (view instanceof FooterView) {
+ viewString = "FooterView";
+ } else if (view instanceof MediaContainerView) {
+ viewString = "MediaContainerView";
+ } else if (view instanceof EmptyShadeView) {
+ viewString = "EmptyShadeView";
+ } else {
+ viewString = view.toString();
+ }
+ log(viewString + " " + s);
+ }
+
private void resetChildViewStates() {
int numChildren = mHostView.getChildCount();
for (int i = 0; i < numChildren; i++) {
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 4b4b84b..6b018b5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -2496,6 +2496,12 @@
animate, intent.getPackage(), (adapter) -> {
ActivityOptions options = new ActivityOptions(
CentralSurfaces.getActivityOptions(mDisplayId, adapter));
+
+ // We know that the intent of the caller is to dismiss the keyguard and
+ // this runnable is called right after the keyguard is solved, so we tell
+ // WM that we should dismiss it to avoid flickers when opening an activity
+ // that can also be shown over the keyguard.
+ options.setDismissKeyguard();
options.setDisallowEnterPictureInPictureWhileLaunching(
disallowEnterPictureInPictureWhileLaunching);
if (CameraIntents.isInsecureCameraIntent(intent)) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
index 9863a0e..f386797 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
@@ -29,6 +29,7 @@
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.CrossFadeHelper;
import com.android.systemui.statusbar.HeadsUpStatusBarView;
+import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -40,8 +41,8 @@
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
import com.android.systemui.util.ViewController;
-import java.util.Optional;
import java.util.ArrayList;
+import java.util.Optional;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
@@ -61,17 +62,17 @@
private final NotificationIconAreaController mNotificationIconAreaController;
private final HeadsUpManagerPhone mHeadsUpManager;
private final NotificationStackScrollLayoutController mStackScrollerController;
-
private final DarkIconDispatcher mDarkIconDispatcher;
private final NotificationPanelViewController mNotificationPanelViewController;
- private final Consumer<ExpandableNotificationRow>
- mSetTrackingHeadsUp = this::setTrackingHeadsUp;
+ private final Consumer<ExpandableNotificationRow> mSetTrackingHeadsUp =
+ this::setTrackingHeadsUp;
private final BiConsumer<Float, Float> mSetExpandedHeight = this::setAppearFraction;
private final KeyguardBypassController mBypassController;
private final StatusBarStateController mStatusBarStateController;
private final CommandQueue mCommandQueue;
private final NotificationWakeUpCoordinator mWakeUpCoordinator;
-
+ private final NotificationLockscreenUserManager mNotifLockscreenUserManager;
+ private final Runnable mRedactionChanged = this::updateRedaction;
private final View mClockView;
private final Optional<View> mOperatorNameViewOptional;
@@ -90,6 +91,13 @@
};
private boolean mAnimationsEnabled = true;
private final KeyguardStateController mKeyguardStateController;
+ private final StatusBarStateController.StateListener mStatusBarStateListener =
+ new StatusBarStateController.StateListener() {
+ @Override
+ public void onStatePostChange() {
+ updateRedaction();
+ }
+ };
@VisibleForTesting
@Inject
@@ -98,6 +106,7 @@
HeadsUpManagerPhone headsUpManager,
StatusBarStateController stateController,
KeyguardBypassController bypassController,
+ NotificationLockscreenUserManager notifLockscreenUserManager,
NotificationWakeUpCoordinator wakeUpCoordinator,
DarkIconDispatcher darkIconDispatcher,
KeyguardStateController keyguardStateController,
@@ -125,6 +134,7 @@
mClockView = clockView;
mOperatorNameViewOptional = operatorNameViewOptional;
mDarkIconDispatcher = darkIconDispatcher;
+ mNotifLockscreenUserManager = notifLockscreenUserManager;
mView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
@Override
@@ -156,6 +166,8 @@
mNotificationPanelViewController.setHeadsUpAppearanceController(this);
mStackScrollerController.addOnExpandedHeightChangedListener(mSetExpandedHeight);
mDarkIconDispatcher.addDarkReceiver(this);
+ mNotifLockscreenUserManager.addOnNeedsRedactionInPublicChangedListener(mRedactionChanged);
+ mStatusBarStateController.addCallback(mStatusBarStateListener);
}
@Override
@@ -167,6 +179,9 @@
mNotificationPanelViewController.setHeadsUpAppearanceController(null);
mStackScrollerController.removeOnExpandedHeightChangedListener(mSetExpandedHeight);
mDarkIconDispatcher.removeDarkReceiver(this);
+ mNotifLockscreenUserManager
+ .removeOnNeedsRedactionInPublicChangedListener(mRedactionChanged);
+ mStatusBarStateController.removeCallback(mStatusBarStateListener);
}
private void updateIsolatedIconLocation(boolean requireStateUpdate) {
@@ -180,6 +195,19 @@
updateHeader(entry);
}
+ private void updateRedaction() {
+ NotificationEntry showingEntry = mView.getShowingEntry();
+ if (showingEntry == null) {
+ return;
+ }
+ int notifUserId = showingEntry.getSbn().getUserId();
+ boolean redactSensitiveContent =
+ mNotifLockscreenUserManager.isLockscreenPublicMode(notifUserId)
+ && mNotifLockscreenUserManager
+ .sensitiveNotifsNeedRedactionInPublic(notifUserId);
+ mView.setRedactSensitiveContent(redactSensitiveContent);
+ }
+
private void updateTopEntry() {
NotificationEntry newEntry = null;
if (shouldBeVisible()) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index 347e05c..fd307df 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -1198,15 +1198,19 @@
if (tileIcon != null) {
mWalletButton.setImageDrawable(tileIcon);
}
- updateWalletVisibility();
- updateAffordanceColors();
+ post(() -> {
+ updateWalletVisibility();
+ updateAffordanceColors();
+ });
}
@Override
public void onWalletCardRetrievalError(@NonNull GetWalletCardsError error) {
mHasCard = false;
- updateWalletVisibility();
- updateAffordanceColors();
+ post(() -> {
+ updateWalletVisibility();
+ updateAffordanceColors();
+ });
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index 0b72138..8792118 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -188,6 +188,10 @@
}
if (mContainer.getVisibility() == View.VISIBLE || mShowingSoon) {
+ // Calls to reset must resume the ViewControllers when in fullscreen mode
+ if (needsFullscreenBouncer()) {
+ mKeyguardViewController.onResume();
+ }
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NPVCDownEventState.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NPVCDownEventState.kt
index 0623507..d44a569 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NPVCDownEventState.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NPVCDownEventState.kt
@@ -14,9 +14,9 @@
package com.android.systemui.statusbar.phone
import android.view.MotionEvent
-import com.android.internal.util.RingBuffer
import com.android.systemui.dump.DumpsysTableLogger
import com.android.systemui.dump.Row
+import com.android.systemui.util.collection.RingBuffer
import java.text.SimpleDateFormat
import java.util.Locale
@@ -67,16 +67,9 @@
* Do not use [append] to add new elements. Instead use [insert], as it will recycle if
* necessary.
*/
- class Buffer(
- capacity: Int
- ) : RingBuffer<NPVCDownEventState>(NPVCDownEventState::class.java, capacity) {
- override fun append(t: NPVCDownEventState?) {
- throw UnsupportedOperationException("Not supported, use insert instead")
- }
+ class Buffer(capacity: Int) {
- override fun createNewItem(): NPVCDownEventState {
- return NPVCDownEventState()
- }
+ private val buffer = RingBuffer(capacity) { NPVCDownEventState() }
/**
* Insert a new element in the buffer.
@@ -94,7 +87,7 @@
touchSlopExceededBeforeDown: Boolean,
lastEventSynthesized: Boolean
) {
- nextSlot.apply {
+ buffer.advance().apply {
this.timeStamp = timeStamp
this.x = x
this.y = y
@@ -115,7 +108,7 @@
* @see NPVCDownEventState.asStringList
*/
fun toList(): List<Row> {
- return toArray().map { it.asStringList }
+ return buffer.asSequence().map { it.asStringList }.toList()
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotifActivityLaunchEvents.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotifActivityLaunchEvents.kt
deleted file mode 100644
index f46d073..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotifActivityLaunchEvents.kt
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.phone
-
-import com.android.systemui.statusbar.notification.collection.NotificationEntry
-
-/** Provides events about [android.app.Activity] launches from Notifications. */
-interface NotifActivityLaunchEvents {
-
- /** Registers a [Listener] to be invoked when notification activity launch events occur. */
- fun registerListener(listener: Listener)
-
- /** Unregisters a [Listener] previously registered via [registerListener] */
- fun unregisterListener(listener: Listener)
-
- /** Listener for events about [android.app.Activity] launches from Notifications. */
- interface Listener {
-
- /** Invoked when an activity has started launching from a notification. */
- fun onStartLaunchNotifActivity(entry: NotificationEntry)
-
- /** Invoked when an activity has finished launching. */
- fun onFinishLaunchNotifActivity(entry: NotificationEntry)
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotifActivityLaunchEventsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotifActivityLaunchEventsModule.java
deleted file mode 100644
index 84ff538..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotifActivityLaunchEventsModule.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.phone;
-
-import com.android.systemui.dagger.SysUISingleton;
-
-import dagger.Binds;
-import dagger.Module;
-
-/** Provides a {@link NotifActivityLaunchEvents} in {@link SysUISingleton} scope. */
-@Module
-public abstract class NotifActivityLaunchEventsModule {
- @Binds
- abstract NotifActivityLaunchEvents bindLaunchEvents(
- StatusBarNotificationActivityStarter.LaunchEventsEmitter impl);
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index 77b9efa..075df1a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -32,7 +32,6 @@
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
import static com.android.systemui.statusbar.StatusBarState.SHADE;
-import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_ALL;
import static com.android.systemui.statusbar.notification.stack.StackStateAnimator.ANIMATION_DURATION_FOLD_TO_AOD;
import static com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManagerKt.STATE_CLOSED;
import static com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManagerKt.STATE_OPEN;
@@ -323,7 +322,7 @@
private final LargeScreenShadeHeaderController mLargeScreenShadeHeaderController;
private final RecordingController mRecordingController;
private final PanelEventsEmitter mPanelEventsEmitter;
- private boolean mShouldUseSplitNotificationShade;
+ private boolean mSplitShadeEnabled;
// The bottom padding reserved for elements of the keyguard measuring notifications
private float mKeyguardNotificationBottomPadding;
/**
@@ -814,7 +813,7 @@
mKeyguardUserSwitcherComponentFactory = keyguardUserSwitcherComponentFactory;
mFragmentService = fragmentService;
mSettingsChangeObserver = new SettingsChangeObserver(handler);
- mShouldUseSplitNotificationShade =
+ mSplitShadeEnabled =
LargeScreenUtils.shouldUseSplitNotificationShade(mResources);
mView.setWillNotDraw(!DEBUG);
mLargeScreenShadeHeaderController = largeScreenShadeHeaderController;
@@ -1029,7 +1028,7 @@
});
mView.setAccessibilityDelegate(mAccessibilityDelegate);
- if (mShouldUseSplitNotificationShade) {
+ if (mSplitShadeEnabled) {
updateResources();
}
@@ -1126,20 +1125,18 @@
mSplitShadeNotificationsScrimMarginBottom =
mResources.getDimensionPixelSize(
R.dimen.split_shade_notifications_scrim_margin_bottom);
-
mShelfAndLockIconOverlap =
mResources.getDimensionPixelSize(R.dimen.shelf_and_lock_icon_overlap);
- final boolean newShouldUseSplitNotificationShade =
+ final boolean newSplitShadeEnabled =
LargeScreenUtils.shouldUseSplitNotificationShade(mResources);
- final boolean splitNotificationShadeChanged =
- mShouldUseSplitNotificationShade != newShouldUseSplitNotificationShade;
+ final boolean splitShadeChanged = mSplitShadeEnabled != newSplitShadeEnabled;
+ mSplitShadeEnabled = newSplitShadeEnabled;
- mShouldUseSplitNotificationShade = newShouldUseSplitNotificationShade;
boolean useLargeScreenShadeHeader =
LargeScreenUtils.shouldUseLargeScreenShadeHeader(mView.getResources());
if (mQs != null) {
- mQs.setInSplitShade(mShouldUseSplitNotificationShade);
+ mQs.setInSplitShade(mSplitShadeEnabled);
}
mLargeScreenShadeHeaderHeight =
mResources.getDimensionPixelSize(R.dimen.large_screen_shade_header_height);
@@ -1155,7 +1152,12 @@
mKeyguardMediaController.refreshMediaPosition();
- if (splitNotificationShadeChanged) {
+ if (splitShadeChanged) {
+ // when we switch from split shade to regular shade we want to enforce setting qs to
+ // the default state: expanded for split shade and collapsed otherwise
+ if (!isOnKeyguard() && mPanelExpanded) {
+ setQsExpanded(mSplitShadeEnabled);
+ }
updateClockAppearance();
updateQsState();
mNotificationStackScrollLayoutController.updateFooter();
@@ -1384,7 +1386,7 @@
updateClockAppearance();
}
if (!onKeyguard) {
- if (mShouldUseSplitNotificationShade) {
+ if (mSplitShadeEnabled) {
// Quick settings are not on the top of the notifications
// when in split shade mode (they are on the left side),
// so we should not add a padding for them
@@ -1412,10 +1414,9 @@
.getVisibleNotificationCount() != 0
|| mMediaDataManager.hasActiveMediaOrRecommendation();
boolean splitShadeWithActiveMedia =
- mShouldUseSplitNotificationShade
- && mMediaDataManager.hasActiveMediaOrRecommendation();
+ mSplitShadeEnabled && mMediaDataManager.hasActiveMediaOrRecommendation();
boolean shouldAnimateClockChange = mScreenOffAnimationController.shouldAnimateClockChange();
- if ((hasVisibleNotifications && !mShouldUseSplitNotificationShade)
+ if ((hasVisibleNotifications && !mSplitShadeEnabled)
|| (splitShadeWithActiveMedia && !mDozing)) {
mKeyguardStatusViewController.displayClock(SMALL, shouldAnimateClockChange);
} else {
@@ -1452,7 +1453,7 @@
bypassEnabled, getUnlockedStackScrollerPadding(),
computeQsExpansionFraction(),
mDisplayTopInset,
- mShouldUseSplitNotificationShade,
+ mSplitShadeEnabled,
udfpsAodTopLocation,
mKeyguardStatusViewController.getClockBottom(mStatusBarHeaderHeightKeyguard),
mKeyguardStatusViewController.isClockTopAligned());
@@ -1482,8 +1483,7 @@
boolean hasVisibleNotifications = mNotificationStackScrollLayoutController
.getVisibleNotificationCount() != 0
|| mMediaDataManager.hasActiveMediaOrRecommendation();
- boolean shouldBeCentered = !mShouldUseSplitNotificationShade || !hasVisibleNotifications
- || mDozing;
+ boolean shouldBeCentered = !mSplitShadeEnabled || !hasVisibleNotifications || mDozing;
if (mStatusViewCentered != shouldBeCentered) {
mStatusViewCentered = shouldBeCentered;
ConstraintSet constraintSet = new ConstraintSet();
@@ -1492,7 +1492,7 @@
constraintSet.connect(R.id.keyguard_status_view, END, statusConstraint, END);
if (animate) {
ChangeBounds transition = new ChangeBounds();
- if (mShouldUseSplitNotificationShade) {
+ if (mSplitShadeEnabled) {
// Excluding media from the transition on split-shade, as it doesn't transition
// horizontally properly.
transition.excludeTarget(R.id.status_view_media_container, true);
@@ -1649,7 +1649,7 @@
private void setShowShelfOnly(boolean shelfOnly) {
mNotificationStackScrollLayoutController.setShouldShowShelfOnly(
- shelfOnly && !mShouldUseSplitNotificationShade);
+ shelfOnly && !mSplitShadeEnabled);
}
public void closeQs() {
@@ -1690,7 +1690,17 @@
mQsExpandImmediate = true;
setShowShelfOnly(true);
}
- if (isFullyCollapsed()) {
+ if (mSplitShadeEnabled && isOnKeyguard()) {
+ // It's a special case as this method is likely to not be initiated by finger movement
+ // but rather called from adb shell or accessibility service.
+ // We're using LockscreenShadeTransitionController because on lockscreen that's the
+ // source of truth for all shade motion. Not using it would make part of state to be
+ // outdated and will cause bugs. Ideally we'd use this controller also for non-split
+ // case but currently motion in portrait looks worse than when using flingSettings.
+ // TODO: make below function transitioning smoothly also in portrait with null target
+ mLockscreenShadeTransitionController.goToLockedShade(
+ /* expandedView= */null, /* needsQSAnimation= */false);
+ } else if (isFullyCollapsed()) {
expand(true /* animate */);
} else {
traceQsJank(true /* startTracing */, false /* wasCancelled */);
@@ -1910,7 +1920,7 @@
int flingType;
if (expandsQs && !isCancelMotionEvent) {
flingType = FLING_EXPAND;
- } else if (mShouldUseSplitNotificationShade) {
+ } else if (mSplitShadeEnabled) {
flingType = FLING_HIDE;
} else {
flingType = FLING_COLLAPSE;
@@ -1976,11 +1986,11 @@
private boolean handleQsTouch(MotionEvent event) {
- if (mShouldUseSplitNotificationShade && touchXOutsideOfQs(event.getX())) {
+ if (mSplitShadeEnabled && touchXOutsideOfQs(event.getX())) {
return false;
}
final int action = event.getActionMasked();
- boolean collapsedQs = !mQsExpanded && !mShouldUseSplitNotificationShade;
+ boolean collapsedQs = !mQsExpanded && !mSplitShadeEnabled;
boolean expandedShadeCollapsedQs = getExpandedFraction() == 1f && mBarState != KEYGUARD
&& collapsedQs && isQsExpansionEnabled();
if (action == MotionEvent.ACTION_DOWN && expandedShadeCollapsedQs) {
@@ -1998,7 +2008,7 @@
}
if (!mQsExpandImmediate && mQsTracking) {
onQsTouch(event);
- if (!mConflictingQsExpansionGesture && !mShouldUseSplitNotificationShade) {
+ if (!mConflictingQsExpansionGesture && !mSplitShadeEnabled) {
return true;
}
}
@@ -2289,7 +2299,7 @@
}
private void updateQsState() {
- boolean qsFullScreen = mQsExpanded && !mShouldUseSplitNotificationShade;
+ boolean qsFullScreen = mQsExpanded && !mSplitShadeEnabled;
mNotificationStackScrollLayoutController.setQsFullScreen(qsFullScreen);
mNotificationStackScrollLayoutController.setScrollingEnabled(
mBarState != KEYGUARD && (!qsFullScreen || mQsExpansionFromOverscroll));
@@ -2337,7 +2347,7 @@
private void updateQsExpansion() {
if (mQs == null) return;
final float squishiness;
- if ((mQsExpandImmediate || mQsExpanded) && !mShouldUseSplitNotificationShade) {
+ if ((mQsExpandImmediate || mQsExpanded) && !mSplitShadeEnabled) {
squishiness = 1;
} else if (mLockscreenShadeTransitionController.getQSDragProgress() > 0) {
squishiness = mLockscreenShadeTransitionController.getQSDragProgress();
@@ -2346,7 +2356,7 @@
.getNotificationSquishinessFraction();
}
final float qsExpansionFraction = computeQsExpansionFraction();
- final float adjustedExpansionFraction = mShouldUseSplitNotificationShade
+ final float adjustedExpansionFraction = mSplitShadeEnabled
? 1f : computeQsExpansionFraction();
mQs.setQsExpansion(adjustedExpansionFraction, getExpandedFraction(), getHeaderTranslation(),
squishiness);
@@ -2355,9 +2365,12 @@
mScrimController.setQsPosition(qsExpansionFraction, qsPanelBottomY);
setQSClippingBounds();
- // Only need to notify the notification stack when we're not in split screen mode. If we
- // do, then the notification panel starts scrolling along with the QS.
- if (!mShouldUseSplitNotificationShade) {
+ if (mSplitShadeEnabled) {
+ // In split shade we want to pretend that QS are always collapsed so their behaviour and
+ // interactions don't influence notifications as they do in portrait. But we want to set
+ // 0 explicitly in case we're rotating from non-split shade with QS expansion of 1.
+ mNotificationStackScrollLayoutController.setQsExpansionFraction(0);
+ } else {
mNotificationStackScrollLayoutController.setQsExpansionFraction(qsExpansionFraction);
}
@@ -2392,7 +2405,7 @@
private void updateQSExpansionEnabledAmbient() {
final float scrollRangeToTop = mAmbientState.getTopPadding() - mQuickQsHeaderHeight;
- mQsExpansionEnabledAmbient = mShouldUseSplitNotificationShade
+ mQsExpansionEnabledAmbient = mSplitShadeEnabled
|| (mAmbientState.getScrollY() <= scrollRangeToTop);
setQsExpansionEnabled();
}
@@ -2416,7 +2429,7 @@
private int calculateTopQsClippingBound(int qsPanelBottomY) {
int top;
- if (mShouldUseSplitNotificationShade) {
+ if (mSplitShadeEnabled) {
top = Math.min(qsPanelBottomY, mLargeScreenShadeHeaderHeight);
} else {
if (mTransitioningToFullShadeProgress > 0.0f) {
@@ -2450,7 +2463,7 @@
}
private int calculateBottomQsClippingBound(int top) {
- if (mShouldUseSplitNotificationShade) {
+ if (mSplitShadeEnabled) {
return top + mNotificationStackScrollLayoutController.getHeight()
+ mSplitShadeNotificationsScrimMarginBottom;
} else {
@@ -2547,7 +2560,7 @@
// qsTranslation should only be positive during pulse expansion because it's
// already translating in from the top
qsTranslation = Math.max(0, (top - mQs.getHeader().getHeight()) / 2.0f);
- } else if (!mShouldUseSplitNotificationShade) {
+ } else if (!mSplitShadeEnabled) {
qsTranslation = (top - mQs.getHeader().getHeight()) * QS_PARALLAX_AMOUNT;
}
}
@@ -2561,11 +2574,11 @@
mQsClipTop,
mQsClipBottom,
radius, qsVisible
- && !mShouldUseSplitNotificationShade);
+ && !mSplitShadeEnabled);
}
mKeyguardStatusViewController.setClipBounds(
clipStatusView ? mKeyguardStatusAreaClipBounds : null);
- if (!qsVisible && mShouldUseSplitNotificationShade) {
+ if (!qsVisible && mSplitShadeEnabled) {
// On the lockscreen when qs isn't visible, we don't want the bounds of the shade to
// be visible, otherwise you can see the bounds once swiping up to see bouncer
mScrimController.setNotificationsBounds(0, 0, 0, 0);
@@ -2573,12 +2586,11 @@
// Increase the height of the notifications scrim when not in split shade
// (e.g. portrait tablet) so the rounded corners are not visible at the bottom,
// in this case they are rendered off-screen
- final int notificationsScrimBottom =
- mShouldUseSplitNotificationShade ? bottom : bottom + radius;
+ final int notificationsScrimBottom = mSplitShadeEnabled ? bottom : bottom + radius;
mScrimController.setNotificationsBounds(left, top, right, notificationsScrimBottom);
}
- if (mShouldUseSplitNotificationShade) {
+ if (mSplitShadeEnabled) {
mKeyguardStatusBarViewController.setNoTopClipping();
} else {
mKeyguardStatusBarViewController.updateTopClipping(top);
@@ -2592,7 +2604,7 @@
int nsslRight = right - mNotificationStackScrollLayoutController.getLeft();
int nsslTop = top - mNotificationStackScrollLayoutController.getTop();
int nsslBottom = bottom - mNotificationStackScrollLayoutController.getTop();
- int bottomRadius = mShouldUseSplitNotificationShade ? radius : 0;
+ int bottomRadius = mSplitShadeEnabled ? radius : 0;
mNotificationStackScrollLayoutController.setRoundedClippingBounds(
nsslLeft, nsslTop, nsslRight, nsslBottom, radius, bottomRadius);
}
@@ -2634,7 +2646,7 @@
}
private float calculateNotificationsTopPadding() {
- if (mShouldUseSplitNotificationShade && !mKeyguardShowing) {
+ if (mSplitShadeEnabled && !mKeyguardShowing) {
return 0;
}
if (mKeyguardShowing && (mQsExpandImmediate
@@ -2907,7 +2919,7 @@
private boolean shouldQuickSettingsIntercept(float x, float y, float yDiff) {
if (!isQsExpansionEnabled() || mCollapsedOnDown
|| (mKeyguardShowing && mKeyguardBypassController.getBypassEnabled())
- || mShouldUseSplitNotificationShade) {
+ || mSplitShadeEnabled) {
return false;
}
View header = mKeyguardShowing || mQs == null ? mKeyguardStatusBar : mQs.getHeader();
@@ -2938,7 +2950,7 @@
return true;
}
- return !mShouldUseSplitNotificationShade && (isInSettings() || mIsPanelCollapseOnQQS);
+ return !mSplitShadeEnabled && (isInSettings() || mIsPanelCollapseOnQQS);
}
@Override
@@ -3122,7 +3134,7 @@
float appearAmount = mNotificationStackScrollLayoutController
.calculateAppearFraction(mExpandedHeight);
float startHeight = -mQsExpansionHeight;
- if (!mShouldUseSplitNotificationShade && mBarState == StatusBarState.SHADE) {
+ if (!mSplitShadeEnabled && mBarState == StatusBarState.SHADE) {
// Small parallax as we pull down and clip QS
startHeight = -mQsExpansionHeight * QS_PARALLAX_AMOUNT;
}
@@ -3365,9 +3377,9 @@
@Override
public void setIsLaunchAnimationRunning(boolean running) {
- boolean wasRunning = isLaunchTransitionRunning();
+ boolean wasRunning = mIsLaunchAnimationRunning;
super.setIsLaunchAnimationRunning(running);
- if (wasRunning != isLaunchTransitionRunning()) {
+ if (wasRunning != mIsLaunchAnimationRunning) {
mPanelEventsEmitter.notifyLaunchingActivityChanged(running);
}
}
@@ -3670,7 +3682,7 @@
mQs.setCollapseExpandAction(mCollapseExpandAction);
mQs.setHeaderClickable(isQsExpansionEnabled());
mQs.setOverscrolling(mStackScrollerOverscrolling);
- mQs.setInSplitShade(mShouldUseSplitNotificationShade);
+ mQs.setInSplitShade(mSplitShadeEnabled);
// recompute internal state when qspanel height changes
mQs.getView().addOnLayoutChangeListener(
@@ -3931,10 +3943,6 @@
}
}
- public boolean hasActiveClearableNotifications() {
- return mNotificationStackScrollLayoutController.hasActiveClearableNotifications(ROWS_ALL);
- }
-
public RemoteInputController.Delegate createRemoteInputDelegate() {
return mNotificationStackScrollLayoutController.createDelegate();
}
@@ -4345,7 +4353,7 @@
@Override
public void onOverscrollTopChanged(float amount, boolean isRubberbanded) {
// When in split shade, overscroll shouldn't carry through to QS
- if (mShouldUseSplitNotificationShade) {
+ if (mSplitShadeEnabled) {
return;
}
cancelQsAnimation();
@@ -4363,7 +4371,7 @@
@Override
public void flingTopOverscroll(float velocity, boolean open) {
// in split shade mode we want to expand/collapse QS only when touch happens within QS
- if (mShouldUseSplitNotificationShade && touchXOutsideOfQs(mInitialTouchX)) {
+ if (mSplitShadeEnabled && touchXOutsideOfQs(mInitialTouchX)) {
return;
}
mLastOverscroll = 0f;
@@ -4703,7 +4711,7 @@
// the top of QS
if (!mQsExpanded) {
// TODO(b/185683835) Nicer clipping when using new spacial model
- if (mShouldUseSplitNotificationShade) {
+ if (mSplitShadeEnabled) {
mQs.animateHeaderSlidingOut();
}
}
@@ -4900,7 +4908,7 @@
private void updateQSMinHeight() {
float previousMin = mQsMinExpansionHeight;
- if (mKeyguardShowing || mShouldUseSplitNotificationShade) {
+ if (mKeyguardShowing || mSplitShadeEnabled) {
mQsMinExpansionHeight = 0;
} else {
mQsMinExpansionHeight = mQs.getQsMinExpansionHeight();
@@ -5034,7 +5042,7 @@
// we need to ignore it on keyguard as this is a false alarm - transition from unlocked
// to locked will trigger this event and we're not actually in the process of opening
// the shade, lockscreen is just always expanded
- if (mShouldUseSplitNotificationShade && !isOnKeyguard()) {
+ if (mSplitShadeEnabled && !isOnKeyguard()) {
mQsExpandImmediate = true;
}
mCentralSurfaces.makeExpandedVisible(false);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
index faae4bb..a8da554 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
@@ -502,7 +502,8 @@
cb.onStateChanged(mCurrentState.mKeyguardShowing,
mCurrentState.mKeyguardOccluded,
mCurrentState.mBouncerShowing,
- mCurrentState.mDozing);
+ mCurrentState.mDozing,
+ mCurrentState.mPanelExpanded);
}
}
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 f9e17da..0e77866 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -402,6 +402,8 @@
mScrimBehind.setFocusable(!state.isLowPowerState());
mNotificationsScrim.setFocusable(!state.isLowPowerState());
+ mScrimInFront.setBlendWithMainColor(state.shouldBlendWithMainColor());
+
// Cancel blanking transitions that were pending before we requested a new state
if (mPendingFrameCallback != null) {
mScrimBehind.removeCallbacks(mPendingFrameCallback);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
index 47b7058..4a5f712 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
@@ -203,6 +203,11 @@
public boolean isLowPowerState() {
return true;
}
+
+ @Override
+ public boolean shouldBlendWithMainColor() {
+ return false;
+ }
},
/**
@@ -325,6 +330,13 @@
public void prepare(ScrimState previousState) {
}
+ /**
+ * Whether a particular state should enable blending with extracted theme colors.
+ */
+ public boolean shouldBlendWithMainColor() {
+ return true;
+ }
+
public float getFrontAlpha() {
return mFrontAlpha;
}
@@ -422,4 +434,4 @@
public void setClipQsScrim(boolean clipsQsScrim) {
mClipQsScrim = clipsQsScrim;
}
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLaunchAnimatorController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLaunchAnimatorController.kt
index 56b6dfc..c092216 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLaunchAnimatorController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLaunchAnimatorController.kt
@@ -20,7 +20,9 @@
override fun onIntentStarted(willAnimate: Boolean) {
delegate.onIntentStarted(willAnimate)
- if (!willAnimate) {
+ if (willAnimate) {
+ centralSurfaces.notificationPanelViewController.setIsLaunchAnimationRunning(true)
+ } else {
centralSurfaces.collapsePanelOnMainThread()
}
}
@@ -51,6 +53,7 @@
override fun onLaunchAnimationCancelled() {
delegate.onLaunchAnimationCancelled()
+ centralSurfaces.notificationPanelViewController.setIsLaunchAnimationRunning(false)
centralSurfaces.onLaunchAnimationCancelled(isLaunchForActivity)
}
}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
index 87ca942..cf776e3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -41,7 +41,6 @@
import android.util.EventLog;
import android.view.View;
-import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import com.android.internal.jank.InteractionJankMonitor;
@@ -52,7 +51,6 @@
import com.android.systemui.EventLogTags;
import com.android.systemui.animation.ActivityLaunchAnimator;
import com.android.systemui.assist.AssistManager;
-import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.CommandQueue;
@@ -77,7 +75,6 @@
import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent;
import com.android.systemui.statusbar.policy.HeadsUpUtil;
import com.android.systemui.statusbar.policy.KeyguardStateController;
-import com.android.systemui.util.ListenerSet;
import com.android.systemui.wmshell.BubblesManager;
import java.util.Optional;
@@ -131,7 +128,6 @@
private final ActivityLaunchAnimator mActivityLaunchAnimator;
private final NotificationLaunchAnimatorControllerProvider mNotificationAnimationProvider;
private final OnUserInteractionCallback mOnUserInteractionCallback;
- private final LaunchEventsEmitter mLaunchEventsEmitter;
private boolean mIsCollapsingToShowActivityOverLockscreen;
@@ -170,8 +166,7 @@
NotificationPresenter presenter,
NotificationPanelViewController panel,
ActivityLaunchAnimator activityLaunchAnimator,
- NotificationLaunchAnimatorControllerProvider notificationAnimationProvider,
- LaunchEventsEmitter launchEventsEmitter) {
+ NotificationLaunchAnimatorControllerProvider notificationAnimationProvider) {
mContext = context;
mCommandQueue = commandQueue;
mMainThreadHandler = mainThreadHandler;
@@ -207,7 +202,6 @@
mNotificationPanel = panel;
mActivityLaunchAnimator = activityLaunchAnimator;
mNotificationAnimationProvider = notificationAnimationProvider;
- mLaunchEventsEmitter = launchEventsEmitter;
if (!mNotifPipelineFlags.isNewPipelineEnabled()) {
mEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
@@ -229,14 +223,13 @@
/**
* Called when a notification is clicked.
*
- * @param sbn notification that was clicked
+ * @param entry notification that was clicked
* @param row row for that notification
*/
@Override
- public void onNotificationClicked(StatusBarNotification sbn, ExpandableNotificationRow row) {
- mLogger.logStartingActivityFromClick(sbn.getKey());
+ public void onNotificationClicked(NotificationEntry entry, ExpandableNotificationRow row) {
+ mLogger.logStartingActivityFromClick(entry);
- final NotificationEntry entry = row.getEntry();
if (mRemoteInputManager.isRemoteInputActive(entry)
&& !TextUtils.isEmpty(row.getActiveRemoteInputText())) {
// We have an active remote input typed and the user clicked on the notification.
@@ -244,7 +237,7 @@
mRemoteInputManager.closeRemoteInputs();
return;
}
- Notification notification = sbn.getNotification();
+ Notification notification = entry.getSbn().getNotification();
final PendingIntent intent = notification.contentIntent != null
? notification.contentIntent
: notification.fullScreenIntent;
@@ -254,12 +247,10 @@
// The only valid case is Bubble notifications. Guard against other cases
// entering here.
if (intent == null && !isBubble) {
- mLogger.logNonClickableNotification(sbn.getKey());
+ mLogger.logNonClickableNotification(entry);
return;
}
- mLaunchEventsEmitter.notifyStartLaunchNotifActivity(entry);
-
boolean isActivityIntent = intent != null && intent.isActivity() && !isBubble;
final boolean willLaunchResolverActivity = isActivityIntent
&& mActivityIntentHelper.wouldLaunchResolverActivity(intent.getIntent(),
@@ -287,7 +278,7 @@
} else {
mActivityStarter.dismissKeyguardThenExecute(
postKeyguardAction,
- () -> mLaunchEventsEmitter.notifyFinishLaunchNotifActivity(entry),
+ null,
willLaunchResolverActivity);
}
}
@@ -299,7 +290,7 @@
boolean isActivityIntent,
boolean animate,
boolean showOverLockscreen) {
- mLogger.logHandleClickAfterKeyguardDismissed(entry.getKey());
+ mLogger.logHandleClickAfterKeyguardDismissed(entry);
final Runnable runnable = () -> handleNotificationClickAfterPanelCollapsed(
entry, row, intent, isActivityIntent, animate);
@@ -326,7 +317,7 @@
boolean isActivityIntent,
boolean animate) {
String notificationKey = entry.getKey();
- mLogger.logHandleClickAfterPanelCollapsed(notificationKey);
+ mLogger.logHandleClickAfterPanelCollapsed(entry);
try {
// The intent we are sending is for the application, which
@@ -367,11 +358,9 @@
}
final boolean canBubble = entry.canBubble();
if (canBubble) {
- mLogger.logExpandingBubble(notificationKey);
+ mLogger.logExpandingBubble(entry);
removeHunAfterClick(row);
expandBubbleStackOnMainThread(entry);
- mMainThreadHandler.post(
- () -> mLaunchEventsEmitter.notifyFinishLaunchNotifActivity(entry));
} else {
startNotificationIntent(intent, fillInIntent, entry, row, animate, isActivityIntent);
}
@@ -381,30 +370,13 @@
final NotificationVisibility nv = mVisibilityProvider.obtain(entry, true);
- // retrieve the group summary to remove with this entry before we tell NMS the
- // notification was clicked to avoid a race condition
- final boolean shouldAutoCancel = shouldAutoCancel(entry.getSbn());
- final NotificationEntry summaryToRemove = shouldAutoCancel
- ? mOnUserInteractionCallback.getGroupSummaryToDismiss(entry) : null;
-
- // inform NMS that the notification was clicked
- mClickNotifier.onNotificationClick(notificationKey, nv);
-
- if (!canBubble && (shouldAutoCancel
+ if (!canBubble && (shouldAutoCancel(entry.getSbn())
|| mRemoteInputManager.isNotificationKeptForRemoteInputHistory(notificationKey))) {
+ final Runnable removeNotification =
+ mOnUserInteractionCallback.registerFutureDismissal(entry, REASON_CLICK);
// Immediately remove notification from visually showing.
// We have to post the removal to the UI thread for synchronization.
mMainThreadHandler.post(() -> {
- final Runnable removeNotification = () -> {
- mOnUserInteractionCallback.onDismiss(entry, REASON_CLICK, summaryToRemove);
- if (!animate) {
- // If we're animating, this would be invoked after the activity launch
- // animation completes. Since we're not animating, the launch already
- // happened synchronously, so we notify the launch is complete here after
- // onDismiss.
- mLaunchEventsEmitter.notifyFinishLaunchNotifActivity(entry);
- }
- };
if (mPresenter.isCollapsing()) {
// To avoid lags we're only performing the remove after the shade is collapsed
mShadeController.addPostCollapseAction(removeNotification);
@@ -412,12 +384,11 @@
removeNotification.run();
}
});
- } else if (!canBubble && !animate) {
- // Not animating, this is the end of the launch flow (see above comment for more info).
- mMainThreadHandler.post(
- () -> mLaunchEventsEmitter.notifyFinishLaunchNotifActivity(entry));
}
+ // inform NMS that the notification was clicked
+ mClickNotifier.onNotificationClick(notificationKey, nv);
+
mIsCollapsingToShowActivityOverLockscreen = false;
}
@@ -434,24 +405,14 @@
// will focus follow operation only after drag-and-drop that notification.
final NotificationVisibility nv = mVisibilityProvider.obtain(entry, true);
- // retrieve the group summary to remove with this entry before we tell NMS the
- // notification was clicked to avoid a race condition
- final boolean shouldAutoCancel = shouldAutoCancel(entry.getSbn());
- final NotificationEntry summaryToRemove = shouldAutoCancel
- ? mOnUserInteractionCallback.getGroupSummaryToDismiss(entry) : null;
-
String notificationKey = entry.getKey();
- // inform NMS that the notification was clicked
- mClickNotifier.onNotificationClick(notificationKey, nv);
-
- if (shouldAutoCancel || mRemoteInputManager.isNotificationKeptForRemoteInputHistory(
- notificationKey)) {
+ if (shouldAutoCancel(entry.getSbn())
+ || mRemoteInputManager.isNotificationKeptForRemoteInputHistory(notificationKey)) {
+ final Runnable removeNotification =
+ mOnUserInteractionCallback.registerFutureDismissal(entry, REASON_CLICK);
// Immediately remove notification from visually showing.
// We have to post the removal to the UI thread for synchronization.
mMainThreadHandler.post(() -> {
- final Runnable removeNotification = () ->
- mOnUserInteractionCallback.onDismiss(
- entry, REASON_CLICK, summaryToRemove);
if (mPresenter.isCollapsing()) {
// To avoid lags we're only performing the remove
// after the shade is collapsed
@@ -462,6 +423,9 @@
});
}
+ // inform NMS that the notification was clicked
+ mClickNotifier.onNotificationClick(notificationKey, nv);
+
mIsCollapsingToShowActivityOverLockscreen = false;
}
@@ -489,15 +453,11 @@
ExpandableNotificationRow row,
boolean animate,
boolean isActivityIntent) {
- mLogger.logStartNotificationIntent(entry.getKey());
+ mLogger.logStartNotificationIntent(entry);
try {
- Runnable onFinishAnimationCallback = animate
- ? () -> mLaunchEventsEmitter.notifyFinishLaunchNotifActivity(entry)
- : null;
ActivityLaunchAnimator.Controller animationController =
new StatusBarLaunchAnimatorController(
- mNotificationAnimationProvider
- .getAnimatorController(row, onFinishAnimationCallback),
+ mNotificationAnimationProvider.getAnimatorController(row, null),
mCentralSurfaces,
isActivityIntent);
mActivityLaunchAnimator.startPendingIntentWithAnimation(
@@ -515,7 +475,7 @@
: getActivityOptions(mCentralSurfaces.getDisplayId(), adapter);
int result = intent.sendAndReturnResult(mContext, 0, fillInIntent, null,
null, null, options);
- mLogger.logSendPendingIntent(entry.getKey(), intent, result);
+ mLogger.logSendPendingIntent(entry, intent, result);
return result;
});
} catch (PendingIntent.CanceledException e) {
@@ -622,9 +582,9 @@
void handleFullScreenIntent(NotificationEntry entry) {
if (mNotificationInterruptStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry)) {
if (shouldSuppressFullScreenIntent(entry)) {
- mLogger.logFullScreenIntentSuppressedByDnD(entry.getKey());
+ mLogger.logFullScreenIntentSuppressedByDnD(entry);
} else if (entry.getImportance() < NotificationManager.IMPORTANCE_HIGH) {
- mLogger.logFullScreenIntentNotImportantEnough(entry.getKey());
+ mLogger.logFullScreenIntentNotImportantEnough(entry);
} else {
// Stop screensaver if the notification has a fullscreen intent.
// (like an incoming phone call)
@@ -639,7 +599,7 @@
// not immersive & a fullscreen alert should be shown
final PendingIntent fullscreenIntent =
entry.getSbn().getNotification().fullScreenIntent;
- mLogger.logSendingFullScreenIntent(entry.getKey(), fullscreenIntent);
+ mLogger.logSendingFullScreenIntent(entry, fullscreenIntent);
try {
EventLog.writeEvent(EventLogTags.SYSUI_FULLSCREEN_NOTIFICATION,
entry.getKey());
@@ -685,35 +645,4 @@
return entry.shouldSuppressFullScreenIntent();
}
-
- @SysUISingleton
- static class LaunchEventsEmitter implements NotifActivityLaunchEvents {
-
- private final ListenerSet<Listener> mListeners = new ListenerSet<>();
-
- @Inject
- LaunchEventsEmitter() {}
-
- @Override
- public void registerListener(@NonNull Listener listener) {
- mListeners.addIfAbsent(listener);
- }
-
- @Override
- public void unregisterListener(@NonNull Listener listener) {
- mListeners.remove(listener);
- }
-
- private void notifyStartLaunchNotifActivity(NotificationEntry entry) {
- for (Listener listener : mListeners) {
- listener.onStartLaunchNotifActivity(entry);
- }
- }
-
- private void notifyFinishLaunchNotifActivity(NotificationEntry entry) {
- for (Listener listener : mListeners) {
- listener.onFinishLaunchNotifActivity(entry);
- }
- }
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterLogger.kt
index 2fbe520..b9a1413 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterLogger.kt
@@ -23,46 +23,48 @@
import com.android.systemui.log.LogLevel.INFO
import com.android.systemui.log.LogLevel.WARNING
import com.android.systemui.log.dagger.NotifInteractionLog
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.logKey
import javax.inject.Inject
class StatusBarNotificationActivityStarterLogger @Inject constructor(
@NotifInteractionLog private val buffer: LogBuffer
) {
- fun logStartingActivityFromClick(key: String) {
+ fun logStartingActivityFromClick(entry: NotificationEntry) {
buffer.log(TAG, DEBUG, {
- str1 = key
+ str1 = entry.logKey
}, {
"(1/5) onNotificationClicked: $str1"
})
}
- fun logHandleClickAfterKeyguardDismissed(key: String) {
+ fun logHandleClickAfterKeyguardDismissed(entry: NotificationEntry) {
buffer.log(TAG, DEBUG, {
- str1 = key
+ str1 = entry.logKey
}, {
"(2/5) handleNotificationClickAfterKeyguardDismissed: $str1"
})
}
- fun logHandleClickAfterPanelCollapsed(key: String) {
+ fun logHandleClickAfterPanelCollapsed(entry: NotificationEntry) {
buffer.log(TAG, DEBUG, {
- str1 = key
+ str1 = entry.logKey
}, {
"(3/5) handleNotificationClickAfterPanelCollapsed: $str1"
})
}
- fun logStartNotificationIntent(key: String) {
+ fun logStartNotificationIntent(entry: NotificationEntry) {
buffer.log(TAG, INFO, {
- str1 = key
+ str1 = entry.logKey
}, {
"(4/5) startNotificationIntent: $str1"
})
}
- fun logSendPendingIntent(key: String, pendingIntent: PendingIntent, result: Int) {
+ fun logSendPendingIntent(entry: NotificationEntry, pendingIntent: PendingIntent, result: Int) {
buffer.log(TAG, INFO, {
- str1 = key
+ str1 = entry.logKey
str2 = pendingIntent.intent.toString()
int1 = result
}, {
@@ -70,9 +72,9 @@
})
}
- fun logExpandingBubble(key: String) {
+ fun logExpandingBubble(entry: NotificationEntry) {
buffer.log(TAG, DEBUG, {
- str1 = key
+ str1 = entry.logKey
}, {
"Expanding bubble for $str1 (rather than firing intent)"
})
@@ -86,33 +88,33 @@
})
}
- fun logNonClickableNotification(key: String) {
+ fun logNonClickableNotification(entry: NotificationEntry) {
buffer.log(TAG, ERROR, {
- str1 = key
+ str1 = entry.logKey
}, {
"onNotificationClicked called for non-clickable notification! $str1"
})
}
- fun logFullScreenIntentSuppressedByDnD(key: String) {
+ fun logFullScreenIntentSuppressedByDnD(entry: NotificationEntry) {
buffer.log(TAG, DEBUG, {
- str1 = key
+ str1 = entry.logKey
}, {
"No Fullscreen intent: suppressed by DND: $str1"
})
}
- fun logFullScreenIntentNotImportantEnough(key: String) {
+ fun logFullScreenIntentNotImportantEnough(entry: NotificationEntry) {
buffer.log(TAG, DEBUG, {
- str1 = key
+ str1 = entry.logKey
}, {
"No Fullscreen intent: not important enough: $str1"
})
}
- fun logSendingFullScreenIntent(key: String, pendingIntent: PendingIntent) {
+ fun logSendingFullScreenIntent(entry: NotificationEntry, pendingIntent: PendingIntent) {
buffer.log(TAG, INFO, {
- str1 = key
+ str1 = entry.logKey
str2 = pendingIntent.intent.toString()
}, {
"Notification $str1 has fullScreenIntent; sending fullScreenIntent $str2"
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 aa061d7..037063f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
@@ -411,8 +411,8 @@
if (nowExpanded) {
if (mStatusBarStateController.getState() == StatusBarState.KEYGUARD) {
mShadeTransitionController.goToLockedShade(clickedEntry.getRow());
- } else if (clickedEntry.isSensitive()
- && mDynamicPrivacyController.isInLockedDownShade()) {
+ } else if (mDynamicPrivacyController.isInLockedDownShade()
+ && mLockscreenUserManager.notifNeedsRedactionInPublic(clickedEntry)) {
mStatusBarStateController.setLeaveOpenOnKeyguardHide(true);
mActivityStarter.dismissKeyguardThenExecute(() -> false /* dismissAction */
, null /* cancelRunnable */, false /* afterKeyguardGone */);
@@ -480,7 +480,7 @@
.isLockscreenPublicMode(mLockscreenUserManager.getCurrentUserId());
boolean userPublic = devicePublic
|| mLockscreenUserManager.isLockscreenPublicMode(sbn.getUserId());
- boolean needsRedaction = mLockscreenUserManager.needsRedaction(entry);
+ boolean needsRedaction = mLockscreenUserManager.notifNeedsRedactionInPublic(entry);
if (userPublic && needsRedaction) {
// TODO(b/135046837): we can probably relax this with dynamic privacy
return true;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowCallback.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowCallback.java
index ac43b67..ae48c2d3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowCallback.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowCallback.java
@@ -17,5 +17,5 @@
public interface StatusBarWindowCallback {
void onStateChanged(boolean keyguardShowing, boolean keyguardOccluded, boolean bouncerShowing,
- boolean isDozing);
+ boolean isDozing, boolean panelExpanded);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
index c1d0769..b117515 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
@@ -311,9 +311,9 @@
// We currently draw both the light reveal scrim, and the AOD UI, in the shade. If it's
// already expanded and showing notifications/QS, the animation looks really messy. For now,
- // disable it if the notification panel is not fully collapsed.
+ // disable it if the notification panel is expanded.
if ((!this::mCentralSurfaces.isInitialized ||
- !mCentralSurfaces.notificationPanelViewController.isFullyCollapsed) &&
+ mCentralSurfaces.notificationPanelViewController.isExpanded) &&
// Status bar might be expanded because we have started
// playing the animation already
!isAnimationPlaying()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java
index 15ee553..dce2412 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java
@@ -18,6 +18,7 @@
import android.app.IActivityTaskManager;
+import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.policy.KeyguardStateController.Callback;
@@ -94,6 +95,15 @@
boolean isKeyguardGoingAway();
/**
+ * Whether we're currently animating between the keyguard and the app/launcher surface behind
+ * it, or will be shortly (which happens if we started a fling to dismiss the keyguard).
+ * @see {@link KeyguardViewMediator#isAnimatingBetweenKeyguardAndSurfaceBehind()}
+ */
+ default boolean isAnimatingBetweenKeyguardAndSurfaceBehind() {
+ return false;
+ };
+
+ /**
* @return a shortened fading away duration similar to
* {{@link #getKeyguardFadingAwayDuration()}} which may only span half of the duration, unless
* we're bypassing
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 77e285d..2a225b9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
@@ -279,6 +279,11 @@
}
@Override
+ public boolean isAnimatingBetweenKeyguardAndSurfaceBehind() {
+ return mUnlockAnimationControllerLazy.get().isAnimatingBetweenKeyguardAndSurfaceBehind();
+ }
+
+ @Override
public boolean isBypassFadingAnimation() {
return mBypassFadingAnimation;
}
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
index 7920d388..c6a8445 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
@@ -78,6 +78,7 @@
import org.json.JSONObject;
import java.io.PrintWriter;
+import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
@@ -639,6 +640,11 @@
}
private Style fetchThemeStyleFromSetting() {
+ // Allow-list of Style objects that can be created from a setting string, i.e. can be
+ // used as a system-wide theme.
+ // - Content intentionally excluded, intended for media player, not system-wide
+ List<Style> validStyles = Arrays.asList(Style.EXPRESSIVE, Style.SPRITZ, Style.TONAL_SPOT,
+ Style.FRUIT_SALAD, Style.RAINBOW, Style.VIBRANT);
Style style = mThemeStyle;
final String overlayPackageJson = mSecureSettings.getStringForUser(
Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES,
@@ -648,6 +654,9 @@
JSONObject object = new JSONObject(overlayPackageJson);
style = Style.valueOf(
object.getString(ThemeOverlayApplier.OVERLAY_CATEGORY_THEME_STYLE));
+ if (!validStyles.contains(style)) {
+ style = Style.TONAL_SPOT;
+ }
} catch (JSONException | IllegalArgumentException e) {
Log.i(TAG, "Failed to parse THEME_CUSTOMIZATION_OVERLAY_PACKAGES.", e);
style = Style.TONAL_SPOT;
diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvBottomSheetActivity.java b/packages/SystemUI/src/com/android/systemui/tv/TvBottomSheetActivity.java
index 2b7a332..90f2434 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/TvBottomSheetActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/TvBottomSheetActivity.java
@@ -18,15 +18,18 @@
import android.app.Activity;
import android.graphics.PixelFormat;
+import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Gravity;
+import android.view.View;
import android.view.WindowManager;
import com.android.systemui.R;
+import java.util.Collections;
import java.util.function.Consumer;
/**
@@ -75,6 +78,12 @@
getWindow().setElevation(getWindow().getElevation() + 5);
getWindow().setBackgroundBlurRadius(getResources().getDimensionPixelSize(
R.dimen.bottom_sheet_background_blur_radius));
+
+ final View rootView = findViewById(R.id.bottom_sheet);
+ rootView.addOnLayoutChangeListener((view, l, t, r, b, oldL, oldT, oldR, oldB) -> {
+ rootView.setUnrestrictedPreferKeepClearRects(
+ Collections.singletonList(new Rect(0, 0, r - l, b - t)));
+ });
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionModule.kt b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionModule.kt
index d2d2361..eea6ac0 100644
--- a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionModule.kt
@@ -20,6 +20,7 @@
import android.view.IWindowManager
import com.android.systemui.keyguard.LifecycleScreenStatusProvider
import com.android.systemui.unfold.config.UnfoldTransitionConfig
+import com.android.systemui.unfold.system.SystemUnfoldSharedModule
import com.android.systemui.unfold.updates.FoldStateProvider
import com.android.systemui.unfold.updates.screen.ScreenStatusProvider
import com.android.systemui.unfold.util.NaturalRotationUnfoldProgressProvider
@@ -34,7 +35,7 @@
import javax.inject.Named
import javax.inject.Singleton
-@Module(includes = [UnfoldSharedModule::class])
+@Module(includes = [UnfoldSharedModule::class, SystemUnfoldSharedModule::class])
class UnfoldTransitionModule {
@Provides @UnfoldTransitionATracePrefix fun tracingTagPrefix() = "systemui"
@@ -62,11 +63,6 @@
@Provides
@Singleton
- fun provideUnfoldTransitionConfig(context: Context): UnfoldTransitionConfig =
- createConfig(context)
-
- @Provides
- @Singleton
fun provideNaturalRotationProgressProvider(
context: Context,
windowManager: IWindowManager,
diff --git a/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java b/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java
index 76dfcb1..53da213 100644
--- a/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java
+++ b/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java
@@ -35,11 +35,15 @@
public class NotificationChannels extends CoreStartable {
public static String ALERTS = "ALR";
public static String SCREENSHOTS_HEADSUP = "SCN_HEADSUP";
- public static String GENERAL = "GEN";
+ // Deprecated. Please use or create a more specific channel that users will better understand
+ @Deprecated
+ static String GENERAL = "GEN";
public static String STORAGE = "DSK";
public static String BATTERY = "BAT";
public static String TVPIP = TvPipNotificationController.NOTIFICATION_CHANNEL; // "TVPIP"
public static String HINTS = "HNT";
+ public static String INSTANT = "INS";
+ public static String SETUP = "STP";
@Inject
public NotificationChannels(Context context) {
@@ -64,11 +68,17 @@
context.getString(R.string.notification_channel_alerts),
NotificationManager.IMPORTANCE_HIGH);
- final NotificationChannel general = new NotificationChannel(
- GENERAL,
- context.getString(R.string.notification_channel_general),
+ final NotificationChannel instant = new NotificationChannel(
+ INSTANT,
+ context.getString(R.string.notification_channel_instant),
NotificationManager.IMPORTANCE_MIN);
+ final NotificationChannel setup = new NotificationChannel(
+ SETUP,
+ context.getString(R.string.notification_channel_setup),
+ NotificationManager.IMPORTANCE_DEFAULT);
+ setup.setSound(null, null);
+
final NotificationChannel storage = new NotificationChannel(
STORAGE,
context.getString(R.string.notification_channel_storage),
@@ -84,7 +94,8 @@
nm.createNotificationChannels(Arrays.asList(
alerts,
- general,
+ instant,
+ setup,
storage,
createScreenshotChannel(
context.getString(R.string.notification_channel_screenshot)),
@@ -123,6 +134,11 @@
@Override
public void start() {
createAll(mContext);
+ cleanUp();
+ }
+
+ private void cleanUp() {
+ mContext.getSystemService(NotificationManager.class).deleteNotificationChannel(GENERAL);
}
private static boolean isTv(Context context) {
diff --git a/packages/SystemUI/src/com/android/systemui/util/collection/RingBuffer.kt b/packages/SystemUI/src/com/android/systemui/util/collection/RingBuffer.kt
new file mode 100644
index 0000000..97dc842
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/collection/RingBuffer.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.util.collection
+
+import kotlin.math.max
+
+/**
+ * A simple ring buffer implementation
+ *
+ * Use [advance] to get the least recent item in the buffer (and then presumably fill it with
+ * appropriate data). This will cause it to become the most recent item.
+ *
+ * As the buffer is used, it will grow, allocating new instances of T using [factory] until it
+ * reaches [maxSize]. After this point, no new instances will be created. Instead, the "oldest"
+ * instances will be recycled from the back of the buffer and placed at the front.
+ *
+ * @param maxSize The maximum size the buffer can grow to before it begins functioning as a ring.
+ * @param factory A function that creates a fresh instance of T. Used by the buffer while it's
+ * growing to [maxSize].
+ */
+class RingBuffer<T>(
+ private val maxSize: Int,
+ private val factory: () -> T
+) : Iterable<T> {
+
+ private val buffer = MutableList<T?>(maxSize) { null }
+
+ /**
+ * An abstract representation that points to the "end" of the buffer. Increments every time
+ * [advance] is called and never wraps. Use [indexOf] to calculate the associated index into
+ * the backing array. Always points to the "next" available slot in the buffer. Before the
+ * buffer has completely filled, the value pointed to will be null. Afterward, it will be the
+ * value at the "beginning" of the buffer.
+ *
+ * This value is unlikely to overflow. Assuming [advance] is called at rate of 100 calls/ms,
+ * omega will overflow after a little under three million years of continuous operation.
+ */
+ private var omega: Long = 0
+
+ /**
+ * The number of items currently stored in the buffer. Calls to [advance] will cause this value
+ * to increase by one until it reaches [maxSize].
+ */
+ val size: Int
+ get() = if (omega < maxSize) omega.toInt() else maxSize
+
+ /**
+ * Advances the buffer's position by one and returns the value that is now present at the "end"
+ * of the buffer. If the buffer is not yet full, uses [factory] to create a new item.
+ * Otherwise, reuses the value that was previously at the "beginning" of the buffer.
+ *
+ * IMPORTANT: The value is returned as-is, without being reset. It will retain any data that
+ * was previously stored on it.
+ */
+ fun advance(): T {
+ val index = indexOf(omega)
+ omega += 1
+ val entry = buffer[index] ?: factory().also {
+ buffer[index] = it
+ }
+ return entry
+ }
+
+ /**
+ * Returns the value stored at [index], which can range from 0 (the "start", or oldest element
+ * of the buffer) to [size] - 1 (the "end", or newest element of the buffer).
+ */
+ operator fun get(index: Int): T {
+ if (index < 0 || index >= size) {
+ throw IndexOutOfBoundsException("Index $index is out of bounds")
+ }
+
+ // If omega is larger than the maxSize, then the buffer is full, and omega is equivalent
+ // to the "start" of the buffer. If omega is smaller than the maxSize, then the buffer is
+ // not yet full and our start should be 0. However, in modspace, maxSize and 0 are
+ // equivalent, so we can get away with using it as the start value instead.
+ val start = max(omega, maxSize.toLong())
+
+ return buffer[indexOf(start + index)]!!
+ }
+
+ inline fun forEach(action: (T) -> Unit) {
+ for (i in 0 until size) {
+ action(get(i))
+ }
+ }
+
+ override fun iterator(): Iterator<T> {
+ return object : Iterator<T> {
+ private var position: Int = 0
+
+ override fun next(): T {
+ if (position >= size) {
+ throw NoSuchElementException()
+ }
+ return get(position).also { position += 1 }
+ }
+
+ override fun hasNext(): Boolean {
+ return position < size
+ }
+ }
+ }
+
+ private fun indexOf(position: Long): Int {
+ return (position % maxSize).toInt()
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index bfdcbd6..cf0d023 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -32,6 +32,8 @@
import static android.view.View.VISIBLE;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+import static com.android.internal.jank.InteractionJankMonitor.CUJ_VOLUME_CONTROL;
+import static com.android.internal.jank.InteractionJankMonitor.Configuration.Builder;
import static com.android.systemui.volume.Events.DISMISS_REASON_SETTINGS_CLICKED;
import android.animation.Animator;
@@ -68,6 +70,7 @@
import android.os.Looper;
import android.os.Message;
import android.os.SystemClock;
+import android.os.Trace;
import android.os.VibrationEffect;
import android.provider.Settings;
import android.provider.Settings.Global;
@@ -101,9 +104,11 @@
import android.widget.TextView;
import android.widget.Toast;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.internal.graphics.drawable.BackgroundBlurDrawable;
+import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.view.RotationPolicy;
import com.android.settingslib.Utils;
import com.android.systemui.Prefs;
@@ -149,6 +154,13 @@
private static final int DRAWER_ANIMATION_DURATION_SHORT = 175;
private static final int DRAWER_ANIMATION_DURATION = 250;
+ /** Shows volume dialog show animation. */
+ private static final String TYPE_SHOW = "show";
+ /** Dismiss volume dialog animation. */
+ private static final String TYPE_DISMISS = "dismiss";
+ /** Volume dialog slider animation. */
+ private static final String TYPE_UPDATE = "update";
+
private final int mDialogShowAnimationDurationMs;
private final int mDialogHideAnimationDurationMs;
private int mDialogWidth;
@@ -258,6 +270,7 @@
private final boolean mUseBackgroundBlur;
private Consumer<Boolean> mCrossWindowBlurEnabledListener;
private BackgroundBlurDrawable mDialogRowsViewBackground;
+ private final InteractionJankMonitor mInteractionJankMonitor;
public VolumeDialogImpl(
Context context,
@@ -266,7 +279,8 @@
DeviceProvisionedController deviceProvisionedController,
ConfigurationController configurationController,
MediaOutputDialogFactory mediaOutputDialogFactory,
- ActivityStarter activityStarter) {
+ ActivityStarter activityStarter,
+ InteractionJankMonitor interactionJankMonitor) {
mContext =
new ContextThemeWrapper(context, R.style.volume_dialog_theme);
mController = volumeDialogController;
@@ -290,6 +304,7 @@
mContext.getResources().getInteger(R.integer.config_dialogHideAnimationDurationMs);
mUseBackgroundBlur =
mContext.getResources().getBoolean(R.bool.config_volumeDialogUseBackgroundBlur);
+ mInteractionJankMonitor = interactionJankMonitor;
if (mUseBackgroundBlur) {
final int dialogRowsViewColorAboveBlur = mContext.getColor(
@@ -422,6 +437,7 @@
.alpha(1)
.translationX(0)
.setDuration(mDialogShowAnimationDurationMs)
+ .setListener(getJankListener(getDialogView(), TYPE_SHOW, DIALOG_TIMEOUT_MILLIS))
.setInterpolator(new SystemUIInterpolators.LogDecelerateInterpolator())
.withEndAction(() -> {
if (!Prefs.getBoolean(mContext, Prefs.Key.TOUCHED_RINGER_TOGGLE, false)) {
@@ -692,7 +708,7 @@
final int m = seekBar.getMax();
final int n = m / 100 - 1;
final int level = progress == 0 ? 0
- : progress == m ? (m / 100) : (1 + (int)((progress / (float) m) * n));
+ : progress == m ? (m / 100) : (1 + (int) ((progress / (float) m) * n));
return level;
}
@@ -1251,7 +1267,33 @@
mHandler.obtainMessage(H.DISMISS, reason, 0).sendToTarget();
}
+ private Animator.AnimatorListener getJankListener(View v, String type, long timeout) {
+ return new Animator.AnimatorListener() {
+ @Override
+ public void onAnimationStart(@NonNull Animator animation) {
+ mInteractionJankMonitor.begin(Builder.withView(CUJ_VOLUME_CONTROL, v).setTag(type)
+ .setTimeout(timeout));
+ }
+
+ @Override
+ public void onAnimationEnd(@NonNull Animator animation) {
+ mInteractionJankMonitor.end(CUJ_VOLUME_CONTROL);
+ }
+
+ @Override
+ public void onAnimationCancel(@NonNull Animator animation) {
+ mInteractionJankMonitor.cancel(CUJ_VOLUME_CONTROL);
+ }
+
+ @Override
+ public void onAnimationRepeat(@NonNull Animator animation) {
+ // no-op
+ }
+ };
+ }
+
private void showH(int reason) {
+ Trace.beginSection("VolumeDialogImpl#showH");
if (D.BUG) Log.d(TAG, "showH r=" + Events.SHOW_REASONS[reason]);
mHandler.removeMessages(H.SHOW);
mHandler.removeMessages(H.DISMISS);
@@ -1272,6 +1314,7 @@
mController.getCaptionsComponentState(false);
checkODICaptionsTooltip(false);
updateBackgroundForDrawerClosedAmount();
+ Trace.endSection();
}
protected void rescheduleTimeoutH() {
@@ -1305,6 +1348,7 @@
}
protected void dismissH(int reason) {
+ Trace.beginSection("VolumeDialogImpl#dismissH");
if (D.BUG) {
Log.d(TAG, "mDialog.dismiss() reason: " + Events.DISMISS_REASONS[reason]
+ " from: " + Debug.getCaller());
@@ -1335,7 +1379,8 @@
hideRingerDrawer();
}, 50));
if (!shouldSlideInVolumeTray()) animator.translationX(mDialogView.getWidth() / 2.0f);
- animator.start();
+ animator.setListener(getJankListener(getDialogView(), TYPE_DISMISS,
+ mDialogHideAnimationDurationMs)).start();
checkODICaptionsTooltip(true);
mController.notifyVisible(false);
synchronized (mSafetyWarningLock) {
@@ -1344,6 +1389,7 @@
mSafetyWarning.dismiss();
}
}
+ Trace.endSection();
}
private boolean showActiveStreamOnly() {
@@ -1383,6 +1429,7 @@
}
private void updateRowsH(final VolumeRow activeRow) {
+ Trace.beginSection("VolumeDialogImpl#updateRowsH");
if (D.BUG) Log.d(TAG, "updateRowsH");
if (!mShowing) {
trimObsoleteH();
@@ -1446,6 +1493,7 @@
}
updateBackgroundForDrawerClosedAmount();
+ Trace.endSection();
}
protected void updateRingerH() {
@@ -1730,7 +1778,9 @@
final boolean enableSlider = !zenMuted;
final int vlevel = row.ss.muted && (!isRingStream && !zenMuted) ? 0
: row.ss.level;
+ Trace.beginSection("VolumeDialogImpl#updateVolumeRowSliderH");
updateVolumeRowSliderH(row, enableSlider, vlevel);
+ Trace.endSection();
if (row.number != null) row.number.setText(Integer.toString(vlevel));
}
@@ -1824,6 +1874,8 @@
}
row.animTargetProgress = newProgress;
row.anim.setDuration(UPDATE_ANIMATION_DURATION);
+ row.anim.addListener(
+ getJankListener(row.view, TYPE_UPDATE, UPDATE_ANIMATION_DURATION));
row.anim.start();
} else {
// update slider directly to clamped value
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java b/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java
index 79aa643..f3855bd 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java
@@ -19,6 +19,7 @@
import android.content.Context;
import android.media.AudioManager;
+import com.android.internal.jank.InteractionJankMonitor;
import com.android.systemui.media.dialog.MediaOutputDialogFactory;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.VolumeDialog;
@@ -51,7 +52,8 @@
DeviceProvisionedController deviceProvisionedController,
ConfigurationController configurationController,
MediaOutputDialogFactory mediaOutputDialogFactory,
- ActivityStarter activityStarter) {
+ ActivityStarter activityStarter,
+ InteractionJankMonitor interactionJankMonitor) {
VolumeDialogImpl impl = new VolumeDialogImpl(
context,
volumeDialogController,
@@ -59,7 +61,8 @@
deviceProvisionedController,
configurationController,
mediaOutputDialogFactory,
- activityStarter);
+ activityStarter,
+ interactionJankMonitor);
impl.setStreamImportant(AudioManager.STREAM_SYSTEM, false);
impl.setAutomute(true);
impl.setSilentMode(false);
diff --git a/packages/SystemUI/src/com/android/systemui/wallet/controller/QuickAccessWalletController.java b/packages/SystemUI/src/com/android/systemui/wallet/controller/QuickAccessWalletController.java
index ebdddbf..8c842f1 100644
--- a/packages/SystemUI/src/com/android/systemui/wallet/controller/QuickAccessWalletController.java
+++ b/packages/SystemUI/src/com/android/systemui/wallet/controller/QuickAccessWalletController.java
@@ -19,7 +19,6 @@
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.annotation.CallbackExecutor;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
@@ -65,7 +64,6 @@
private static final long RECREATION_TIME_WINDOW = TimeUnit.MINUTES.toMillis(10L);
private final Context mContext;
private final Executor mExecutor;
- private final Executor mCallbackExecutor;
private final Executor mBgExecutor;
private final SecureSettings mSecureSettings;
private final SystemClock mClock;
@@ -82,14 +80,12 @@
public QuickAccessWalletController(
Context context,
@Main Executor executor,
- @CallbackExecutor Executor callbackExecutor,
@Background Executor bgExecutor,
SecureSettings secureSettings,
QuickAccessWalletClient quickAccessWalletClient,
SystemClock clock) {
mContext = context;
mExecutor = executor;
- mCallbackExecutor = callbackExecutor;
mBgExecutor = bgExecutor;
mSecureSettings = secureSettings;
mQuickAccessWalletClient = quickAccessWalletClient;
@@ -180,7 +176,7 @@
int iconSizePx = mContext.getResources().getDimensionPixelSize(R.dimen.wallet_icon_size);
GetWalletCardsRequest request =
new GetWalletCardsRequest(cardWidth, cardHeight, iconSizePx, /* maxCards= */ 1);
- mQuickAccessWalletClient.getWalletCards(mCallbackExecutor, request, cardsRetriever);
+ mQuickAccessWalletClient.getWalletCards(mBgExecutor, request, cardsRetriever);
}
/**
@@ -212,7 +208,7 @@
public void startQuickAccessUiIntent(ActivityStarter activityStarter,
ActivityLaunchAnimator.Controller animationController,
boolean hasCard) {
- mQuickAccessWalletClient.getWalletPendingIntent(mCallbackExecutor,
+ mQuickAccessWalletClient.getWalletPendingIntent(mBgExecutor,
walletPendingIntent -> {
if (walletPendingIntent != null) {
startQuickAccessViaPendingIntent(walletPendingIntent, activityStarter,
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
index 542a537..e90775d 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
@@ -78,6 +78,7 @@
import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
import com.android.systemui.statusbar.phone.ShadeController;
+import com.android.systemui.statusbar.phone.StatusBarWindowCallback;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.ZenModeController;
@@ -121,6 +122,7 @@
private final Bubbles.SysuiProxy mSysuiProxy;
// TODO (b/145659174): allow for multiple callbacks to support the "shadow" new notif pipeline
private final List<NotifCallback> mCallbacks = new ArrayList<>();
+ private final StatusBarWindowCallback mStatusBarWindowCallback;
/**
* Creates {@link BubblesManager}, returns {@code null} if Optional {@link Bubbles} not present
@@ -271,11 +273,22 @@
mBubbles.onCurrentProfilesChanged(currentProfiles);
}
+ @Override
+ public void onUserRemoved(int userId) {
+ mBubbles.onUserRemoved(userId);
+ }
+
});
+ // Store callback in a field so it won't get GC'd
+ mStatusBarWindowCallback =
+ (keyguardShowing, keyguardOccluded, bouncerShowing, isDozing, panelExpanded) ->
+ mBubbles.onNotificationPanelExpandedChanged(panelExpanded);
+ notificationShadeWindowController.registerCallback(mStatusBarWindowCallback);
+
mSysuiProxy = new Bubbles.SysuiProxy() {
@Override
- public void isNotificationShadeExpand(Consumer<Boolean> callback) {
+ public void isNotificationPanelExpand(Consumer<Boolean> callback) {
sysuiMainExecutor.execute(() -> {
callback.accept(mNotificationShadeWindowController.getPanelExpanded());
});
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
index cddfd44..a6db2aa 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
@@ -200,9 +200,13 @@
mPipKeyguardCallback = new KeyguardUpdateMonitorCallback() {
@Override
public void onKeyguardVisibilityChanged(boolean showing) {
- if (showing) {
- pip.hidePipMenu(null, null);
- }
+ pip.onKeyguardVisibilityChanged(showing,
+ mKeyguardStateController.isAnimatingBetweenKeyguardAndSurfaceBehind());
+ }
+
+ @Override
+ public void onKeyguardDismissAnimationFinished() {
+ pip.onKeyguardDismissAnimationFinished();
}
};
mKeyguardUpdateMonitor.registerCallback(mPipKeyguardCallback);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
index 7c211b2..57253af 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
@@ -159,6 +159,7 @@
when(mContext.getDisplay()).thenReturn(mDisplay);
// Not support hwc layer by default
doReturn(null).when(mDisplay).getDisplayDecorationSupport();
+ doReturn(mDisplayMode).when(mDisplay).getMode();
when(mMockTypedArray.length()).thenReturn(0);
mPrivacyDotTopLeftDecorProvider = spy(new PrivacyDotCornerDecorProviderImpl(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsBpViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsBpViewControllerTest.kt
new file mode 100644
index 0000000..a52c4a3
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsBpViewControllerTest.kt
@@ -0,0 +1,118 @@
+/*
+ * 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.app.Instrumentation
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.testing.ViewUtils
+import androidx.test.filters.SmallTest
+import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
+import com.android.internal.jank.InteractionJankMonitor
+import com.android.internal.logging.testing.UiEventLoggerFake
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.broadcast.BroadcastSender
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.statusbar.StatusBarStateControllerImpl
+import com.android.systemui.statusbar.phone.SystemUIDialogManager
+import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager
+import com.android.systemui.util.mockito.any
+import org.junit.After
+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.spy
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
+import org.mockito.junit.MockitoJUnit
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper
+class UdfpsBpViewControllerTest : SysuiTestCase() {
+
+ @JvmField @Rule var rule = MockitoJUnit.rule()
+
+ @Mock lateinit var dumpManager: DumpManager
+ @Mock lateinit var systemUIDialogManager: SystemUIDialogManager
+ @Mock lateinit var broadcastSender: BroadcastSender
+ @Mock lateinit var interactionJankMonitor: InteractionJankMonitor
+ @Mock lateinit var panelExpansionStateManager: PanelExpansionStateManager
+
+ private lateinit var instrumentation: Instrumentation
+ private lateinit var uiEventLogger: UiEventLoggerFake
+ private lateinit var udfpsBpView: UdfpsBpView
+ private lateinit var statusBarStateController: StatusBarStateControllerImpl
+ private lateinit var udfpsBpViewController: UdfpsBpViewController
+
+ @Before
+ fun setup() {
+ instrumentation = getInstrumentation()
+ instrumentation.runOnMainSync { createUdfpsView() }
+ instrumentation.waitForIdleSync()
+
+ uiEventLogger = UiEventLoggerFake()
+ statusBarStateController =
+ StatusBarStateControllerImpl(uiEventLogger, dumpManager, interactionJankMonitor)
+ udfpsBpViewController = UdfpsBpViewController(
+ udfpsBpView,
+ statusBarStateController,
+ panelExpansionStateManager,
+ systemUIDialogManager,
+ broadcastSender,
+ dumpManager)
+ udfpsBpViewController.init()
+ }
+
+ @After
+ fun tearDown() {
+ if (udfpsBpViewController.isAttachedToWindow) {
+ instrumentation.runOnMainSync { ViewUtils.detachView(udfpsBpView) }
+ instrumentation.waitForIdleSync()
+ }
+ }
+
+ private fun createUdfpsView() {
+ context.setTheme(R.style.Theme_AppCompat)
+ context.orCreateTestableResources.addOverride(
+ com.android.internal.R.integer.config_udfps_illumination_transition_ms, 0)
+ udfpsBpView = UdfpsBpView(context, null)
+ }
+
+ @Test
+ fun addExpansionListener() {
+ instrumentation.runOnMainSync { ViewUtils.attachView(udfpsBpView) }
+ instrumentation.waitForIdleSync()
+
+ // Both UdfpsBpViewController & UdfpsAnimationViewController add listener
+ verify(panelExpansionStateManager, times(2)).addExpansionListener(any())
+ }
+
+ @Test
+ fun removeExpansionListener() {
+ instrumentation.runOnMainSync { ViewUtils.attachView(udfpsBpView) }
+ instrumentation.waitForIdleSync()
+ instrumentation.runOnMainSync { ViewUtils.detachView(udfpsBpView) }
+ instrumentation.waitForIdleSync()
+
+ // Both UdfpsBpViewController & UdfpsAnimationViewController remove listener
+ verify(panelExpansionStateManager, times(2)).removeExpansionListener(any())
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
index fc5ccbc..431739b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
@@ -40,6 +40,7 @@
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.ActivityLaunchAnimator
+import com.android.systemui.broadcast.BroadcastSender
import com.android.systemui.dump.DumpManager
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.LockscreenShadeTransitionController
@@ -102,6 +103,7 @@
@Mock private lateinit var udfpsView: UdfpsView
@Mock private lateinit var udfpsEnrollView: UdfpsEnrollView
@Mock private lateinit var activityLaunchAnimator: ActivityLaunchAnimator
+ @Mock private lateinit var broadcastSender: BroadcastSender
@Captor private lateinit var layoutParamsCaptor: ArgumentCaptor<WindowManager.LayoutParams>
private val onTouch = { _: View, _: MotionEvent, _: Boolean -> true }
@@ -131,7 +133,8 @@
keyguardUpdateMonitor, dialogManager, dumpManager, transitionController,
configurationController, systemClock, keyguardStateController,
unlockedScreenOffAnimationController, HAL_CONTROLS_ILLUMINATION, hbmProvider,
- REQUEST_ID, reason, controllerCallback, onTouch, activityLaunchAnimator)
+ REQUEST_ID, reason, controllerCallback, onTouch, activityLaunchAnimator,
+ broadcastSender)
block()
}
@@ -364,6 +367,73 @@
assertThat(controllerOverlay.matchesRequestId(REQUEST_ID)).isTrue()
assertThat(controllerOverlay.matchesRequestId(REQUEST_ID + 1)).isFalse()
}
+
+ @Test
+ fun testTouchOutsideAreaNoRotation() = withReason(REASON_ENROLL_ENROLLING) {
+ val touchHints =
+ context.resources.getStringArray(R.array.udfps_accessibility_touch_hints)
+ val rotation = Surface.ROTATION_0
+ // touch at 0 degrees
+ assertThat(controllerOverlay.onTouchOutsideOfSensorAreaImpl(0.0f /* x */, 0.0f /* y */,
+ 0.0f /* sensorX */, 0.0f /* sensorY */, rotation))
+ .isEqualTo(touchHints[0])
+ // touch at 90 degrees
+ assertThat(controllerOverlay.onTouchOutsideOfSensorAreaImpl(0.0f /* x */, -1.0f /* y */,
+ 0.0f /* sensorX */, 0.0f /* sensorY */, rotation))
+ .isEqualTo(touchHints[1])
+ // touch at 180 degrees
+ assertThat(controllerOverlay.onTouchOutsideOfSensorAreaImpl(-1.0f /* x */, 0.0f /* y */,
+ 0.0f /* sensorX */, 0.0f /* sensorY */, rotation))
+ .isEqualTo(touchHints[2])
+ // touch at 270 degrees
+ assertThat(controllerOverlay.onTouchOutsideOfSensorAreaImpl(0.0f /* x */, 1.0f /* y */,
+ 0.0f /* sensorX */, 0.0f /* sensorY */, rotation))
+ .isEqualTo(touchHints[3])
+ }
+
+ fun testTouchOutsideAreaNoRotation90Degrees() = withReason(REASON_ENROLL_ENROLLING) {
+ val touchHints =
+ context.resources.getStringArray(R.array.udfps_accessibility_touch_hints)
+ val rotation = Surface.ROTATION_90
+ // touch at 0 degrees -> 90 degrees
+ assertThat(controllerOverlay.onTouchOutsideOfSensorAreaImpl(0.0f /* x */, 0.0f /* y */,
+ 0.0f /* sensorX */, 0.0f /* sensorY */, rotation))
+ .isEqualTo(touchHints[1])
+ // touch at 90 degrees -> 180 degrees
+ assertThat(controllerOverlay.onTouchOutsideOfSensorAreaImpl(0.0f /* x */, -1.0f /* y */,
+ 0.0f /* sensorX */, 0.0f /* sensorY */, rotation))
+ .isEqualTo(touchHints[2])
+ // touch at 180 degrees -> 270 degrees
+ assertThat(controllerOverlay.onTouchOutsideOfSensorAreaImpl(-1.0f /* x */, 0.0f /* y */,
+ 0.0f /* sensorX */, 0.0f /* sensorY */, rotation))
+ .isEqualTo(touchHints[3])
+ // touch at 270 degrees -> 0 degrees
+ assertThat(controllerOverlay.onTouchOutsideOfSensorAreaImpl(0.0f /* x */, 1.0f /* y */,
+ 0.0f /* sensorX */, 0.0f /* sensorY */, rotation))
+ .isEqualTo(touchHints[0])
+ }
+
+ fun testTouchOutsideAreaNoRotation270Degrees() = withReason(REASON_ENROLL_ENROLLING) {
+ val touchHints =
+ context.resources.getStringArray(R.array.udfps_accessibility_touch_hints)
+ val rotation = Surface.ROTATION_270
+ // touch at 0 degrees -> 270 degrees
+ assertThat(controllerOverlay.onTouchOutsideOfSensorAreaImpl(0.0f /* x */, 0.0f /* y */,
+ 0.0f /* sensorX */, 0.0f /* sensorY */, rotation))
+ .isEqualTo(touchHints[3])
+ // touch at 90 degrees -> 0 degrees
+ assertThat(controllerOverlay.onTouchOutsideOfSensorAreaImpl(0.0f /* x */, -1.0f /* y */,
+ 0.0f /* sensorX */, 0.0f /* sensorY */, rotation))
+ .isEqualTo(touchHints[0])
+ // touch at 180 degrees -> 90 degrees
+ assertThat(controllerOverlay.onTouchOutsideOfSensorAreaImpl(-1.0f /* x */, 0.0f /* y */,
+ 0.0f /* sensorX */, 0.0f /* sensorY */, rotation))
+ .isEqualTo(touchHints[1])
+ // touch at 270 degrees -> 180 degrees
+ assertThat(controllerOverlay.onTouchOutsideOfSensorAreaImpl(0.0f /* x */, 1.0f /* y */,
+ 0.0f /* sensorX */, 0.0f /* sensorY */, rotation))
+ .isEqualTo(touchHints[2])
+ }
}
private class EnrollListener(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
index aa548d2..554e27d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -66,6 +66,7 @@
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.animation.ActivityLaunchAnimator;
+import com.android.systemui.broadcast.BroadcastSender;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.plugins.FalsingManager;
@@ -116,6 +117,7 @@
private UdfpsController mUdfpsController;
// Dependencies
+ private FakeExecutor mBiometricsExecutor;
private Execution mExecution;
@Mock
private LayoutInflater mLayoutInflater;
@@ -186,6 +188,8 @@
private ActivityLaunchAnimator mActivityLaunchAnimator;
@Mock
private AlternateUdfpsTouchProvider mAlternateTouchProvider;
+ @Mock
+ private BroadcastSender mBroadcastSender;
// Capture listeners so that they can be used to send events
@Captor private ArgumentCaptor<IUdfpsOverlayController> mOverlayCaptor;
@@ -231,6 +235,10 @@
true /* resetLockoutRequiresHardwareAuthToken */));
when(mFingerprintManager.getSensorPropertiesInternal()).thenReturn(props);
mFgExecutor = new FakeExecutor(new FakeSystemClock());
+
+ // Create a fake background executor.
+ mBiometricsExecutor = new FakeExecutor(new FakeSystemClock());
+
mUdfpsController = new UdfpsController(
mContext,
mExecution,
@@ -261,7 +269,9 @@
mSystemUIDialogManager,
mLatencyTracker,
mActivityLaunchAnimator,
- Optional.of(mAlternateTouchProvider));
+ Optional.of(mAlternateTouchProvider),
+ mBroadcastSender,
+ mBiometricsExecutor);
verify(mFingerprintManager).setUdfpsOverlayController(mOverlayCaptor.capture());
mOverlayController = mOverlayCaptor.getValue();
verify(mScreenLifecycle).addObserver(mScreenObserverCaptor.capture());
@@ -294,6 +304,7 @@
verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
MotionEvent downEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent);
+ mBiometricsExecutor.runAllReady();
downEvent.recycle();
// THEN notify keyguard authenticate to dismiss the keyguard
@@ -332,6 +343,7 @@
mFgExecutor.runAllReady();
}
mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
+ mBiometricsExecutor.runAllReady();
moveEvent.recycle();
// THEN notify keyguard authenticate to dismiss the keyguard
@@ -355,10 +367,12 @@
verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
MotionEvent downEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent);
+ mBiometricsExecutor.runAllReady();
downEvent.recycle();
MotionEvent moveEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 0, 0, 0);
mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
+ mBiometricsExecutor.runAllReady();
moveEvent.recycle();
// THEN notify keyguard authenticate to dismiss the keyguard
@@ -512,9 +526,11 @@
MotionEvent event = obtainMotionEvent(ACTION_DOWN, displayWidth, displayHeight, touchMinor,
touchMajor);
mTouchListenerCaptor.getValue().onTouch(mUdfpsView, event);
+ mBiometricsExecutor.runAllReady();
event.recycle();
event = obtainMotionEvent(ACTION_MOVE, displayWidth, displayHeight, touchMinor, touchMajor);
mTouchListenerCaptor.getValue().onTouch(mUdfpsView, event);
+ mBiometricsExecutor.runAllReady();
event.recycle();
verify(mAlternateTouchProvider).onPointerDown(eq(TEST_REQUEST_ID), eq(expectedX),
eq(expectedY), eq(expectedMinor), eq(expectedMajor));
@@ -526,9 +542,11 @@
Surface.ROTATION_90));
event = obtainMotionEvent(ACTION_DOWN, displayHeight, 0, touchMinor, touchMajor);
mTouchListenerCaptor.getValue().onTouch(mUdfpsView, event);
+ mBiometricsExecutor.runAllReady();
event.recycle();
event = obtainMotionEvent(ACTION_MOVE, displayHeight, 0, touchMinor, touchMajor);
mTouchListenerCaptor.getValue().onTouch(mUdfpsView, event);
+ mBiometricsExecutor.runAllReady();
event.recycle();
verify(mAlternateTouchProvider).onPointerDown(eq(TEST_REQUEST_ID), eq(expectedX),
eq(expectedY), eq(expectedMinor), eq(expectedMajor));
@@ -540,9 +558,11 @@
Surface.ROTATION_270));
event = obtainMotionEvent(ACTION_DOWN, 0, displayWidth, touchMinor, touchMajor);
mTouchListenerCaptor.getValue().onTouch(mUdfpsView, event);
+ mBiometricsExecutor.runAllReady();
event.recycle();
event = obtainMotionEvent(ACTION_MOVE, 0, displayWidth, touchMinor, touchMajor);
mTouchListenerCaptor.getValue().onTouch(mUdfpsView, event);
+ mBiometricsExecutor.runAllReady();
event.recycle();
verify(mAlternateTouchProvider).onPointerDown(eq(TEST_REQUEST_ID), eq(expectedX),
eq(expectedY), eq(expectedMinor), eq(expectedMajor));
@@ -555,9 +575,11 @@
// ROTATION_180 is not supported. It should be treated like ROTATION_0.
event = obtainMotionEvent(ACTION_DOWN, displayWidth, displayHeight, touchMinor, touchMajor);
mTouchListenerCaptor.getValue().onTouch(mUdfpsView, event);
+ mBiometricsExecutor.runAllReady();
event.recycle();
event = obtainMotionEvent(ACTION_MOVE, displayWidth, displayHeight, touchMinor, touchMajor);
mTouchListenerCaptor.getValue().onTouch(mUdfpsView, event);
+ mBiometricsExecutor.runAllReady();
event.recycle();
verify(mAlternateTouchProvider).onPointerDown(eq(TEST_REQUEST_ID), eq(expectedX),
eq(expectedY), eq(expectedMinor), eq(expectedMajor));
@@ -578,11 +600,13 @@
verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
MotionEvent downEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent);
+ mBiometricsExecutor.runAllReady();
downEvent.recycle();
MotionEvent moveEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 0, 0, 0);
// FIX THIS TEST
mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
+ mBiometricsExecutor.runAllReady();
moveEvent.recycle();
mFgExecutor.runAllReady();
// THEN FingerprintManager is notified about onPointerDown
@@ -597,6 +621,7 @@
verify(mKeyguardUpdateMonitor).onUdfpsPointerDown(eq((int) TEST_REQUEST_ID));
// AND onIlluminatedRunnable notifies FingerprintManager about onUiReady
mOnIlluminatedRunnableCaptor.getValue().run();
+ mBiometricsExecutor.runAllReady();
InOrder inOrder = inOrder(mAlternateTouchProvider, mLatencyTracker);
inOrder.verify(mAlternateTouchProvider).onUiReady();
inOrder.verify(mLatencyTracker).onActionEnd(eq(LatencyTracker.ACTION_UDFPS_ILLUMINATE));
@@ -617,6 +642,7 @@
// AND onIlluminatedRunnable that notifies FingerprintManager is set
verify(mUdfpsView).startIllumination(mOnIlluminatedRunnableCaptor.capture());
mOnIlluminatedRunnableCaptor.getValue().run();
+ mBiometricsExecutor.runAllReady();
verify(mAlternateTouchProvider).onPointerDown(eq(TEST_REQUEST_ID),
eq(0), eq(0), eq(3f) /* minor */, eq(2f) /* major */);
verify(mFingerprintManager, never()).onPointerDown(anyLong(), anyInt(), anyInt(), anyInt(),
@@ -742,9 +768,11 @@
verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
MotionEvent downEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent);
+ mBiometricsExecutor.runAllReady();
downEvent.recycle();
MotionEvent moveEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 0, 0, 0);
mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
+ mBiometricsExecutor.runAllReady();
moveEvent.recycle();
// THEN NO haptic played
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapterTest.java
index cd646c6..78fb5b0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapterTest.java
@@ -70,7 +70,7 @@
assertEquals(970,
UdfpsDialogMeasureAdapter.calculateBottomSpacerHeightForPortrait(
props, displayHeightPx, textIndicatorHeightPx, buttonBarHeightPx,
- dialogBottomMarginPx, navbarHeightPx
+ dialogBottomMarginPx, navbarHeightPx, 1.0f /* resolutionScale */
));
}
@@ -135,6 +135,7 @@
assertEquals(1205,
UdfpsDialogMeasureAdapter.calculateHorizontalSpacerWidthForLandscape(
- props, displayWidthPx, dialogMarginPx, navbarHorizontalInsetPx));
+ props, displayWidthPx, dialogMarginPx, navbarHorizontalInsetPx,
+ 1.0f /* resolutionScale */));
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/BroadcastDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/BroadcastDialogTest.java
new file mode 100644
index 0000000..a61cecb
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/BroadcastDialogTest.java
@@ -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.bluetooth;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
+
+import androidx.test.filters.SmallTest;
+
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.view.View;
+import android.widget.Button;
+import android.widget.TextView;
+
+import com.android.internal.logging.UiEventLogger;
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.media.dialog.MediaOutputDialogFactory;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+public class BroadcastDialogTest extends SysuiTestCase {
+
+ private static final String SWITCH_APP = "Music";
+ private static final String TEST_PACKAGE = "com.google.android.apps.nbu.files";
+ private BroadcastDialog mBroadcastDialog;
+ private View mDialogView;
+ private TextView mSubTitle;
+ private Button mChangeOutputButton;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mBroadcastDialog = new BroadcastDialog(mContext, mock(MediaOutputDialogFactory.class),
+ SWITCH_APP, TEST_PACKAGE, mock(UiEventLogger.class));
+ mBroadcastDialog.show();
+ mDialogView = mBroadcastDialog.mDialogView;
+ }
+
+ @After
+ public void tearDown() {
+ mBroadcastDialog.dismiss();
+ }
+
+ @Test
+ public void onCreate_withCurrentApp_checkSwitchAppContent() {
+ mSubTitle = mDialogView.requireViewById(R.id.dialog_subtitle);
+
+ assertThat(mSubTitle.getText()).isEqualTo(
+ mContext.getString(R.string.bt_le_audio_broadcast_dialog_sub_title, SWITCH_APP));
+ }
+
+ @Test
+ public void onClick_withChangeOutput_dismissBroadcastDialog() {
+ mChangeOutputButton = mDialogView.requireViewById(R.id.change_output);
+ mChangeOutputButton.performClick();
+
+ assertThat(mBroadcastDialog.isShowing()).isFalse();
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardListenerTest.java b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardListenerTest.java
index de04d3e..91214a8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardListenerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardListenerTest.java
@@ -19,6 +19,8 @@
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.CLIPBOARD_OVERLAY_ENABLED;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -26,7 +28,9 @@
import static org.mockito.Mockito.when;
import android.content.ClipData;
+import android.content.ClipDescription;
import android.content.ClipboardManager;
+import android.os.PersistableBundle;
import android.provider.DeviceConfig;
import androidx.test.filters.SmallTest;
@@ -139,4 +143,30 @@
verify(mClipboardOverlayControllerFactory, times(2)).create(any());
}
+
+ @Test
+ public void test_shouldSuppressOverlay() {
+ // Regardless of the package or emulator, nothing should be suppressed without the flag
+ assertFalse(ClipboardListener.shouldSuppressOverlay(mSampleClipData, mSampleSource,
+ false));
+ assertFalse(ClipboardListener.shouldSuppressOverlay(mSampleClipData,
+ ClipboardListener.SHELL_PACKAGE, false));
+ assertFalse(ClipboardListener.shouldSuppressOverlay(mSampleClipData, mSampleSource,
+ true));
+
+ ClipDescription desc = new ClipDescription("Test", new String[]{"text/plain"});
+ PersistableBundle bundle = new PersistableBundle();
+ bundle.putBoolean(ClipboardListener.EXTRA_SUPPRESS_OVERLAY, true);
+ desc.setExtras(bundle);
+ ClipData suppressableClipData = new ClipData(desc, new ClipData.Item("Test Item"));
+
+ // Clip data with the suppression extra is only honored in the emulator or with the shell
+ // package.
+ assertFalse(ClipboardListener.shouldSuppressOverlay(suppressableClipData, mSampleSource,
+ false));
+ assertTrue(ClipboardListener.shouldSuppressOverlay(suppressableClipData, mSampleSource,
+ true));
+ assertTrue(ClipboardListener.shouldSuppressOverlay(suppressableClipData,
+ ClipboardListener.SHELL_PACKAGE, false));
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dump/LogBufferHelper.kt b/packages/SystemUI/tests/src/com/android/systemui/dump/LogBufferHelper.kt
index 0720bdb..bd029a7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dump/LogBufferHelper.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/dump/LogBufferHelper.kt
@@ -24,7 +24,7 @@
* Creates a LogBuffer that will echo everything to logcat, which is useful for debugging tests.
*/
fun logcatLogBuffer(name: String = "EchoToLogcatLogBuffer") =
- LogBuffer(name, 50, 50, LogcatEchoTrackerAlways())
+ LogBuffer(name, 50, LogcatEchoTrackerAlways())
/**
* A [LogcatEchoTracker] that always allows echoing to the logcat.
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 2abc666..a4d2238 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardUnlockAnimationControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardUnlockAnimationControllerTest.kt
@@ -14,6 +14,8 @@
import com.android.keyguard.KeyguardViewController
import com.android.systemui.SysuiTestCase
import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.shared.system.smartspace.ILauncherUnlockAnimationController
+import com.android.systemui.statusbar.NotificationShadeWindowController
import com.android.systemui.statusbar.SysuiStatusBarStateController
import com.android.systemui.statusbar.phone.BiometricUnlockController
import com.android.systemui.statusbar.policy.KeyguardStateController
@@ -52,6 +54,11 @@
private lateinit var surfaceTransactionApplier: SyncRtSurfaceTransactionApplier
@Mock
private lateinit var statusBarStateController: SysuiStatusBarStateController
+ @Mock
+ private lateinit var notificationShadeWindowController: NotificationShadeWindowController
+
+ @Mock
+ private lateinit var launcherUnlockAnimationController: ILauncherUnlockAnimationController.Stub
private lateinit var remoteAnimationTarget: RemoteAnimationTarget
@@ -60,8 +67,11 @@
MockitoAnnotations.initMocks(this)
keyguardUnlockAnimationController = KeyguardUnlockAnimationController(
context, keyguardStateController, { keyguardViewMediator }, keyguardViewController,
- featureFlags, { biometricUnlockController }, statusBarStateController
+ featureFlags, { biometricUnlockController }, statusBarStateController,
+ notificationShadeWindowController
)
+ keyguardUnlockAnimationController.setLauncherUnlockController(
+ launcherUnlockAnimationController)
`when`(keyguardViewController.viewRootImpl).thenReturn(mock(ViewRootImpl::class.java))
@@ -194,4 +204,18 @@
assertTrue(keyguardUnlockAnimationController.isPlayingCannedUnlockAnimation())
assertFalse(keyguardUnlockAnimationController.surfaceBehindAlphaAnimator.isRunning)
}
+
+ @Test
+ fun doNotPlayCannedUnlockAnimation_ifLaunchingApp() {
+ `when`(notificationShadeWindowController.isLaunchingActivity).thenReturn(true)
+
+ keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation(
+ remoteAnimationTarget,
+ 0 /* startTime */,
+ true /* requestedShowSurfaceBehindKeyguard */
+ )
+
+ assertFalse(keyguardUnlockAnimationController.canPerformInWindowLauncherAnimations())
+ assertFalse(keyguardUnlockAnimationController.isPlayingCannedUnlockAnimation())
+ }
}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java
index c532ed5..24d0515 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java
@@ -135,8 +135,7 @@
.startMocking();
MockitoAnnotations.initMocks(this);
- when(mLockIconView.getResources()).thenReturn(mResources);
- when(mLockIconView.getContext()).thenReturn(mContext);
+ setupLockIconViewMocks();
when(mContext.getResources()).thenReturn(mResources);
when(mContext.getSystemService(WindowManager.class)).thenReturn(mWindowManager);
Rect windowBounds = new Rect(0, 0, 800, 1200);
@@ -206,13 +205,14 @@
}
@Test
- public void testUpdateFingerprintLocationOnAuthenticatorsRegistered() {
+ public void testUpdateLockIconLocationOnAuthenticatorsRegistered() {
// GIVEN fp sensor location is not available pre-init
when(mKeyguardUpdateMonitor.isUdfpsSupported()).thenReturn(false);
when(mAuthController.getFingerprintSensorLocation()).thenReturn(null);
mLockIconViewController.init();
captureAttachListener();
mAttachListener.onViewAttachedToWindow(mLockIconView);
+ resetLockIconView(); // reset any method call counts for when we verify method calls later
// GIVEN fp sensor location is available post-attached
captureAuthControllerCallback();
@@ -228,6 +228,29 @@
}
@Test
+ public void testUpdateLockIconLocationOnUdfpsLocationChanged() {
+ // GIVEN fp sensor location is not available pre-init
+ when(mKeyguardUpdateMonitor.isUdfpsSupported()).thenReturn(false);
+ when(mAuthController.getFingerprintSensorLocation()).thenReturn(null);
+ mLockIconViewController.init();
+ captureAttachListener();
+ mAttachListener.onViewAttachedToWindow(mLockIconView);
+ resetLockIconView(); // reset any method call counts for when we verify method calls later
+
+ // GIVEN fp sensor location is available post-attached
+ captureAuthControllerCallback();
+ Pair<Float, PointF> udfps = setupUdfps();
+
+ // WHEN udfps location changes
+ mAuthControllerCallback.onUdfpsLocationChanged();
+ mDelayableExecutor.runAllReady();
+
+ // THEN lock icon view location is updated with the same coordinates as auth controller vals
+ verify(mLockIconView).setCenterLocation(eq(udfps.second), eq(udfps.first),
+ eq(PADDING));
+ }
+
+ @Test
public void testLockIconViewBackgroundEnabledWhenUdfpsIsSupported() {
// GIVEN Udpfs sensor location is available
setupUdfps();
@@ -440,4 +463,14 @@
mKeyguardUpdateMonitorCallbackCaptor.capture());
mKeyguardUpdateMonitorCallback = mKeyguardUpdateMonitorCallbackCaptor.getValue();
}
+
+ private void setupLockIconViewMocks() {
+ when(mLockIconView.getResources()).thenReturn(mResources);
+ when(mLockIconView.getContext()).thenReturn(mContext);
+ }
+
+ private void resetLockIconView() {
+ reset(mLockIconView);
+ setupLockIconViewMocks();
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityControllerTest.java
index cd5740d..e9db8cc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityControllerTest.java
@@ -60,6 +60,13 @@
public class WorkLockActivityControllerTest extends SysuiTestCase {
private static final int USER_ID = 333;
private static final int TASK_ID = 444;
+ private static final ActivityManager.RunningTaskInfo TASK_INFO =
+ new ActivityManager.RunningTaskInfo();
+
+ static {
+ TASK_INFO.userId = USER_ID;
+ TASK_INFO.taskId = TASK_ID;
+ }
private @Mock Context mContext;
private @Mock TaskStackChangeListeners mTaskStackChangeListeners;
@@ -91,7 +98,7 @@
setActivityStartCode(TASK_ID, true /*taskOverlay*/, ActivityManager.START_SUCCESS);
// And the controller receives a message saying the profile is locked,
- mTaskStackListener.onTaskProfileLocked(TASK_ID, USER_ID);
+ mTaskStackListener.onTaskProfileLocked(TASK_INFO);
// The overlay should start and the task the activity started in should not be removed.
verifyStartActivity(TASK_ID, true /*taskOverlay*/);
@@ -104,7 +111,7 @@
setActivityStartCode(TASK_ID, true /*taskOverlay*/, ActivityManager.START_CLASS_NOT_FOUND);
// And the controller receives a message saying the profile is locked,
- mTaskStackListener.onTaskProfileLocked(TASK_ID, USER_ID);
+ mTaskStackListener.onTaskProfileLocked(TASK_INFO);
// The task the activity started in should be removed to prevent the locked task from
// being shown.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityTest.java
index e4c387a..640e6dc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityTest.java
@@ -16,8 +16,6 @@
package com.android.systemui.keyguard;
-import static android.app.ActivityManager.TaskDescription;
-
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.eq;
@@ -25,14 +23,15 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.annotation.ColorInt;
import android.annotation.UserIdInt;
-import android.app.KeyguardManager;
-import android.app.admin.DevicePolicyManager;
import android.content.Context;
import android.content.Intent;
-import android.graphics.Color;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.graphics.drawable.Drawable;
import android.os.Looper;
+import android.os.UserHandle;
+import android.os.UserManager;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -53,18 +52,21 @@
@RunWith(AndroidJUnit4.class)
public class WorkLockActivityTest extends SysuiTestCase {
private static final @UserIdInt int USER_ID = 270;
- private static final String TASK_LABEL = "task label";
+ private static final String CALLING_PACKAGE_NAME = "com.android.test";
- private @Mock DevicePolicyManager mDevicePolicyManager;
- private @Mock KeyguardManager mKeyguardManager;
+ private @Mock UserManager mUserManager;
+ private @Mock PackageManager mPackageManager;
private @Mock Context mContext;
private @Mock BroadcastDispatcher mBroadcastDispatcher;
+ private @Mock Drawable mDrawable;
+ private @Mock Drawable mBadgedDrawable;
private WorkLockActivity mActivity;
private static class WorkLockActivityTestable extends WorkLockActivity {
- WorkLockActivityTestable(Context baseContext, BroadcastDispatcher broadcastDispatcher) {
- super(broadcastDispatcher);
+ WorkLockActivityTestable(Context baseContext, BroadcastDispatcher broadcastDispatcher,
+ UserManager userManager, PackageManager packageManager) {
+ super(broadcastDispatcher, userManager, packageManager);
attachBaseContext(baseContext);
}
}
@@ -73,46 +75,26 @@
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- when(mContext.getSystemService(eq(Context.DEVICE_POLICY_SERVICE)))
- .thenReturn(mDevicePolicyManager);
- when(mContext.getSystemService(eq(Context.KEYGUARD_SERVICE)))
- .thenReturn(mKeyguardManager);
-
if (Looper.myLooper() == null) {
Looper.prepare();
}
- mActivity = new WorkLockActivityTestable(mContext, mBroadcastDispatcher);
+ mActivity = new WorkLockActivityTestable(mContext, mBroadcastDispatcher, mUserManager,
+ mPackageManager);
}
@Test
- public void testBackgroundAlwaysOpaque() throws Exception {
- final @ColorInt int orgColor = Color.rgb(250, 199, 67);
- when(mDevicePolicyManager.getOrganizationColorForUser(eq(USER_ID))).thenReturn(orgColor);
-
- final @ColorInt int opaqueColor= Color.rgb(164, 198, 57);
- final @ColorInt int transparentColor = Color.argb(0, 0, 0, 0);
- TaskDescription opaque = new TaskDescription(null, null, opaqueColor);
- TaskDescription transparent = new TaskDescription(null, null, transparentColor);
-
- // When a task description is provided with a suitable (opaque) primaryColor, it should be
- // used as the scrim's background color.
+ public void testGetBadgedIcon() throws Exception {
+ ApplicationInfo info = new ApplicationInfo();
+ when(mPackageManager.getApplicationInfoAsUser(eq(CALLING_PACKAGE_NAME), any(),
+ eq(USER_ID))).thenReturn(info);
+ when(mPackageManager.getApplicationIcon(eq(info))).thenReturn(mDrawable);
+ when(mUserManager.getBadgedIconForUser(any(), eq(UserHandle.of(USER_ID)))).thenReturn(
+ mBadgedDrawable);
mActivity.setIntent(new Intent()
.putExtra(Intent.EXTRA_USER_ID, USER_ID)
- .putExtra(WorkLockActivity.EXTRA_TASK_DESCRIPTION, opaque));
- assertEquals(opaqueColor, mActivity.getPrimaryColor());
+ .putExtra(Intent.EXTRA_PACKAGE_NAME, CALLING_PACKAGE_NAME));
- // When a task description is provided but has no primaryColor / the primaryColor is
- // transparent, the organization color should be used instead.
- mActivity.setIntent(new Intent()
- .putExtra(Intent.EXTRA_USER_ID, USER_ID)
- .putExtra(WorkLockActivity.EXTRA_TASK_DESCRIPTION, transparent));
- assertEquals(orgColor, mActivity.getPrimaryColor());
-
- // When no task description is provided at all, it should be treated like a transparent
- // description and the organization color shown instead.
- mActivity.setIntent(new Intent()
- .putExtra(Intent.EXTRA_USER_ID, USER_ID));
- assertEquals(orgColor, mActivity.getPrimaryColor());
+ assertEquals(mBadgedDrawable, mActivity.getBadgedIcon());
}
@Test
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 0d917e3..ceb811b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt
@@ -63,6 +63,7 @@
@Mock lateinit var falsingManager: FalsingManager
@Mock lateinit var dumpManager: DumpManager
@Mock lateinit var logger: MediaUiEventLogger
+ @Mock lateinit var debugLogger: MediaCarouselControllerLogger
private val clock = FakeSystemClock()
private lateinit var mediaCarouselController: MediaCarouselController
@@ -83,7 +84,8 @@
falsingCollector,
falsingManager,
dumpManager,
- logger
+ logger,
+ debugLogger
)
MediaPlayerData.clear()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
index 18aae0e..241ed24 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
@@ -21,6 +21,7 @@
import android.app.PendingIntent
import android.app.smartspace.SmartspaceAction
import android.content.Context
+import org.mockito.Mockito.`when` as whenever
import android.content.Intent
import android.content.pm.ApplicationInfo
import android.content.pm.PackageManager
@@ -67,8 +68,8 @@
import com.android.systemui.util.animation.TransitionLayout
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.KotlinArgumentCaptor
-import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.argumentCaptor
+import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.nullable
import com.android.systemui.util.mockito.withArgCaptor
@@ -92,7 +93,6 @@
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.junit.MockitoJUnit
-import org.mockito.Mockito.`when` as whenever
private const val KEY = "TEST_KEY"
private const val PACKAGE = "PKG"
@@ -342,7 +342,6 @@
whenever(viewHolder.player).thenReturn(view)
whenever(viewHolder.appIcon).thenReturn(appIcon)
whenever(viewHolder.albumView).thenReturn(albumView)
- whenever(albumView.foreground).thenReturn(mock(Drawable::class.java))
whenever(viewHolder.titleText).thenReturn(titleText)
whenever(viewHolder.artistText).thenReturn(artistText)
whenever(seamlessBackground.getDrawable(0)).thenReturn(mock(GradientDrawable::class.java))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaTimeoutListenerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaTimeoutListenerTest.kt
index 91c0cc2..823d4ae 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaTimeoutListenerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaTimeoutListenerTest.kt
@@ -23,6 +23,8 @@
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.statusbar.SysuiStatusBarStateController
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.capture
@@ -63,10 +65,13 @@
@Mock private lateinit var mediaControllerFactory: MediaControllerFactory
@Mock private lateinit var mediaController: MediaController
@Mock private lateinit var logger: MediaTimeoutLogger
+ @Mock private lateinit var statusBarStateController: SysuiStatusBarStateController
private lateinit var executor: FakeExecutor
@Mock private lateinit var timeoutCallback: (String, Boolean) -> Unit
@Mock private lateinit var stateCallback: (String, PlaybackState) -> Unit
@Captor private lateinit var mediaCallbackCaptor: ArgumentCaptor<MediaController.Callback>
+ @Captor private lateinit var dozingCallbackCaptor:
+ ArgumentCaptor<StatusBarStateController.StateListener>
@JvmField @Rule val mockito = MockitoJUnit.rule()
private lateinit var metadataBuilder: MediaMetadata.Builder
private lateinit var playbackBuilder: PlaybackState.Builder
@@ -74,12 +79,19 @@
private lateinit var mediaData: MediaData
private lateinit var resumeData: MediaData
private lateinit var mediaTimeoutListener: MediaTimeoutListener
+ private var clock = FakeSystemClock()
@Before
fun setup() {
`when`(mediaControllerFactory.create(any())).thenReturn(mediaController)
- executor = FakeExecutor(FakeSystemClock())
- mediaTimeoutListener = MediaTimeoutListener(mediaControllerFactory, executor, logger)
+ executor = FakeExecutor(clock)
+ mediaTimeoutListener = MediaTimeoutListener(
+ mediaControllerFactory,
+ executor,
+ logger,
+ statusBarStateController,
+ clock
+ )
mediaTimeoutListener.timeoutCallback = timeoutCallback
mediaTimeoutListener.stateCallback = stateCallback
@@ -530,6 +542,49 @@
verify(stateCallback, never()).invoke(eq(KEY), eq(playingState!!))
}
+ @Test
+ fun testTimeoutCallback_dozedPastTimeout_invokedOnWakeup() {
+ // When paused media is loaded
+ testOnMediaDataLoaded_registersPlaybackListener()
+ mediaCallbackCaptor.value.onPlaybackStateChanged(PlaybackState.Builder()
+ .setState(PlaybackState.STATE_PAUSED, 0L, 0f).build())
+ verify(statusBarStateController).addCallback(capture(dozingCallbackCaptor))
+
+ // And we doze past the scheduled timeout
+ val time = clock.currentTimeMillis()
+ clock.setElapsedRealtime(time + PAUSED_MEDIA_TIMEOUT)
+ assertThat(executor.numPending()).isEqualTo(1)
+
+ // Then when no longer dozing, the timeout runs immediately
+ dozingCallbackCaptor.value.onDozingChanged(false)
+ verify(timeoutCallback).invoke(eq(KEY), eq(true))
+ verify(logger).logTimeout(eq(KEY))
+
+ // and cancel any later scheduled timeout
+ verify(logger).logTimeoutCancelled(eq(KEY), any())
+ assertThat(executor.numPending()).isEqualTo(0)
+ }
+
+ @Test
+ fun testTimeoutCallback_dozeShortTime_notInvokedOnWakeup() {
+ // When paused media is loaded
+ val time = clock.currentTimeMillis()
+ clock.setElapsedRealtime(time)
+ testOnMediaDataLoaded_registersPlaybackListener()
+ mediaCallbackCaptor.value.onPlaybackStateChanged(PlaybackState.Builder()
+ .setState(PlaybackState.STATE_PAUSED, 0L, 0f).build())
+ verify(statusBarStateController).addCallback(capture(dozingCallbackCaptor))
+
+ // And we doze, but not past the scheduled timeout
+ clock.setElapsedRealtime(time + PAUSED_MEDIA_TIMEOUT / 2L)
+ assertThat(executor.numPending()).isEqualTo(1)
+
+ // Then when no longer dozing, the timeout remains scheduled
+ dozingCallbackCaptor.value.onDozingChanged(false)
+ verify(timeoutCallback, never()).invoke(eq(KEY), eq(true))
+ assertThat(executor.numPending()).isEqualTo(1)
+ }
+
private fun loadMediaDataWithPlaybackState(state: PlaybackState) {
`when`(mediaController.playbackState).thenReturn(state)
mediaTimeoutListener.onMediaDataLoaded(KEY, null, mediaData)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/ResumeMediaBrowserTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/ResumeMediaBrowserTest.kt
index a074475..dafaa6b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/ResumeMediaBrowserTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/ResumeMediaBrowserTest.kt
@@ -35,6 +35,7 @@
import org.mockito.Captor
import org.mockito.Mock
import org.mockito.Mockito
+import org.mockito.Mockito.reset
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
import org.mockito.Mockito.`when` as whenever
@@ -73,6 +74,7 @@
@Captor lateinit var connectionCallback: ArgumentCaptor<MediaBrowser.ConnectionCallback>
@Captor lateinit var subscriptionCallback: ArgumentCaptor<MediaBrowser.SubscriptionCallback>
+ @Captor lateinit var mediaControllerCallback: ArgumentCaptor<MediaController.Callback>
@Before
fun setUp() {
@@ -82,6 +84,7 @@
.thenReturn(browser)
whenever(mediaController.transportControls).thenReturn(transportControls)
+ whenever(mediaController.sessionToken).thenReturn(token)
resumeBrowser = TestableResumeMediaBrowser(
context,
@@ -137,6 +140,22 @@
}
@Test
+ fun testConnection_thenSessionDestroyed_disconnects() {
+ // When testConnection is called and we connect successfully
+ setupBrowserConnection()
+ resumeBrowser.testConnection()
+ verify(mediaController).registerCallback(mediaControllerCallback.capture())
+ reset(browser)
+
+ // And a sessionDestroyed event is triggered
+ mediaControllerCallback.value.onSessionDestroyed()
+
+ // Then we disconnect the browser and unregister the callback
+ verify(browser).disconnect()
+ verify(mediaController).unregisterCallback(mediaControllerCallback.value)
+ }
+
+ @Test
fun testConnection_calledTwice_oldBrowserDisconnected() {
val oldBrowser = mock<MediaBrowser>()
whenever(browserFactory.create(any(), any(), any())).thenReturn(oldBrowser)
@@ -188,6 +207,22 @@
}
@Test
+ fun testFindRecentMedia_thenSessionDestroyed_disconnects() {
+ // When findRecentMedia is called and we connect successfully
+ setupBrowserConnection()
+ resumeBrowser.findRecentMedia()
+ verify(mediaController).registerCallback(mediaControllerCallback.capture())
+ reset(browser)
+
+ // And a sessionDestroyed event is triggered
+ mediaControllerCallback.value.onSessionDestroyed()
+
+ // Then we disconnect the browser and unregister the callback
+ verify(browser).disconnect()
+ verify(mediaController).unregisterCallback(mediaControllerCallback.value)
+ }
+
+ @Test
fun testFindRecentMedia_calledTwice_oldBrowserDisconnected() {
val oldBrowser = mock<MediaBrowser>()
whenever(browserFactory.create(any(), any(), any())).thenReturn(oldBrowser)
@@ -261,6 +296,22 @@
}
@Test
+ fun testRestart_thenSessionDestroyed_disconnects() {
+ // When restart is called and we connect successfully
+ setupBrowserConnection()
+ resumeBrowser.restart()
+ verify(mediaController).registerCallback(mediaControllerCallback.capture())
+ reset(browser)
+
+ // And a sessionDestroyed event is triggered
+ mediaControllerCallback.value.onSessionDestroyed()
+
+ // Then we disconnect the browser and unregister the callback
+ verify(browser).disconnect()
+ verify(mediaController).unregisterCallback(mediaControllerCallback.value)
+ }
+
+ @Test
fun testRestart_calledTwice_oldBrowserDisconnected() {
val oldBrowser = mock<MediaBrowser>()
whenever(browserFactory.create(any(), any(), any())).thenReturn(oldBrowser)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/monet/ColorSchemeTest.java b/packages/SystemUI/tests/src/com/android/systemui/monet/ColorSchemeTest.java
index 863484b..890e4de 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/monet/ColorSchemeTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/monet/ColorSchemeTest.java
@@ -133,7 +133,7 @@
Style.VIBRANT /* style */);
int neutralMid = colorScheme.getNeutral1().get(colorScheme.getNeutral1().size() / 2);
Cam cam = Cam.fromInt(neutralMid);
- Assert.assertTrue("chroma was " + cam.getChroma(), Math.floor(cam.getChroma()) <= 10.0);
+ Assert.assertTrue("chroma was " + cam.getChroma(), Math.floor(cam.getChroma()) <= 12.0);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qrcodescanner/controller/QRCodeScannerControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qrcodescanner/controller/QRCodeScannerControllerTest.java
index 4a6bbbc..346d1e6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qrcodescanner/controller/QRCodeScannerControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qrcodescanner/controller/QRCodeScannerControllerTest.java
@@ -24,7 +24,6 @@
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -32,6 +31,7 @@
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
import android.os.UserHandle;
import android.provider.DeviceConfig;
import android.provider.Settings;
@@ -41,7 +41,6 @@
import androidx.test.filters.SmallTest;
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
-import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.util.DeviceConfigProxyFake;
@@ -90,8 +89,9 @@
when(mPackageManager.queryIntentActivities(any(Intent.class),
any(Integer.class))).thenReturn(resolveInfoList);
when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA)).thenReturn(true);
- mContext.getOrCreateTestableResources().addOverride(R.string.def_qr_code_component,
- defaultActivity);
+ mContext.getOrCreateTestableResources().addOverride(
+ com.android.internal.R.string.config_defaultQrCodeComponent, defaultActivity);
+
mContext.getOrCreateTestableResources().addOverride(
android.R.bool.config_enableQrCodeScannerOnLockScreen, enableOnLockScreen);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/FgsManagerControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/FgsManagerControllerTest.java
new file mode 100644
index 0000000..2927669
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/FgsManagerControllerTest.java
@@ -0,0 +1,285 @@
+/*
+ * 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;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.app.IActivityManager;
+import android.app.IForegroundServiceObserver;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
+import android.os.Binder;
+import android.os.RemoteException;
+import android.provider.DeviceConfig;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.animation.DialogLaunchAnimator;
+import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.dump.DumpManager;
+import com.android.systemui.settings.UserTracker;
+import com.android.systemui.util.DeviceConfigProxyFake;
+import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.time.FakeSystemClock;
+
+import org.junit.Assert;
+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;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+@SmallTest
+public class FgsManagerControllerTest extends SysuiTestCase {
+
+ FakeSystemClock mSystemClock;
+ FakeExecutor mMainExecutor;
+ FakeExecutor mBackgroundExecutor;
+ DeviceConfigProxyFake mDeviceConfigProxyFake;
+
+ @Mock
+ IActivityManager mIActivityManager;
+ @Mock
+ PackageManager mPackageManager;
+ @Mock
+ UserTracker mUserTracker;
+ @Mock
+ DialogLaunchAnimator mDialogLaunchAnimator;
+ @Mock
+ BroadcastDispatcher mBroadcastDispatcher;
+ @Mock
+ DumpManager mDumpManager;
+
+ private FgsManagerController mFmc;
+
+ private IForegroundServiceObserver mIForegroundServiceObserver;
+ private UserTracker.Callback mUserTrackerCallback;
+ private BroadcastReceiver mShowFgsManagerReceiver;
+
+ private List<UserInfo> mUserProfiles;
+
+ @Before
+ public void setUp() throws RemoteException {
+ MockitoAnnotations.initMocks(this);
+
+ mDeviceConfigProxyFake = new DeviceConfigProxyFake();
+ mDeviceConfigProxyFake.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
+ SystemUiDeviceConfigFlags.TASK_MANAGER_ENABLED, "true", false);
+ mSystemClock = new FakeSystemClock();
+ mMainExecutor = new FakeExecutor(mSystemClock);
+ mBackgroundExecutor = new FakeExecutor(mSystemClock);
+
+ mUserProfiles = new ArrayList<>();
+ Mockito.doReturn(mUserProfiles).when(mUserTracker).getUserProfiles();
+
+ mFmc = createFgsManagerController();
+ }
+
+ @Test
+ public void testNumPackages() throws RemoteException {
+ setUserProfiles(0);
+
+ Binder b1 = new Binder();
+ Binder b2 = new Binder();
+ Assert.assertEquals(0, mFmc.getNumRunningPackages());
+ mIForegroundServiceObserver.onForegroundStateChanged(b1, "pkg1", 0, true);
+ Assert.assertEquals(1, mFmc.getNumRunningPackages());
+ mIForegroundServiceObserver.onForegroundStateChanged(b2, "pkg2", 0, true);
+ Assert.assertEquals(2, mFmc.getNumRunningPackages());
+ mIForegroundServiceObserver.onForegroundStateChanged(b1, "pkg1", 0, false);
+ Assert.assertEquals(1, mFmc.getNumRunningPackages());
+ mIForegroundServiceObserver.onForegroundStateChanged(b2, "pkg2", 0, false);
+ Assert.assertEquals(0, mFmc.getNumRunningPackages());
+ }
+
+ @Test
+ public void testNumPackagesDoesNotChangeWhenSecondFgsIsStarted() throws RemoteException {
+ setUserProfiles(0);
+
+ // Different tokens == different services
+ Binder b1 = new Binder();
+ Binder b2 = new Binder();
+ Assert.assertEquals(0, mFmc.getNumRunningPackages());
+ mIForegroundServiceObserver.onForegroundStateChanged(b1, "pkg1", 0, true);
+ Assert.assertEquals(1, mFmc.getNumRunningPackages());
+ mIForegroundServiceObserver.onForegroundStateChanged(b2, "pkg1", 0, true);
+ Assert.assertEquals(1, mFmc.getNumRunningPackages());
+ mIForegroundServiceObserver.onForegroundStateChanged(b1, "pkg1", 0, false);
+ Assert.assertEquals(1, mFmc.getNumRunningPackages());
+ mIForegroundServiceObserver.onForegroundStateChanged(b2, "pkg1", 0, false);
+ Assert.assertEquals(0, mFmc.getNumRunningPackages());
+ }
+
+ @Test
+ public void testNumPackagesListener() throws RemoteException {
+ setUserProfiles(0);
+
+ FgsManagerController.OnNumberOfPackagesChangedListener onNumberOfPackagesChangedListener =
+ Mockito.mock(FgsManagerController.OnNumberOfPackagesChangedListener.class);
+
+ mFmc.addOnNumberOfPackagesChangedListener(onNumberOfPackagesChangedListener);
+
+ Binder b1 = new Binder();
+ Binder b2 = new Binder();
+
+ verify(onNumberOfPackagesChangedListener, never()).onNumberOfPackagesChanged(anyInt());
+
+ mIForegroundServiceObserver.onForegroundStateChanged(b1, "pkg1", 0, true);
+ mBackgroundExecutor.advanceClockToLast();
+ mBackgroundExecutor.runAllReady();
+ verify(onNumberOfPackagesChangedListener).onNumberOfPackagesChanged(1);
+
+ mIForegroundServiceObserver.onForegroundStateChanged(b2, "pkg2", 0, true);
+ mBackgroundExecutor.advanceClockToLast();
+ mBackgroundExecutor.runAllReady();
+ verify(onNumberOfPackagesChangedListener).onNumberOfPackagesChanged(2);
+
+ mIForegroundServiceObserver.onForegroundStateChanged(b1, "pkg1", 0, false);
+ mBackgroundExecutor.advanceClockToLast();
+ mBackgroundExecutor.runAllReady();
+ verify(onNumberOfPackagesChangedListener, times(2)).onNumberOfPackagesChanged(1);
+
+ mIForegroundServiceObserver.onForegroundStateChanged(b2, "pkg2", 0, false);
+ mBackgroundExecutor.advanceClockToLast();
+ mBackgroundExecutor.runAllReady();
+ verify(onNumberOfPackagesChangedListener).onNumberOfPackagesChanged(0);
+ }
+
+ @Test
+ public void testChangesSinceLastDialog() throws RemoteException {
+ setUserProfiles(0);
+
+ Assert.assertFalse(mFmc.getChangesSinceDialog());
+ mIForegroundServiceObserver.onForegroundStateChanged(new Binder(), "pkg", 0, true);
+ Assert.assertTrue(mFmc.getChangesSinceDialog());
+ }
+
+ @Test
+ public void testProfilePackagesCounted() throws RemoteException {
+ setUserProfiles(0, 10);
+
+ mIForegroundServiceObserver.onForegroundStateChanged(new Binder(), "pkg1", 0, true);
+ mIForegroundServiceObserver.onForegroundStateChanged(new Binder(), "pkg2", 10, true);
+ Assert.assertEquals(2, mFmc.getNumRunningPackages());
+ }
+
+ @Test
+ public void testSecondaryUserPackagesAreNotCounted() throws RemoteException {
+ setUserProfiles(0);
+
+ mIForegroundServiceObserver.onForegroundStateChanged(new Binder(), "pkg1", 0, true);
+ mIForegroundServiceObserver.onForegroundStateChanged(new Binder(), "pkg2", 10, true);
+ Assert.assertEquals(1, mFmc.getNumRunningPackages());
+ }
+
+ @Test
+ public void testSecondaryUserPackagesAreCountedWhenUserSwitch() throws RemoteException {
+ setUserProfiles(0);
+
+ mIForegroundServiceObserver.onForegroundStateChanged(new Binder(), "pkg1", 0, true);
+ mIForegroundServiceObserver.onForegroundStateChanged(new Binder(), "pkg2", 10, true);
+ mIForegroundServiceObserver.onForegroundStateChanged(new Binder(), "pkg3", 10, true);
+
+ Assert.assertEquals(1, mFmc.getNumRunningPackages());
+
+ setUserProfiles(10);
+ Assert.assertEquals(2, mFmc.getNumRunningPackages());
+ }
+
+
+
+ FgsManagerController createFgsManagerController() throws RemoteException {
+ ArgumentCaptor<IForegroundServiceObserver> iForegroundServiceObserverArgumentCaptor =
+ ArgumentCaptor.forClass(IForegroundServiceObserver.class);
+ ArgumentCaptor<UserTracker.Callback> userTrackerCallbackArgumentCaptor =
+ ArgumentCaptor.forClass(UserTracker.Callback.class);
+ ArgumentCaptor<BroadcastReceiver> showFgsManagerReceiverArgumentCaptor =
+ ArgumentCaptor.forClass(BroadcastReceiver.class);
+
+ FgsManagerController result = new FgsManagerController(
+ mContext,
+ mMainExecutor,
+ mBackgroundExecutor,
+ mSystemClock,
+ mIActivityManager,
+ mPackageManager,
+ mUserTracker,
+ mDeviceConfigProxyFake,
+ mDialogLaunchAnimator,
+ mBroadcastDispatcher,
+ mDumpManager
+ );
+ result.init();
+
+ verify(mIActivityManager).registerForegroundServiceObserver(
+ iForegroundServiceObserverArgumentCaptor.capture()
+ );
+ verify(mUserTracker).addCallback(
+ userTrackerCallbackArgumentCaptor.capture(),
+ ArgumentMatchers.eq(mBackgroundExecutor)
+ );
+ verify(mBroadcastDispatcher).registerReceiver(
+ showFgsManagerReceiverArgumentCaptor.capture(),
+ argThat(fltr -> fltr.matchAction(Intent.ACTION_SHOW_FOREGROUND_SERVICE_MANAGER)),
+ eq(mMainExecutor),
+ isNull(),
+ eq(Context.RECEIVER_NOT_EXPORTED),
+ isNull()
+ );
+
+ mIForegroundServiceObserver = iForegroundServiceObserverArgumentCaptor.getValue();
+ mUserTrackerCallback = userTrackerCallbackArgumentCaptor.getValue();
+ mShowFgsManagerReceiver = showFgsManagerReceiverArgumentCaptor.getValue();
+
+ return result;
+ }
+
+ private void setUserProfiles(int current, int... profileUserIds) {
+ mUserProfiles.clear();
+ mUserProfiles.add(new UserInfo(current, "current:" + current, 0));
+ for (int id : profileUserIds) {
+ mUserProfiles.add(new UserInfo(id, "profile:" + id, 0));
+ }
+
+ if (mUserTrackerCallback != null) {
+ mUserTrackerCallback.onUserChanged(current, mock(Context.class));
+ mUserTrackerCallback.onProfilesChanged(mUserProfiles);
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DreamTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DreamTileTest.java
index f4a6df8..c2a41d5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DreamTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DreamTileTest.java
@@ -17,7 +17,10 @@
package com.android.systemui.qs.tiles;
import static junit.framework.TestCase.assertEquals;
+import static junit.framework.TestCase.assertFalse;
+import static junit.framework.TestCase.assertTrue;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -25,6 +28,7 @@
import android.content.ComponentName;
import android.os.Handler;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.provider.Settings;
import android.service.dreams.IDreamManager;
import android.service.quicksettings.Tile;
@@ -42,6 +46,7 @@
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.qs.QSTileHost;
import com.android.systemui.qs.logging.QSLogger;
+import com.android.systemui.settings.UserTracker;
import com.android.systemui.util.settings.FakeSettings;
import com.android.systemui.util.settings.SecureSettings;
@@ -70,6 +75,8 @@
private IDreamManager mDreamManager;
@Mock
private BroadcastDispatcher mBroadcastDispatcher;
+ @Mock
+ private UserTracker mUserTracker;
private TestableLooper mTestableLooper;
@@ -94,18 +101,7 @@
when(mHost.getUserId()).thenReturn(DEFAULT_USER);
when(mHost.getContext()).thenReturn(mContext);
- mTile = spy(new DreamTile(
- mHost,
- mTestableLooper.getLooper(),
- new Handler(mTestableLooper.getLooper()),
- new FalsingManagerFake(),
- mMetricsLogger,
- mStatusBarStateController,
- mActivityStarter,
- mQSLogger,
- mDreamManager,
- mSecureSettings,
- mBroadcastDispatcher));
+ mTile = spy(constructTileForTest(true, false));
mTestableLooper.processAllMessages();
mTile.initialize();
@@ -195,8 +191,51 @@
mTile.getContentDescription(testDreamName));
}
+ @Test
+ public void testUserAvailability() {
+ DreamTile unsupportedTile = constructTileForTest(false, true);
+ assertFalse(unsupportedTile.isAvailable());
+
+ DreamTile supportedTileAllUsers = constructTileForTest(true, false);
+
+ UserHandle systemUserHandle = mock(UserHandle.class);
+ when(systemUserHandle.isSystem()).thenReturn(true);
+
+ UserHandle nonSystemUserHandle = mock(UserHandle.class);
+ when(nonSystemUserHandle.isSystem()).thenReturn(false);
+
+ when(mUserTracker.getUserHandle()).thenReturn(systemUserHandle);
+ assertTrue(supportedTileAllUsers.isAvailable());
+ when(mUserTracker.getUserHandle()).thenReturn(nonSystemUserHandle);
+ assertTrue(supportedTileAllUsers.isAvailable());
+
+ DreamTile supportedTileOnlySystemUser = constructTileForTest(true, true);
+ when(mUserTracker.getUserHandle()).thenReturn(systemUserHandle);
+ assertTrue(supportedTileOnlySystemUser.isAvailable());
+ when(mUserTracker.getUserHandle()).thenReturn(nonSystemUserHandle);
+ assertFalse(supportedTileOnlySystemUser.isAvailable());
+ }
+
private void setScreensaverEnabled(boolean enabled) {
mSecureSettings.putIntForUser(Settings.Secure.SCREENSAVER_ENABLED, enabled ? 1 : 0,
DEFAULT_USER);
}
+
+ private DreamTile constructTileForTest(boolean dreamSupported,
+ boolean dreamOnlyEnabledForSystemUser) {
+ return new DreamTile(
+ mHost,
+ mTestableLooper.getLooper(),
+ new Handler(mTestableLooper.getLooper()),
+ new FalsingManagerFake(),
+ mMetricsLogger,
+ mStatusBarStateController,
+ mActivityStarter,
+ mQSLogger,
+ mDreamManager,
+ mSecureSettings,
+ mBroadcastDispatcher,
+ mUserTracker,
+ dreamSupported, dreamOnlyEnabledForSystemUser);
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/HotspotTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/HotspotTileTest.java
new file mode 100644
index 0000000..b86713d
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/HotspotTileTest.java
@@ -0,0 +1,125 @@
+/*
+ * 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 static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.os.Handler;
+import android.service.quicksettings.Tile;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.dx.mockito.inline.extended.ExtendedMockito;
+import com.android.internal.logging.MetricsLogger;
+import com.android.settingslib.wifi.WifiEnterpriseRestrictionUtils;
+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.statusbar.policy.DataSaverController;
+import com.android.systemui.statusbar.policy.HotspotController;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoSession;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+@SmallTest
+public class HotspotTileTest extends SysuiTestCase {
+
+ @Rule
+ public MockitoRule mRule = MockitoJUnit.rule();
+ @Mock
+ private QSTileHost mHost;
+ @Mock
+ private HotspotController mHotspotController;
+ @Mock
+ private DataSaverController mDataSaverController;
+
+ private TestableLooper mTestableLooper;
+ private HotspotTile mTile;
+ private QSTile.BooleanState mState = new QSTile.BooleanState();
+
+ @Before
+ public void setUp() throws Exception {
+ mTestableLooper = TestableLooper.get(this);
+ when(mHost.getContext()).thenReturn(mContext);
+ when(mHost.getUserContext()).thenReturn(mContext);
+ when(mDataSaverController.isDataSaverEnabled()).thenReturn(false);
+
+ mTile = new HotspotTile(
+ mHost,
+ mTestableLooper.getLooper(),
+ new Handler(mTestableLooper.getLooper()),
+ new FalsingManagerFake(),
+ mock(MetricsLogger.class),
+ mock(StatusBarStateController.class),
+ mock(ActivityStarter.class),
+ mock(QSLogger.class),
+ mHotspotController,
+ mDataSaverController
+ );
+
+ mTile.initialize();
+ mTestableLooper.processAllMessages();
+ }
+
+ @Test
+ public void handleUpdateState_wifiTetheringIsAllowed_stateIsNotUnavailable() {
+ MockitoSession mockitoSession = ExtendedMockito.mockitoSession()
+ .spyStatic(WifiEnterpriseRestrictionUtils.class)
+ .startMocking();
+ when(WifiEnterpriseRestrictionUtils.isWifiTetheringAllowed(mContext)).thenReturn(true);
+
+ mTile.handleUpdateState(mState, null);
+
+ assertThat(mState.state).isNotEqualTo(Tile.STATE_UNAVAILABLE);
+ assertThat(String.valueOf(mState.secondaryLabel))
+ .isNotEqualTo(mContext.getString(R.string.wifitrackerlib_admin_restricted_network));
+ mockitoSession.finishMocking();
+ }
+
+ @Test
+ public void handleUpdateState_wifiTetheringIsDisallowed_stateIsUnavailable() {
+ MockitoSession mockitoSession = ExtendedMockito.mockitoSession()
+ .spyStatic(WifiEnterpriseRestrictionUtils.class)
+ .startMocking();
+ when(WifiEnterpriseRestrictionUtils.isWifiTetheringAllowed(mContext)).thenReturn(false);
+
+ mTile.handleUpdateState(mState, null);
+
+ assertThat(mState.state).isEqualTo(Tile.STATE_UNAVAILABLE);
+ assertThat(String.valueOf(mState.secondaryLabel))
+ .isEqualTo(mContext.getString(R.string.wifitrackerlib_admin_restricted_network));
+ mockitoSession.finishMocking();
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimatorTest.kt
index 3231415..a4a89a4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimatorTest.kt
@@ -1,3 +1,17 @@
+/*
+ * 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.shared.animation
import android.testing.AndroidTestingRunner
@@ -7,31 +21,24 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.shared.animation.UnfoldConstantTranslateAnimator.Direction
import com.android.systemui.shared.animation.UnfoldConstantTranslateAnimator.ViewIdToTranslate
-import com.android.systemui.unfold.UnfoldTransitionProgressProvider
-import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
+import com.android.systemui.unfold.TestUnfoldTransitionProvider
import org.junit.Assert.assertEquals
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.`when` as whenever
import org.mockito.MockitoAnnotations
+import org.mockito.Mockito.`when` as whenever
@SmallTest
@RunWith(AndroidTestingRunner::class)
class UnfoldConstantTranslateAnimatorTest : SysuiTestCase() {
- @Mock private lateinit var progressProvider: UnfoldTransitionProgressProvider
+ private val progressProvider = TestUnfoldTransitionProvider()
@Mock private lateinit var parent: ViewGroup
- @Captor private lateinit var progressListenerCaptor: ArgumentCaptor<TransitionProgressListener>
-
private lateinit var animator: UnfoldConstantTranslateAnimator
- private lateinit var progressListener: TransitionProgressListener
private val viewsIdToRegister =
setOf(
@@ -46,17 +53,14 @@
UnfoldConstantTranslateAnimator(viewsIdToRegister, progressProvider)
animator.init(parent, MAX_TRANSLATION)
-
- verify(progressProvider).addCallback(progressListenerCaptor.capture())
- progressListener = progressListenerCaptor.value
}
@Test
fun onTransition_noMatchingIds() {
// GIVEN no views matching any ids
// WHEN the transition starts
- progressListener.onTransitionStarted()
- progressListener.onTransitionProgress(.1f)
+ progressProvider.onTransitionStarted()
+ progressProvider.onTransitionProgress(.1f)
// THEN nothing... no exceptions
}
@@ -86,22 +90,22 @@
// Compare values as ints because -0f != 0f
// WHEN the transition starts
- progressListener.onTransitionStarted()
- progressListener.onTransitionProgress(0f)
+ progressProvider.onTransitionStarted()
+ progressProvider.onTransitionProgress(0f)
list.forEach { (view, direction) ->
assertEquals((-MAX_TRANSLATION * direction).toInt(), view.translationX.toInt())
}
// WHEN the transition progresses, translation is updated
- progressListener.onTransitionProgress(.5f)
+ progressProvider.onTransitionProgress(.5f)
list.forEach { (view, direction) ->
assertEquals((-MAX_TRANSLATION / 2f * direction).toInt(), view.translationX.toInt())
}
// WHEN the transition ends, translation is completed
- progressListener.onTransitionProgress(1f)
- progressListener.onTransitionFinished()
+ progressProvider.onTransitionProgress(1f)
+ progressProvider.onTransitionFinished()
list.forEach { (view, _) -> assertEquals(0, view.translationX.toInt()) }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LSShadeTransitionLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LSShadeTransitionLoggerTest.kt
index 6971c63..8cb530c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LSShadeTransitionLoggerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LSShadeTransitionLoggerTest.kt
@@ -30,7 +30,7 @@
@Before
fun setup() {
logger = LSShadeTransitionLogger(
- LogBuffer("Test", 10, 10, mock()),
+ LogBuffer("Test", 10, mock()),
gestureLogger,
displayMetrics)
}
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 562c970..73e574e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
@@ -130,8 +130,8 @@
whenever(statusbarStateController.state).thenReturn(StatusBarState.KEYGUARD)
whenever(nsslController.isInLockedDownShade).thenReturn(false)
whenever(qS.isFullyCollapsed).thenReturn(true)
- whenever(lockScreenUserManager.userAllowsPrivateNotificationsInPublic(anyInt())).thenReturn(
- true)
+ whenever(lockScreenUserManager.sensitiveNotifsNeedRedactionInPublic(anyInt()))
+ .thenReturn(false)
whenever(lockScreenUserManager.shouldShowLockscreenNotifications()).thenReturn(true)
whenever(lockScreenUserManager.isLockscreenPublicMode(anyInt())).thenReturn(true)
whenever(falsingCollector.shouldEnforceBouncer()).thenReturn(false)
@@ -207,8 +207,8 @@
@Test
fun testTriggeringBouncerWhenPrivateNotificationsArentAllowed() {
- whenever(lockScreenUserManager.userAllowsPrivateNotificationsInPublic(anyInt())).thenReturn(
- false)
+ whenever(lockScreenUserManager.sensitiveNotifsNeedRedactionInPublic(anyInt()))
+ .thenReturn(true)
transitionController.goToLockedShade(null)
verify(statusbarStateController, never()).setState(anyInt())
verify(statusbarStateController).setLeaveOpenOnKeyguardHide(true)
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 7687d12..18937e7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
@@ -53,11 +53,13 @@
import androidx.test.filters.SmallTest;
+import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.Dependency;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.recents.OverviewProxyService;
import com.android.systemui.statusbar.NotificationLockscreenUserManager.KeyguardNotificationSuppressor;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -106,6 +108,10 @@
private BroadcastDispatcher mBroadcastDispatcher;
@Mock
private KeyguardStateController mKeyguardStateController;
+ @Mock
+ private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ @Mock
+ private OverviewProxyService mOverviewProxyService;
private UserInfo mCurrentUser;
private UserInfo mSecondaryUser;
@@ -119,7 +125,6 @@
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- mDependency.injectTestDependency(NotificationEntryManager.class, mEntryManager);
int currentUserId = ActivityManager.getCurrentUser();
mSettings = new FakeSettings();
@@ -212,7 +217,7 @@
mLockscreenUserManager.getLockscreenSettingsObserverForTest().onChange(false);
// THEN current user's notification is redacted
- assertTrue(mLockscreenUserManager.needsRedaction(mCurrentUserNotif));
+ assertTrue(mLockscreenUserManager.notifNeedsRedactionInPublic(mCurrentUserNotif));
}
@Test
@@ -223,7 +228,7 @@
mLockscreenUserManager.getLockscreenSettingsObserverForTest().onChange(false);
// THEN current user's notification isn't redacted
- assertFalse(mLockscreenUserManager.needsRedaction(mCurrentUserNotif));
+ assertFalse(mLockscreenUserManager.notifNeedsRedactionInPublic(mCurrentUserNotif));
}
@Test
@@ -234,7 +239,7 @@
mLockscreenUserManager.getLockscreenSettingsObserverForTest().onChange(false);
// THEN work profile notification is redacted
- assertTrue(mLockscreenUserManager.needsRedaction(mWorkProfileNotif));
+ assertTrue(mLockscreenUserManager.notifNeedsRedactionInPublic(mWorkProfileNotif));
}
@Test
@@ -245,7 +250,7 @@
mLockscreenUserManager.getLockscreenSettingsObserverForTest().onChange(false);
// THEN work profile notification isn't redacted
- assertFalse(mLockscreenUserManager.needsRedaction(mWorkProfileNotif));
+ assertFalse(mLockscreenUserManager.notifNeedsRedactionInPublic(mWorkProfileNotif));
}
@Test
@@ -260,11 +265,11 @@
mLockscreenUserManager.getLockscreenSettingsObserverForTest().onChange(false);
// THEN the work profile notification doesn't need to be redacted
- assertFalse(mLockscreenUserManager.needsRedaction(mWorkProfileNotif));
+ assertFalse(mLockscreenUserManager.notifNeedsRedactionInPublic(mWorkProfileNotif));
// THEN the current user and secondary user notifications do need to be redacted
- assertTrue(mLockscreenUserManager.needsRedaction(mCurrentUserNotif));
- assertTrue(mLockscreenUserManager.needsRedaction(mSecondaryUserNotif));
+ assertTrue(mLockscreenUserManager.notifNeedsRedactionInPublic(mCurrentUserNotif));
+ assertTrue(mLockscreenUserManager.notifNeedsRedactionInPublic(mSecondaryUserNotif));
}
@Test
@@ -279,11 +284,11 @@
mLockscreenUserManager.getLockscreenSettingsObserverForTest().onChange(false);
// THEN the work profile notification needs to be redacted
- assertTrue(mLockscreenUserManager.needsRedaction(mWorkProfileNotif));
+ assertTrue(mLockscreenUserManager.notifNeedsRedactionInPublic(mWorkProfileNotif));
// THEN the current user and secondary user notifications don't need to be redacted
- assertFalse(mLockscreenUserManager.needsRedaction(mCurrentUserNotif));
- assertFalse(mLockscreenUserManager.needsRedaction(mSecondaryUserNotif));
+ assertFalse(mLockscreenUserManager.notifNeedsRedactionInPublic(mCurrentUserNotif));
+ assertFalse(mLockscreenUserManager.notifNeedsRedactionInPublic(mSecondaryUserNotif));
}
@Test
@@ -298,7 +303,7 @@
// THEN the secondary profile notification still needs to be redacted because the current
// user's setting takes precedence
- assertTrue(mLockscreenUserManager.needsRedaction(mSecondaryUserNotif));
+ assertTrue(mLockscreenUserManager.notifNeedsRedactionInPublic(mSecondaryUserNotif));
}
@Test
@@ -418,9 +423,12 @@
context,
mBroadcastDispatcher,
mDevicePolicyManager,
+ mKeyguardUpdateMonitor,
+ () -> mEntryManager,
+ () -> mOverviewProxyService,
mUserManager,
- (() -> mVisibilityProvider),
- (() -> mNotifCollection),
+ () -> mVisibilityProvider,
+ () -> mNotifCollection,
mClickNotifier,
NotificationLockscreenUserManagerTest.this.mKeyguardManager,
mStatusBarStateController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicPrivacyControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicPrivacyControllerTest.java
index 7d06abf..e43ae0d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicPrivacyControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicPrivacyControllerTest.java
@@ -124,8 +124,8 @@
}
private void allowPrivateNotificationsInPublic(boolean allow) {
- when(mLockScreenUserManager.userAllowsPrivateNotificationsInPublic(anyInt())).thenReturn(
- allow);
+ when(mLockScreenUserManager.sensitiveNotifsNeedRedactionInPublic(anyInt())).thenReturn(
+ !allow);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
index 0fff5f5..16b0376 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
@@ -294,7 +294,8 @@
verify(mPresenter).updateNotificationViews(any());
verify(mEntryListener).onEntryRemoved(
- eq(mEntry), any(), eq(false) /* removedByUser */, eq(UNDEFINED_DISMISS_REASON));
+ argThat(matchEntryOnKey()), any(),
+ eq(false) /* removedByUser */, eq(UNDEFINED_DISMISS_REASON));
verify(mRow).setRemoved();
assertNull(mEntryManager.getActiveNotificationUnfiltered(mSbn.getKey()));
@@ -319,8 +320,8 @@
mEntryManager.removeNotification("not_a_real_key", mRankingMap, UNDEFINED_DISMISS_REASON);
- verify(mEntryListener, never()).onEntryRemoved(
- eq(mEntry), any(), eq(false) /* removedByUser */, eq(UNDEFINED_DISMISS_REASON));
+ verify(mEntryListener, never()).onEntryRemoved(argThat(matchEntryOnKey()), any(),
+ eq(false) /* removedByUser */, eq(UNDEFINED_DISMISS_REASON));
}
/** Regression test for b/201097913. */
@@ -333,10 +334,10 @@
// Verify that only the listener for the NEW pipeline is notified.
// Old pipeline:
verify(mEntryListener, never()).onEntryRemoved(
- argThat(matchEntryOnSbn()), any(), anyBoolean(), anyInt());
+ argThat(matchEntryOnKey()), any(), anyBoolean(), anyInt());
// New pipeline:
verify(mNotifCollectionListener).onEntryRemoved(
- argThat(matchEntryOnSbn()), anyInt());
+ argThat(matchEntryOnKey()), anyInt());
}
@Test
@@ -457,7 +458,7 @@
// THEN the notification is retained
assertNotNull(mEntryManager.getActiveNotificationUnfiltered(mSbn.getKey()));
verify(mEntryListener, never()).onEntryRemoved(
- eq(mEntry), any(), eq(false), eq(UNDEFINED_DISMISS_REASON));
+ argThat(matchEntryOnKey()), any(), eq(false), eq(UNDEFINED_DISMISS_REASON));
}
@Test
@@ -476,7 +477,7 @@
// THEN the notification is removed
assertNull(mEntryManager.getActiveNotificationUnfiltered(mSbn.getKey()));
verify(mEntryListener).onEntryRemoved(
- eq(mEntry), any(), eq(false), eq(UNDEFINED_DISMISS_REASON));
+ argThat(matchEntryOnKey()), any(), eq(false), eq(UNDEFINED_DISMISS_REASON));
}
@Test
@@ -541,7 +542,7 @@
// GIVEN interceptor that intercepts that entry
when(mRemoveInterceptor.onNotificationRemoveRequested(
- eq(mEntry.getKey()), eq(mEntry), anyInt()))
+ eq(mEntry.getKey()), argThat(matchEntryOnKey()), anyInt()))
.thenReturn(true);
// WHEN the notification is removed
@@ -549,7 +550,7 @@
// THEN the interceptor intercepts & the entry is not removed & no listeners are called
assertNotNull(mEntryManager.getActiveNotificationUnfiltered(mSbn.getKey()));
- verify(mEntryListener, never()).onEntryRemoved(eq(mEntry),
+ verify(mEntryListener, never()).onEntryRemoved(argThat(matchEntryOnKey()),
any(NotificationVisibility.class), anyBoolean(), eq(UNDEFINED_DISMISS_REASON));
}
@@ -560,7 +561,7 @@
// GIVEN interceptor that doesn't intercept
when(mRemoveInterceptor.onNotificationRemoveRequested(
- eq(mEntry.getKey()), eq(mEntry), anyInt()))
+ eq(mEntry.getKey()), argThat(matchEntryOnKey()), anyInt()))
.thenReturn(false);
// WHEN the notification is removed
@@ -568,7 +569,7 @@
// THEN the interceptor intercepts & the entry is not removed & no listeners are called
assertNull(mEntryManager.getActiveNotificationUnfiltered(mSbn.getKey()));
- verify(mEntryListener, atLeastOnce()).onEntryRemoved(eq(mEntry),
+ verify(mEntryListener, atLeastOnce()).onEntryRemoved(argThat(matchEntryOnKey()),
any(NotificationVisibility.class), anyBoolean(), eq(UNDEFINED_DISMISS_REASON));
}
@@ -663,9 +664,8 @@
PendingIntent.FLAG_IMMUTABLE)).build();
}
- // TODO(b/201321631): Update more tests to use this function instead of eq(mEntry).
- private ArgumentMatcher<NotificationEntry> matchEntryOnSbn() {
- return e -> e.getSbn().equals(mSbn);
+ private ArgumentMatcher<NotificationEntry> matchEntryOnKey() {
+ return e -> e.getKey().equals(mEntry.getKey());
}
private static class FakeNotificationLifetimeExtender implements NotificationLifetimeExtender {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
index 7068009..958d542 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
@@ -32,6 +32,8 @@
import static com.android.systemui.statusbar.notification.collection.NotificationEntry.DismissState.NOT_DISMISSED;
import static com.android.systemui.statusbar.notification.collection.NotificationEntry.DismissState.PARENT_DISMISSED;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
@@ -47,6 +49,7 @@
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import static java.util.Collections.singletonList;
@@ -180,13 +183,14 @@
@Test
public void testGetGroupSummary() {
- assertEquals(null, mCollection.getGroupSummary("group"));
- NotifEvent summary = mNoMan.postNotif(
- buildNotif(TEST_PACKAGE, 0)
- .setGroup(mContext, "group")
- .setGroupSummary(mContext, true));
+ final NotificationEntryBuilder entryBuilder = buildNotif(TEST_PACKAGE, 0)
+ .setGroup(mContext, "group")
+ .setGroupSummary(mContext, true);
+ final String groupKey = entryBuilder.build().getSbn().getGroupKey();
+ assertEquals(null, mCollection.getGroupSummary(groupKey));
+ NotifEvent summary = mNoMan.postNotif(entryBuilder);
- final NotificationEntry entry = mCollection.getGroupSummary("group");
+ final NotificationEntry entry = mCollection.getGroupSummary(groupKey);
assertEquals(summary.key, entry.getKey());
assertEquals(summary.sbn, entry.getSbn());
assertEquals(summary.ranking, entry.getRanking());
@@ -194,9 +198,9 @@
@Test
public void testIsOnlyChildInGroup() {
- NotifEvent notif1 = mNoMan.postNotif(
- buildNotif(TEST_PACKAGE, 1)
- .setGroup(mContext, "group"));
+ final NotificationEntryBuilder entryBuilder = buildNotif(TEST_PACKAGE, 1)
+ .setGroup(mContext, "group");
+ NotifEvent notif1 = mNoMan.postNotif(entryBuilder);
final NotificationEntry entry = mCollection.getEntry(notif1.key);
assertTrue(mCollection.isOnlyChildInGroup(entry));
@@ -1488,6 +1492,55 @@
}
@Test
+ public void testRegisterFutureDismissal() throws RemoteException {
+ // GIVEN a pipeline with one notification
+ NotifEvent notifEvent = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47, "myTag"));
+ NotificationEntry entry = requireNonNull(mCollection.getEntry(notifEvent.key));
+ clearInvocations(mCollectionListener);
+
+ // WHEN registering a future dismissal, nothing happens right away
+ final Runnable onDismiss = mCollection.registerFutureDismissal(entry, REASON_CLICK,
+ NotifCollectionTest::defaultStats);
+ verifyNoMoreInteractions(mCollectionListener);
+
+ // WHEN finally dismissing
+ onDismiss.run();
+ verify(mStatusBarService).onNotificationClear(any(), anyInt(), eq(notifEvent.key),
+ anyInt(), anyInt(), any());
+ verifyNoMoreInteractions(mStatusBarService);
+ verifyNoMoreInteractions(mCollectionListener);
+ }
+
+ @Test
+ public void testRegisterFutureDismissalWithRetractionAndRepost() {
+ // GIVEN a pipeline with one notification
+ NotifEvent notifEvent = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47, "myTag"));
+ NotificationEntry entry = requireNonNull(mCollection.getEntry(notifEvent.key));
+ clearInvocations(mCollectionListener);
+
+ // WHEN registering a future dismissal, nothing happens right away
+ final Runnable onDismiss = mCollection.registerFutureDismissal(entry, REASON_CLICK,
+ NotifCollectionTest::defaultStats);
+ verifyNoMoreInteractions(mCollectionListener);
+
+ // WHEN retracting the notification, and then reposting
+ mNoMan.retractNotif(notifEvent.sbn, REASON_CLICK);
+ mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47, "myTag"));
+ clearInvocations(mCollectionListener);
+
+ // KNOWING that the entry in the collection is different now
+ assertThat(mCollection.getEntry(notifEvent.key)).isNotSameInstanceAs(entry);
+
+ // WHEN finally dismissing
+ onDismiss.run();
+
+ // VERIFY that nothing happens; the notification should not be removed
+ verifyNoMoreInteractions(mCollectionListener);
+ assertThat(mCollection.getEntry(notifEvent.key)).isNotNull();
+ verifyNoMoreInteractions(mStatusBarService);
+ }
+
+ @Test
public void testCannotDismissOngoingNotificationChildren() {
// GIVEN an ongoing notification
final NotificationEntry container = new NotificationEntryBuilder()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
index 9ea1813..9546058 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
@@ -53,6 +53,7 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.statusbar.NotificationInteractionTracker;
+import com.android.systemui.statusbar.RankingBuilder;
import com.android.systemui.statusbar.notification.NotifPipelineFlags;
import com.android.systemui.statusbar.notification.collection.ShadeListBuilder.OnRenderListListener;
import com.android.systemui.statusbar.notification.collection.listbuilder.NotifSection;
@@ -1528,6 +1529,34 @@
}
@Test
+ public void testContiguousSections() {
+ mListBuilder.setSectioners(List.of(
+ new PackageSectioner("pkg", 1),
+ new PackageSectioner("pkg", 1),
+ new PackageSectioner("pkg", 3),
+ new PackageSectioner("pkg", 2)
+ ));
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void testNonContiguousSections() {
+ mListBuilder.setSectioners(List.of(
+ new PackageSectioner("pkg", 1),
+ new PackageSectioner("pkg", 1),
+ new PackageSectioner("pkg", 3),
+ new PackageSectioner("pkg", 1)
+ ));
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void testBucketZeroNotAllowed() {
+ mListBuilder.setSectioners(List.of(
+ new PackageSectioner("pkg", 0),
+ new PackageSectioner("pkg", 1)
+ ));
+ }
+
+ @Test
public void testStabilizeGroupsDelayedSummaryRendersAllNotifsTopLevel() {
// GIVEN group children posted without a summary
addGroupChild(0, PACKAGE_1, GROUP_1);
@@ -1769,6 +1798,7 @@
@Test
public void testStableMultipleSectionOrdering() {
+ // WHEN the list is originally built with reordering disabled
mListBuilder.setSectioners(asList(
new PackageSectioner(PACKAGE_1), new PackageSectioner(PACKAGE_2)));
mStabilityManager.setAllowEntryReordering(false);
@@ -1779,12 +1809,94 @@
addNotif(3, PACKAGE_1).setRank(3);
dispatchBuild();
+ // VERIFY the order and that entry reordering has not been suppressed
verifyBuiltList(
notif(0),
notif(1),
notif(3),
notif(2)
);
+ verify(mStabilityManager, never()).onEntryReorderSuppressed();
+
+ // WHEN the ranks change
+ setNewRank(notif(0).entry, 4);
+ dispatchBuild();
+
+ // VERIFY the order does not change that entry reordering has been suppressed
+ verifyBuiltList(
+ notif(0),
+ notif(1),
+ notif(3),
+ notif(2)
+ );
+ verify(mStabilityManager).onEntryReorderSuppressed();
+
+ // WHEN reordering is now allowed again
+ mStabilityManager.setAllowEntryReordering(true);
+ dispatchBuild();
+
+ // VERIFY that list order changes
+ verifyBuiltList(
+ notif(1),
+ notif(3),
+ notif(0),
+ notif(2)
+ );
+ }
+
+ @Test
+ public void testStableChildOrdering() {
+ // WHEN the list is originally built with reordering disabled
+ mStabilityManager.setAllowEntryReordering(false);
+ addGroupSummary(0, PACKAGE_1, GROUP_1).setRank(0);
+ addGroupChild(1, PACKAGE_1, GROUP_1).setRank(1);
+ addGroupChild(2, PACKAGE_1, GROUP_1).setRank(2);
+ addGroupChild(3, PACKAGE_1, GROUP_1).setRank(3);
+ dispatchBuild();
+
+ // VERIFY the order and that entry reordering has not been suppressed
+ verifyBuiltList(
+ group(
+ summary(0),
+ child(1),
+ child(2),
+ child(3)
+ )
+ );
+ verify(mStabilityManager, never()).onEntryReorderSuppressed();
+
+ // WHEN the ranks change
+ setNewRank(notif(2).entry, 5);
+ dispatchBuild();
+
+ // VERIFY the order does not change that entry reordering has been suppressed
+ verifyBuiltList(
+ group(
+ summary(0),
+ child(1),
+ child(2),
+ child(3)
+ )
+ );
+ verify(mStabilityManager).onEntryReorderSuppressed();
+
+ // WHEN reordering is now allowed again
+ mStabilityManager.setAllowEntryReordering(true);
+ dispatchBuild();
+
+ // VERIFY that list order changes
+ verifyBuiltList(
+ group(
+ summary(0),
+ child(1),
+ child(3),
+ child(2)
+ )
+ );
+ }
+
+ private static void setNewRank(NotificationEntry entry, int rank) {
+ entry.setRanking(new RankingBuilder(entry.getRanking()).setRank(rank).build());
}
@Test
@@ -2189,7 +2301,11 @@
}
PackageSectioner(String pkg) {
- super("PackageSection_" + pkg, 0);
+ this(pkg, 0);
+ }
+
+ PackageSectioner(String pkg, int bucket) {
+ super("PackageSection_" + pkg, bucket);
mPackages = List.of(pkg);
mComparator = null;
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ActivityLaunchAnimCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ActivityLaunchAnimCoordinatorTest.kt
deleted file mode 100644
index c6c043a..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ActivityLaunchAnimCoordinatorTest.kt
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.notification.collection.coordinator
-
-import androidx.test.filters.SmallTest
-import com.android.systemui.SysuiTestCase
-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
-import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender
-import com.android.systemui.statusbar.phone.NotifActivityLaunchEvents
-import com.android.systemui.util.mockito.mock
-import com.android.systemui.util.mockito.withArgCaptor
-import dagger.BindsInstance
-import dagger.Component
-import org.junit.Assert.assertFalse
-import org.junit.Assert.assertTrue
-import org.junit.Test
-import org.mockito.Mockito.never
-import org.mockito.Mockito.verify
-import org.mockito.Mockito.`when` as whenever
-
-@SmallTest
-class ActivityLaunchAnimCoordinatorTest : SysuiTestCase() {
-
- val activityLaunchEvents: NotifActivityLaunchEvents = mock()
- val pipeline: NotifPipeline = mock()
-
- val coordinator: ActivityLaunchAnimCoordinator =
- DaggerTestActivityStarterCoordinatorComponent
- .factory()
- .create(activityLaunchEvents)
- .coordinator
-
- @Test
- fun testNoLifetimeExtensionIfNoAssociatedActivityLaunch() {
- coordinator.attach(pipeline)
- val lifetimeExtender = withArgCaptor<NotifLifetimeExtender> {
- verify(pipeline).addNotificationLifetimeExtender(capture())
- }
- val fakeEntry = mock<NotificationEntry>().also {
- whenever(it.key).thenReturn("0")
- }
- assertFalse(lifetimeExtender.maybeExtendLifetime(fakeEntry, 0))
- }
-
- @Test
- fun testNoLifetimeExtensionIfAssociatedActivityLaunchAlreadyEnded() {
- coordinator.attach(pipeline)
- val lifetimeExtender = withArgCaptor<NotifLifetimeExtender> {
- verify(pipeline).addNotificationLifetimeExtender(capture())
- }
- val eventListener = withArgCaptor<NotifActivityLaunchEvents.Listener> {
- verify(activityLaunchEvents).registerListener(capture())
- }
- val fakeEntry = mock<NotificationEntry>().also {
- whenever(it.key).thenReturn("0")
- }
- eventListener.onStartLaunchNotifActivity(fakeEntry)
- eventListener.onFinishLaunchNotifActivity(fakeEntry)
- assertFalse(lifetimeExtender.maybeExtendLifetime(fakeEntry, 0))
- }
-
- @Test
- fun testLifetimeExtensionWhileActivityLaunchInProgress() {
- coordinator.attach(pipeline)
- val lifetimeExtender = withArgCaptor<NotifLifetimeExtender> {
- verify(pipeline).addNotificationLifetimeExtender(capture())
- }
- val eventListener = withArgCaptor<NotifActivityLaunchEvents.Listener> {
- verify(activityLaunchEvents).registerListener(capture())
- }
- val onEndLifetimeExtensionCallback =
- mock<NotifLifetimeExtender.OnEndLifetimeExtensionCallback>()
- lifetimeExtender.setCallback(onEndLifetimeExtensionCallback)
-
- val fakeEntry = mock<NotificationEntry>().also {
- whenever(it.key).thenReturn("0")
- }
- eventListener.onStartLaunchNotifActivity(fakeEntry)
- assertTrue(lifetimeExtender.maybeExtendLifetime(fakeEntry, 0))
-
- eventListener.onFinishLaunchNotifActivity(fakeEntry)
- verify(onEndLifetimeExtensionCallback).onEndLifetimeExtension(lifetimeExtender, fakeEntry)
- }
-
- @Test
- fun testCancelLifetimeExtensionDoesNotInvokeCallback() {
- coordinator.attach(pipeline)
- val lifetimeExtender = withArgCaptor<NotifLifetimeExtender> {
- verify(pipeline).addNotificationLifetimeExtender(capture())
- }
- val eventListener = withArgCaptor<NotifActivityLaunchEvents.Listener> {
- verify(activityLaunchEvents).registerListener(capture())
- }
- val onEndLifetimeExtensionCallback =
- mock<NotifLifetimeExtender.OnEndLifetimeExtensionCallback>()
- lifetimeExtender.setCallback(onEndLifetimeExtensionCallback)
-
- val fakeEntry = mock<NotificationEntry>().also {
- whenever(it.key).thenReturn("0")
- }
- eventListener.onStartLaunchNotifActivity(fakeEntry)
- assertTrue(lifetimeExtender.maybeExtendLifetime(fakeEntry, 0))
-
- lifetimeExtender.cancelLifetimeExtension(fakeEntry)
- eventListener.onFinishLaunchNotifActivity(fakeEntry)
- verify(onEndLifetimeExtensionCallback, never())
- .onEndLifetimeExtension(lifetimeExtender, fakeEntry)
- }
-}
-
-@CoordinatorScope
-@Component(modules = [ActivityLaunchAnimCoordinatorModule::class])
-interface TestActivityStarterCoordinatorComponent {
- val coordinator: ActivityLaunchAnimCoordinator
-
- @Component.Factory
- interface Factory {
- fun create(
- @BindsInstance activityLaunchEvents: NotifActivityLaunchEvents
- ): TestActivityStarterCoordinatorComponent
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java
index fc74f39..8b115fe 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java
@@ -446,6 +446,7 @@
mInflateCallbacks.put(entry, callback);
}
+
@Override
public void rebindViews(@NonNull NotificationEntry entry, @NonNull Params params,
@NonNull InflationCallback callback) {
@@ -462,6 +463,10 @@
public void invokeInflateCallbackForEntry(NotificationEntry entry) {
getInflateCallback(entry).onInflationFinished(entry, entry.getRowController());
}
+
+ @Override
+ public void releaseViews(@NonNull NotificationEntry entry) {
+ }
}
private void fireAddEvents(List<? extends ListEntry> entries) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java
index ff08bc3..d7a88d8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java
@@ -23,7 +23,6 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -33,14 +32,12 @@
import android.app.NotificationManager;
import android.testing.AndroidTestingRunner;
-import androidx.annotation.Nullable;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.RankingBuilder;
import com.android.systemui.statusbar.SbnBuilder;
-import com.android.systemui.statusbar.notification.collection.ListEntry;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
@@ -49,7 +46,6 @@
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
import com.android.systemui.statusbar.notification.collection.provider.SectionStyleProvider;
import com.android.systemui.statusbar.notification.collection.render.NodeController;
-import com.android.systemui.statusbar.notification.collection.render.SectionHeaderController;
import org.junit.Before;
import org.junit.Test;
@@ -72,7 +68,6 @@
@Mock private NotifPipeline mNotifPipeline;
@Mock private NodeController mAlertingHeaderController;
@Mock private NodeController mSilentNodeController;
- @Mock private SectionHeaderController mSilentHeaderController;
@Captor private ArgumentCaptor<NotifFilter> mNotifFilterCaptor;
@@ -94,7 +89,6 @@
mHighPriorityProvider,
mSectionStyleProvider,
mAlertingHeaderController,
- mSilentHeaderController,
mSilentNodeController);
mEntry = spy(new NotificationEntryBuilder().build());
mEntry.setRanking(getRankingForUnfilteredNotif().build());
@@ -112,25 +106,6 @@
}
@Test
- public void testSilentHeaderClearableChildrenUpdate() {
- ListEntry listEntry = new ListEntry(mEntry.getKey(), 0L) {
- @Nullable
- @Override
- public NotificationEntry getRepresentativeEntry() {
- return mEntry;
- }
- };
- setRankingAmbient(false);
- setSbnClearable(true);
- mSilentSectioner.onEntriesUpdated(Arrays.asList(listEntry));
- verify(mSilentHeaderController).setClearSectionEnabled(eq(true));
-
- setSbnClearable(false);
- mSilentSectioner.onEntriesUpdated(Arrays.asList(listEntry));
- verify(mSilentHeaderController).setClearSectionEnabled(eq(false));
- }
-
- @Test
public void testUnfilteredState() {
// GIVEN no suppressed visual effects + app not suspended
mEntry.setRanking(getRankingForUnfilteredNotif().build());
@@ -225,46 +200,6 @@
assertInSection(mEntry, mSilentSectioner);
}
- @Test
- public void testClearableSilentSection() {
- when(mHighPriorityProvider.isHighPriority(mEntry)).thenReturn(false);
- setSbnClearable(true);
- setRankingAmbient(false);
- mSilentSectioner.onEntriesUpdated(Arrays.asList(mEntry));
- verify(mSilentHeaderController).setClearSectionEnabled(eq(true));
- }
-
- @Test
- public void testClearableMinimizedSection() {
- when(mHighPriorityProvider.isHighPriority(mEntry)).thenReturn(false);
- setSbnClearable(true);
- setRankingAmbient(true);
- mMinimizedSectioner.onEntriesUpdated(Arrays.asList(mEntry));
- verify(mSilentHeaderController).setClearSectionEnabled(eq(true));
- }
-
- @Test
- public void testNotClearableSilentSection() {
- setSbnClearable(false);
- when(mHighPriorityProvider.isHighPriority(mEntry)).thenReturn(false);
- setRankingAmbient(false);
- mSilentSectioner.onEntriesUpdated(Arrays.asList(mEntry));
- mMinimizedSectioner.onEntriesUpdated(Arrays.asList(mEntry));
- mAlertingSectioner.onEntriesUpdated(Arrays.asList(mEntry));
- verify(mSilentHeaderController, times(2)).setClearSectionEnabled(eq(false));
- }
-
- @Test
- public void testNotClearableMinimizedSection() {
- setSbnClearable(false);
- when(mHighPriorityProvider.isHighPriority(mEntry)).thenReturn(false);
- setRankingAmbient(true);
- mSilentSectioner.onEntriesUpdated(Arrays.asList(mEntry));
- mMinimizedSectioner.onEntriesUpdated(Arrays.asList(mEntry));
- mAlertingSectioner.onEntriesUpdated(Arrays.asList(mEntry));
- verify(mSilentHeaderController, times(2)).setClearSectionEnabled(eq(false));
- }
-
private void assertInSection(NotificationEntry entry, NotifSectioner section) {
for (NotifSectioner current: mSections) {
if (current == section) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinatorTest.kt
deleted file mode 100644
index a2d8e3d..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinatorTest.kt
+++ /dev/null
@@ -1,268 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.notification.collection.coordinator
-
-import android.os.UserHandle
-import android.service.notification.StatusBarNotification
-import androidx.test.filters.SmallTest
-import com.android.keyguard.KeyguardUpdateMonitor
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.plugins.statusbar.StatusBarStateController
-import com.android.systemui.statusbar.NotificationLockscreenUserManager
-import com.android.systemui.statusbar.StatusBarState
-import com.android.systemui.statusbar.notification.DynamicPrivacyController
-import com.android.systemui.statusbar.notification.collection.ListEntry
-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
-import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeRenderListListener
-import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Invalidator
-import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Pluggable
-import com.android.systemui.statusbar.policy.KeyguardStateController
-import com.android.systemui.util.mockito.any
-import com.android.systemui.util.mockito.mock
-import com.android.systemui.util.mockito.withArgCaptor
-import dagger.BindsInstance
-import dagger.Component
-import org.junit.Test
-import org.mockito.Mockito.never
-import org.mockito.Mockito.verify
-import org.mockito.Mockito.`when` as whenever
-
-@SmallTest
-class SensitiveContentCoordinatorTest : SysuiTestCase() {
-
- val dynamicPrivacyController: DynamicPrivacyController = mock()
- val lockscreenUserManager: NotificationLockscreenUserManager = mock()
- val pipeline: NotifPipeline = mock()
- val keyguardUpdateMonitor: KeyguardUpdateMonitor = mock()
- val statusBarStateController: StatusBarStateController = mock()
- val keyguardStateController: KeyguardStateController = mock()
-
- val coordinator: SensitiveContentCoordinator =
- DaggerTestSensitiveContentCoordinatorComponent
- .factory()
- .create(
- dynamicPrivacyController,
- lockscreenUserManager,
- keyguardUpdateMonitor,
- statusBarStateController,
- keyguardStateController)
- .coordinator
-
- @Test
- fun onDynamicPrivacyChanged_invokeInvalidationListener() {
- coordinator.attach(pipeline)
- val invalidator = withArgCaptor<Invalidator> {
- verify(pipeline).addPreRenderInvalidator(capture())
- }
- val dynamicPrivacyListener = withArgCaptor<DynamicPrivacyController.Listener> {
- verify(dynamicPrivacyController).addListener(capture())
- }
-
- val invalidationListener = mock<Pluggable.PluggableListener<Invalidator>>()
- invalidator.setInvalidationListener(invalidationListener)
-
- dynamicPrivacyListener.onDynamicPrivacyChanged()
-
- verify(invalidationListener).onPluggableInvalidated(invalidator)
- }
-
- @Test
- fun onBeforeRenderList_deviceUnlocked_notifDoesNotNeedRedaction() {
- coordinator.attach(pipeline)
- val onBeforeRenderListListener = withArgCaptor<OnBeforeRenderListListener> {
- verify(pipeline).addOnBeforeRenderListListener(capture())
- }
-
- whenever(lockscreenUserManager.currentUserId).thenReturn(1)
- whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(false)
- whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(true)
- whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(false)
- val entry = fakeNotification(1, false)
-
- onBeforeRenderListListener.onBeforeRenderList(listOf(entry))
-
- verify(entry.representativeEntry!!).setSensitive(false, false)
- }
-
- @Test
- fun onBeforeRenderList_deviceUnlocked_notifWouldNeedRedaction() {
- coordinator.attach(pipeline)
- val onBeforeRenderListListener = withArgCaptor<OnBeforeRenderListListener> {
- verify(pipeline).addOnBeforeRenderListListener(capture())
- }
-
- whenever(lockscreenUserManager.currentUserId).thenReturn(1)
- whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(false)
- whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(true)
- whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(false)
- val entry = fakeNotification(1, true)
-
- onBeforeRenderListListener.onBeforeRenderList(listOf(entry))
-
- verify(entry.representativeEntry!!).setSensitive(false, false)
- }
-
- @Test
- fun onBeforeRenderList_deviceLocked_userAllowsPublicNotifs() {
- coordinator.attach(pipeline)
- val onBeforeRenderListListener = withArgCaptor<OnBeforeRenderListListener> {
- verify(pipeline).addOnBeforeRenderListListener(capture())
- }
-
- whenever(lockscreenUserManager.currentUserId).thenReturn(1)
- whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true)
- whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(true)
- whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(false)
- val entry = fakeNotification(1, false)
-
- onBeforeRenderListListener.onBeforeRenderList(listOf(entry))
-
- verify(entry.representativeEntry!!).setSensitive(false, false)
- }
-
- @Test
- fun onBeforeRenderList_deviceLocked_userDisallowsPublicNotifs_notifDoesNotNeedRedaction() {
- coordinator.attach(pipeline)
- val onBeforeRenderListListener = withArgCaptor<OnBeforeRenderListListener> {
- verify(pipeline).addOnBeforeRenderListListener(capture())
- }
-
- whenever(lockscreenUserManager.currentUserId).thenReturn(1)
- whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true)
- whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(false)
- whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(false)
- val entry = fakeNotification(1, false)
-
- onBeforeRenderListListener.onBeforeRenderList(listOf(entry))
-
- verify(entry.representativeEntry!!).setSensitive(false, true)
- }
-
- @Test
- fun onBeforeRenderList_deviceLocked_notifNeedsRedaction() {
- coordinator.attach(pipeline)
- val onBeforeRenderListListener = withArgCaptor<OnBeforeRenderListListener> {
- verify(pipeline).addOnBeforeRenderListListener(capture())
- }
-
- whenever(lockscreenUserManager.currentUserId).thenReturn(1)
- whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true)
- whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(false)
- whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(false)
- val entry = fakeNotification(1, true)
-
- onBeforeRenderListListener.onBeforeRenderList(listOf(entry))
-
- verify(entry.representativeEntry!!).setSensitive(true, true)
- }
-
- @Test
- fun onBeforeRenderList_deviceDynamicallyUnlocked_notifNeedsRedaction() {
- coordinator.attach(pipeline)
- val onBeforeRenderListListener = withArgCaptor<OnBeforeRenderListListener> {
- verify(pipeline).addOnBeforeRenderListListener(capture())
- }
-
- whenever(lockscreenUserManager.currentUserId).thenReturn(1)
- whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true)
- whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(false)
- whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(true)
- val entry = fakeNotification(1, true)
-
- onBeforeRenderListListener.onBeforeRenderList(listOf(entry))
-
- verify(entry.representativeEntry!!).setSensitive(false, true)
- }
-
- @Test
- fun onBeforeRenderList_deviceDynamicallyUnlocked_notifUserNeedsWorkChallenge() {
- coordinator.attach(pipeline)
- val onBeforeRenderListListener = withArgCaptor<OnBeforeRenderListListener> {
- verify(pipeline).addOnBeforeRenderListListener(capture())
- }
-
- whenever(lockscreenUserManager.currentUserId).thenReturn(1)
- whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true)
- whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(false)
- whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(true)
- whenever(lockscreenUserManager.needsSeparateWorkChallenge(2)).thenReturn(true)
-
- val entry = fakeNotification(2, true)
-
- onBeforeRenderListListener.onBeforeRenderList(listOf(entry))
-
- verify(entry.representativeEntry!!).setSensitive(true, true)
- }
-
- @Test
- fun onBeforeRenderList_deviceDynamicallyUnlocked_deviceBiometricBypassingLockScreen() {
- coordinator.attach(pipeline)
- val onBeforeRenderListListener = withArgCaptor<OnBeforeRenderListListener> {
- verify(pipeline).addOnBeforeRenderListListener(capture())
- }
-
- whenever(lockscreenUserManager.currentUserId).thenReturn(1)
- whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true)
- whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(false)
- whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(true)
- whenever(statusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD)
- whenever(keyguardUpdateMonitor.getUserUnlockedWithBiometricAndIsBypassing(any()))
- .thenReturn(true)
-
- val entry = fakeNotification(2, true)
-
- onBeforeRenderListListener.onBeforeRenderList(listOf(entry))
-
- verify(entry.representativeEntry!!, never()).setSensitive(any(), any())
- }
-
- private fun fakeNotification(notifUserId: Int, needsRedaction: Boolean): ListEntry {
- val mockUserHandle = mock<UserHandle>().apply {
- whenever(identifier).thenReturn(notifUserId)
- }
- val mockSbn: StatusBarNotification = mock<StatusBarNotification>().apply {
- whenever(user).thenReturn(mockUserHandle)
- }
- val mockEntry = mock<NotificationEntry>().apply {
- whenever(sbn).thenReturn(mockSbn)
- }
- whenever(lockscreenUserManager.needsRedaction(mockEntry)).thenReturn(needsRedaction)
- whenever(mockEntry.rowExists()).thenReturn(true)
- return object : ListEntry("key", 0) {
- override fun getRepresentativeEntry(): NotificationEntry = mockEntry
- }
- }
-}
-
-@CoordinatorScope
-@Component(modules = [SensitiveContentCoordinatorModule::class])
-interface TestSensitiveContentCoordinatorComponent {
- val coordinator: SensitiveContentCoordinator
-
- @Component.Factory
- interface Factory {
- fun create(
- @BindsInstance dynamicPrivacyController: DynamicPrivacyController,
- @BindsInstance lockscreenUserManager: NotificationLockscreenUserManager,
- @BindsInstance keyguardUpdateMonitor: KeyguardUpdateMonitor,
- @BindsInstance statusBarStateController: StatusBarStateController,
- @BindsInstance keyguardStateController: KeyguardStateController
- ): TestSensitiveContentCoordinatorComponent
- }
-}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinatorTest.kt
index 70266e4..cf2fc7c3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinatorTest.kt
@@ -15,6 +15,7 @@
*/
package com.android.systemui.statusbar.notification.collection.coordinator
+import android.os.UserHandle
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
import androidx.test.filters.SmallTest
@@ -43,6 +44,11 @@
@RunWith(AndroidTestingRunner::class)
@RunWithLooper
class StackCoordinatorTest : SysuiTestCase() {
+
+ companion object {
+ const val NOTIF_USER_ID = 0
+ }
+
private lateinit var coordinator: StackCoordinator
private lateinit var afterRenderListListener: OnAfterRenderListListener
@@ -61,7 +67,10 @@
afterRenderListListener = withArgCaptor {
verify(pipeline).addOnAfterRenderListListener(capture())
}
- entry = NotificationEntryBuilder().setSection(section).build()
+ entry = NotificationEntryBuilder()
+ .setSection(section)
+ .setUser(UserHandle.of(NOTIF_USER_ID))
+ .build()
}
@Test
@@ -74,13 +83,31 @@
fun testSetNotificationStats_clearableAlerting() {
whenever(section.bucket).thenReturn(BUCKET_ALERTING)
afterRenderListListener.onAfterRenderList(listOf(entry), stackController)
- verify(stackController).setNotifStats(NotifStats(1, false, true, false, false))
+ verify(stackController)
+ .setNotifStats(
+ NotifStats(
+ 1,
+ false,
+ true,
+ false,
+ false,
+ setOf(NOTIF_USER_ID),
+ emptySet()))
}
@Test
fun testSetNotificationStats_clearableSilent() {
whenever(section.bucket).thenReturn(BUCKET_SILENT)
afterRenderListListener.onAfterRenderList(listOf(entry), stackController)
- verify(stackController).setNotifStats(NotifStats(1, false, false, false, true))
+ verify(stackController)
+ .setNotifStats(
+ NotifStats(
+ 1,
+ false,
+ false,
+ false,
+ true,
+ emptySet(),
+ setOf(NOTIF_USER_ID)))
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/IconManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/IconManagerTest.kt
index b63e66f..c7f7ec2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/IconManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/IconManagerTest.kt
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-package com.android.systemui.statusbar.notification.icon;
+package com.android.systemui.statusbar.notification.icon
-import android.app.ActivityManager;
-import android.app.Notification;
+import android.app.ActivityManager
+import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager.IMPORTANCE_DEFAULT
import android.app.Person
@@ -27,11 +27,12 @@
import android.graphics.drawable.Icon
import android.os.SystemClock
import android.os.UserHandle
-import android.testing.AndroidTestingRunner;
+import android.testing.AndroidTestingRunner
import androidx.test.InstrumentationRegistry
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.controls.controller.AuxiliaryPersistenceWrapperTest.Companion.any
+import com.android.systemui.statusbar.NotificationLockscreenUserManager
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
@@ -40,7 +41,7 @@
import org.junit.Before
import org.junit.Test
-import org.junit.runner.RunWith;
+import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito.`when`
import org.mockito.Mockito.anyInt
@@ -48,15 +49,14 @@
@SmallTest
@RunWith(AndroidTestingRunner::class)
-class IconManagerTest: SysuiTestCase() {
+class IconManagerTest : SysuiTestCase() {
companion object {
- private const val TEST_PACKAGE_NAME = "test";
- private const val TEST_UID = 0;
+ private const val TEST_PACKAGE_NAME = "test"
+ private const val TEST_UID = 0
}
-
private var id = 0
- private val context = InstrumentationRegistry.getTargetContext();
+ private val context = InstrumentationRegistry.getTargetContext()
@Mock private lateinit var shortcut: ShortcutInfo
@Mock private lateinit var shortcutIc: Icon
@Mock private lateinit var messageIc: Icon
@@ -65,6 +65,7 @@
@Mock private lateinit var drawable: Drawable
@Mock private lateinit var row: ExpandableNotificationRow
+ @Mock private lateinit var notifLockscreenUserManager: NotificationLockscreenUserManager
@Mock private lateinit var notifCollection: CommonNotifCollection
@Mock private lateinit var launcherApps: LauncherApps
@@ -83,13 +84,16 @@
`when`(shortcut.icon).thenReturn(shortcutIc)
`when`(launcherApps.getShortcutIcon(shortcut)).thenReturn(shortcutIc)
+ `when`(notifLockscreenUserManager.sensitiveNotifsNeedRedactionInPublic(TEST_UID))
+ .thenReturn(true)
- iconManager = IconManager(notifCollection, launcherApps, iconBuilder)
+ iconManager =
+ IconManager(notifCollection, launcherApps, iconBuilder, notifLockscreenUserManager)
}
@Test
fun testCreateIcons_importantConversation_shortcutIcon() {
- val entry = notificationEntry(true, true, true)
+ val entry = notificationEntry()
entry?.channel?.isImportantConversation = true
entry?.let {
iconManager.createIcons(it)
@@ -99,7 +103,7 @@
@Test
fun testCreateIcons_importantConversation_messageIcon() {
- val entry = notificationEntry(false, true, true)
+ val entry = notificationEntry(hasShortcut = false)
entry?.channel?.isImportantConversation = true
entry?.let {
iconManager.createIcons(it)
@@ -109,7 +113,7 @@
@Test
fun testCreateIcons_importantConversation_largeIcon() {
- val entry = notificationEntry(false, false, true)
+ val entry = notificationEntry(hasShortcut = false, hasMessage = false)
entry?.channel?.isImportantConversation = true
entry?.let {
iconManager.createIcons(it)
@@ -119,7 +123,7 @@
@Test
fun testCreateIcons_importantConversation_smallIcon() {
- val entry = notificationEntry(false, false, false)
+ val entry = notificationEntry(hasShortcut = false, hasMessage = false, hasLargeIcon = false)
entry?.channel?.isImportantConversation = true
entry?.let {
iconManager.createIcons(it)
@@ -129,7 +133,7 @@
@Test
fun testCreateIcons_notImportantConversation() {
- val entry = notificationEntry(true, true, true)
+ val entry = notificationEntry()
entry?.let {
iconManager.createIcons(it)
}
@@ -138,8 +142,10 @@
@Test
fun testCreateIcons_sensitiveImportantConversation() {
- val entry = notificationEntry(true, false, false)
- entry?.setSensitive(true, true);
+ val entry = notificationEntry(
+ hasMessage = false,
+ hasLargeIcon = false,
+ hasSensitiveContent = true)
entry?.channel?.isImportantConversation = true
entry?.let {
iconManager.createIcons(it)
@@ -151,14 +157,17 @@
@Test
fun testUpdateIcons_sensitivityChange() {
- val entry = notificationEntry(true, false, false)
+ val entry = notificationEntry(
+ hasMessage = false,
+ hasLargeIcon = false,
+ hasSensitiveContent = true)
entry?.channel?.isImportantConversation = true
- entry?.setSensitive(true, true);
entry?.let {
iconManager.createIcons(it)
}
assertEquals(entry?.icons?.aodIcon?.sourceIcon, smallIc)
- entry?.setSensitive(false, false);
+ `when`(notifLockscreenUserManager.sensitiveNotifsNeedRedactionInPublic(TEST_UID))
+ .thenReturn(false)
entry?.let {
iconManager.updateIcons(it)
}
@@ -166,14 +175,19 @@
}
private fun notificationEntry(
- hasShortcut: Boolean,
- hasMessage: Boolean,
- hasLargeIcon: Boolean
+ hasShortcut: Boolean = true,
+ hasMessage: Boolean = true,
+ hasLargeIcon: Boolean = true,
+ hasSensitiveContent: Boolean = false
): NotificationEntry? {
val n = Notification.Builder(mContext, "id")
.setSmallIcon(smallIc)
.setContentTitle("Title")
.setContentText("Text")
+ .setVisibility(
+ if (hasSensitiveContent)
+ Notification.VISIBILITY_PRIVATE
+ else Notification.VISIBILITY_PUBLIC)
if (hasMessage) {
n.style = Notification.MessagingStyle("")
@@ -203,7 +217,6 @@
val entry = builder.build()
entry.row = row
- entry.setSensitive(false, true);
return entry
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
index 0f2e9bc..f5a0e2d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
@@ -91,7 +91,7 @@
@Test
public void testGroupSummaryNotShowingIconWhenPublic() {
- mGroupRow.setSensitive(true, true);
+ mGroupRow.setSensitive(true);
mGroupRow.setHideSensitiveForIntrinsicHeight(true);
assertTrue(mGroupRow.isSummaryWithChildren());
assertFalse(mGroupRow.isShowingIcon());
@@ -99,7 +99,7 @@
@Test
public void testNotificationHeaderVisibleWhenAnimating() {
- mGroupRow.setSensitive(true, true);
+ mGroupRow.setSensitive(true);
mGroupRow.setHideSensitive(true, false, 0, 0);
mGroupRow.setHideSensitive(false, true, 0, 0);
assertEquals(View.VISIBLE, mGroupRow.getChildrenContainer().getVisibleWrapper()
@@ -130,7 +130,7 @@
public void testIconColorShouldBeUpdatedWhenSensitive() throws Exception {
ExpandableNotificationRow row = spy(mNotificationTestHelper.createRow(
FLAG_CONTENT_VIEW_ALL));
- row.setSensitive(true, true);
+ row.setSensitive(true);
row.setHideSensitive(true, false, 0, 0);
verify(row).updateShelfIconColor();
}
@@ -214,7 +214,7 @@
@Test
public void testFeedback_noHeader() {
// public notification is custom layout - no header
- mGroupRow.setSensitive(true, true);
+ mGroupRow.setSensitive(true);
mGroupRow.setOnFeedbackClickListener(null);
mGroupRow.setFeedbackIcon(null);
}
@@ -322,11 +322,22 @@
ExpandableNotificationRow row =
mNotificationTestHelper.createRow(mNotificationTestHelper.createNotification());
row.getEntry().getChannel().setImportanceLockedByCriticalDeviceFunction(true);
+ row.getEntry().getChannel().setBlockable(false);
assertTrue(row.getIsNonblockable());
}
@Test
+ public void testGetIsNonblockable_criticalDeviceFunction_butBlockable() throws Exception {
+ ExpandableNotificationRow row =
+ mNotificationTestHelper.createRow(mNotificationTestHelper.createNotification());
+ row.getEntry().getChannel().setImportanceLockedByCriticalDeviceFunction(true);
+ row.getEntry().getChannel().setBlockable(true);
+
+ assertFalse(row.getIsNonblockable());
+ }
+
+ @Test
public void testCanDismissNoClear() throws Exception {
ExpandableNotificationRow row =
mNotificationTestHelper.createRow(mNotificationTestHelper.createNotification());
@@ -335,7 +346,7 @@
.build();
row.performDismiss(false);
verify(mNotificationTestHelper.mOnUserInteractionCallback)
- .onDismiss(any(), anyInt(), any());
+ .registerFutureDismissal(any(), anyInt());
}
@Test
@@ -347,6 +358,6 @@
.build();
row.performDismiss(false);
verify(mNotificationTestHelper.mOnUserInteractionCallback, never())
- .onDismiss(any(), anyInt(), any());
+ .registerFutureDismissal(any(), anyInt());
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
index 251ac7d..a855705 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
@@ -78,7 +78,6 @@
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
import com.android.systemui.statusbar.notification.icon.IconBuilder;
import com.android.systemui.statusbar.notification.icon.IconManager;
-import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
import com.android.systemui.statusbar.notification.row.dagger.ExpandableNotificationRowComponent;
@@ -132,7 +131,6 @@
@Mock private NotificationEntryListener mEntryListener;
@Mock private NotificationRowBinderImpl.BindRowCallback mBindCallback;
@Mock private HeadsUpManager mHeadsUpManager;
- @Mock private NotificationInterruptStateProvider mNotificationInterruptionStateProvider;
@Mock private NotificationLockscreenUserManager mLockscreenUserManager;
@Mock private NotificationGutsManager mGutsManager;
@Mock private NotificationRemoteInputManager mRemoteInputManager;
@@ -254,6 +252,7 @@
.thenAnswer((Answer<ExpandableNotificationRowController>) invocation ->
new ExpandableNotificationRowController(
viewCaptor.getValue(),
+ mLockscreenUserManager,
mock(ActivatableNotificationViewController.class),
mock(RemoteInputViewSubcomponent.Factory.class),
mock(MetricsLogger.class),
@@ -300,7 +299,8 @@
new IconManager(
mEntryManager,
mock(LauncherApps.class),
- new IconBuilder(mContext)),
+ new IconBuilder(mContext),
+ mLockscreenUserManager),
mock(LowPriorityInflationHelper.class),
mNotifPipelineFlags);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
index 3d57f66..9ff2c53 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
@@ -23,8 +23,11 @@
import static com.android.systemui.statusbar.NotificationEntryHelper.modifyRanking;
import static org.junit.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.verify;
+import static org.mockito.Mockito.when;
import android.annotation.Nullable;
import android.app.ActivityManager;
@@ -52,6 +55,7 @@
import com.android.systemui.media.MediaFeatureFlag;
import com.android.systemui.media.dialog.MediaOutputDialogFactory;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationShadeWindowController;
@@ -120,6 +124,7 @@
private StatusBarStateController mStatusBarStateController;
private final PeopleNotificationIdentifier mPeopleNotificationIdentifier;
public final OnUserInteractionCallback mOnUserInteractionCallback;
+ public final Runnable mFutureDismissalRunnable;
public NotificationTestHelper(
Context context,
@@ -151,7 +156,8 @@
mIconManager = new IconManager(
mock(CommonNotifCollection.class),
mock(LauncherApps.class),
- new IconBuilder(mContext));
+ new IconBuilder(mContext),
+ mock(NotificationLockscreenUserManager.class));
NotificationContentInflater contentBinder = new NotificationContentInflater(
mock(NotifRemoteViewCache.class),
@@ -179,6 +185,9 @@
mBindPipelineEntryListener = collectionListenerCaptor.getValue();
mPeopleNotificationIdentifier = mock(PeopleNotificationIdentifier.class);
mOnUserInteractionCallback = mock(OnUserInteractionCallback.class);
+ mFutureDismissalRunnable = mock(Runnable.class);
+ when(mOnUserInteractionCallback.registerFutureDismissal(any(), anyInt()))
+ .thenReturn(mFutureDismissalRunnable);
}
/**
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 4270d72..3f19036 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
@@ -5,8 +5,9 @@
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.NotificationShelf
-import junit.framework.Assert.assertFalse
-import junit.framework.Assert.assertTrue
+import com.android.systemui.statusbar.StatusBarIconView
+import com.android.systemui.statusbar.notification.row.ExpandableView
+import junit.framework.Assert.*
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -143,6 +144,113 @@
assertFalse(isYBelowShelfInView)
}
+ @Test
+ fun getAmountInShelf_lastViewBelowShelf_completelyInShelf() {
+ val shelfClipStart = 0f
+ val viewStart = 1f
+
+ val expandableView = mock(ExpandableView::class.java)
+ whenever(expandableView.shelfIcon).thenReturn(mock(StatusBarIconView::class.java))
+ whenever(expandableView.translationY).thenReturn(viewStart)
+ whenever(expandableView.actualHeight).thenReturn(20)
+
+ whenever(expandableView.minHeight).thenReturn(20)
+ whenever(expandableView.shelfTransformationTarget).thenReturn(null) // use translationY
+ whenever(expandableView.isInShelf).thenReturn(true)
+
+ whenever(ambientState.isOnKeyguard).thenReturn(true)
+ whenever(ambientState.isExpansionChanging).thenReturn(false)
+ whenever(ambientState.isShadeExpanded).thenReturn(true)
+
+ val amountInShelf = shelf.getAmountInShelf(/* i= */ 0,
+ /* view= */ expandableView,
+ /* scrollingFast= */ false,
+ /* expandingAnimated= */ false,
+ /* isLastChild= */ true,
+ shelfClipStart)
+ assertEquals(1f, amountInShelf)
+ }
+
+ @Test
+ fun getAmountInShelf_lastViewAlmostBelowShelf_completelyInShelf() {
+ val viewStart = 0f
+ val shelfClipStart = 0.001f
+
+ val expandableView = mock(ExpandableView::class.java)
+ whenever(expandableView.shelfIcon).thenReturn(mock(StatusBarIconView::class.java))
+ whenever(expandableView.translationY).thenReturn(viewStart)
+ whenever(expandableView.actualHeight).thenReturn(20)
+
+ whenever(expandableView.minHeight).thenReturn(20)
+ whenever(expandableView.shelfTransformationTarget).thenReturn(null) // use translationY
+ whenever(expandableView.isInShelf).thenReturn(true)
+
+ whenever(ambientState.isOnKeyguard).thenReturn(true)
+ whenever(ambientState.isExpansionChanging).thenReturn(false)
+ whenever(ambientState.isShadeExpanded).thenReturn(true)
+
+ val amountInShelf = shelf.getAmountInShelf(/* i= */ 0,
+ /* view= */ expandableView,
+ /* scrollingFast= */ false,
+ /* expandingAnimated= */ false,
+ /* isLastChild= */ true,
+ shelfClipStart)
+ assertEquals(1f, amountInShelf)
+ }
+
+ @Test
+ fun getAmountInShelf_lastViewHalfClippedByShelf_halfInShelf() {
+ val viewStart = 0f
+ val shelfClipStart = 10f
+
+ val expandableView = mock(ExpandableView::class.java)
+ whenever(expandableView.shelfIcon).thenReturn(mock(StatusBarIconView::class.java))
+ whenever(expandableView.translationY).thenReturn(viewStart)
+ whenever(expandableView.actualHeight).thenReturn(25)
+
+ whenever(expandableView.minHeight).thenReturn(25)
+ whenever(expandableView.shelfTransformationTarget).thenReturn(null) // use translationY
+ whenever(expandableView.isInShelf).thenReturn(true)
+
+ whenever(ambientState.isOnKeyguard).thenReturn(true)
+ whenever(ambientState.isExpansionChanging).thenReturn(false)
+ whenever(ambientState.isShadeExpanded).thenReturn(true)
+
+ val amountInShelf = shelf.getAmountInShelf(/* i= */ 0,
+ /* view= */ expandableView,
+ /* scrollingFast= */ false,
+ /* expandingAnimated= */ false,
+ /* isLastChild= */ true,
+ shelfClipStart)
+ assertEquals(0.5f, amountInShelf)
+ }
+
+ @Test
+ fun getAmountInShelf_lastViewAboveShelf_notInShelf() {
+ val viewStart = 0f
+ val shelfClipStart = 15f
+
+ val expandableView = mock(ExpandableView::class.java)
+ whenever(expandableView.shelfIcon).thenReturn(mock(StatusBarIconView::class.java))
+ whenever(expandableView.translationY).thenReturn(viewStart)
+ whenever(expandableView.actualHeight).thenReturn(10)
+
+ whenever(expandableView.minHeight).thenReturn(10)
+ whenever(expandableView.shelfTransformationTarget).thenReturn(null) // use translationY
+ whenever(expandableView.isInShelf).thenReturn(false)
+
+ whenever(ambientState.isExpansionChanging).thenReturn(false)
+ whenever(ambientState.isOnKeyguard).thenReturn(true)
+
+ val amountInShelf = shelf.getAmountInShelf(/* i= */ 0,
+ /* view= */ expandableView,
+ /* scrollingFast= */ false,
+ /* expandingAnimated= */ false,
+ /* isLastChild= */ true,
+ shelfClipStart)
+ assertEquals(0f, amountInShelf)
+ }
+
private fun setFractionToShade(fraction: Float) {
whenever(ambientState.fractionToShade).thenReturn(fraction)
}
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 e8608fa7..63e0f53 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
@@ -31,6 +31,8 @@
import static org.junit.Assert.assertFalse;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyFloat;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.clearInvocations;
@@ -612,6 +614,12 @@
assertTrue(mStackScroller.isInsideQsHeader(event2));
}
+ @Test
+ public void setFractionToShade_recomputesStackHeight() {
+ mStackScroller.setFractionToShade(1f);
+ verify(mNotificationStackSizeCalculator).computeHeight(any(), anyInt(), anyFloat());
+ }
+
private void setBarStateForTest(int state) {
// Can't inject this through the listener or we end up on the actual implementation
// rather than the mock because the spy just coppied the anonymous inner /shruggie.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
index ed22cd3..169c04c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
@@ -36,6 +36,7 @@
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.HeadsUpStatusBarView;
+import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
@@ -57,9 +58,12 @@
private final NotificationStackScrollLayoutController mStackScrollerController =
mock(NotificationStackScrollLayoutController.class);
- private final NotificationPanelViewController mPanelView =
+ private final NotificationPanelViewController mPanelViewController =
mock(NotificationPanelViewController.class);
private final DarkIconDispatcher mDarkIconDispatcher = mock(DarkIconDispatcher.class);
+ private final NotificationLockscreenUserManager mLockscreenUserManager =
+ mock(NotificationLockscreenUserManager.class);
+
private HeadsUpAppearanceController mHeadsUpAppearanceController;
private ExpandableNotificationRow mFirst;
private HeadsUpStatusBarView mHeadsUpStatusBarView;
@@ -93,12 +97,13 @@
mHeadsUpManager,
mStatusbarStateController,
mBypassController,
+ mLockscreenUserManager,
mWakeUpCoordinator,
mDarkIconDispatcher,
mKeyguardStateController,
mCommandQueue,
mStackScrollerController,
- mPanelView,
+ mPanelViewController,
mHeadsUpStatusBarView,
new Clock(mContext, null),
Optional.of(mOperatorNameView));
@@ -175,12 +180,13 @@
mHeadsUpManager,
mStatusbarStateController,
mBypassController,
+ mLockscreenUserManager,
mWakeUpCoordinator,
mDarkIconDispatcher,
mKeyguardStateController,
mCommandQueue,
mStackScrollerController,
- mPanelView,
+ mPanelViewController,
mHeadsUpStatusBarView,
new Clock(mContext, null),
Optional.empty());
@@ -193,15 +199,15 @@
public void testDestroy() {
reset(mHeadsUpManager);
reset(mDarkIconDispatcher);
- reset(mPanelView);
+ reset(mPanelViewController);
reset(mStackScrollerController);
mHeadsUpAppearanceController.onViewDetached();
verify(mHeadsUpManager).removeListener(any());
verify(mDarkIconDispatcher).removeDarkReceiver((DarkIconDispatcher.DarkReceiver) any());
- verify(mPanelView).removeTrackingHeadsUpListener(any());
- verify(mPanelView).setHeadsUpAppearanceController(isNull());
+ verify(mPanelViewController).removeTrackingHeadsUpListener(any());
+ verify(mPanelViewController).setHeadsUpAppearanceController(isNull());
verify(mStackScrollerController).removeOnExpandedHeightChangedListener(any());
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
index f43c2a1..9c02216 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
@@ -475,4 +475,19 @@
mBouncer.setExpansion(bouncerHideAmount);
verify(callback, never()).onExpansionChanged(bouncerHideAmount);
}
+
+ @Test
+ public void testOnResumeCalledForFullscreenBouncerOnSecondShow() {
+ // GIVEN a security mode which requires fullscreen bouncer
+ when(mKeyguardSecurityModel.getSecurityMode(anyInt()))
+ .thenReturn(KeyguardSecurityModel.SecurityMode.SimPin);
+ mBouncer.show(true);
+
+ // WHEN a second call to show occurs, the bouncer will already by visible
+ reset(mKeyguardHostViewController);
+ mBouncer.show(true);
+
+ // THEN ensure the ViewController is told to resume
+ verify(mKeyguardHostViewController).onResume();
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java
index 11f96ce..7ebf750 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java
@@ -1009,6 +1009,17 @@
}
@Test
+ public void testExpandWithQsMethodIsUsingLockscreenTransitionController() {
+ enableSplitShade(/* enabled= */ true);
+ mStatusBarStateController.setState(KEYGUARD);
+
+ mNotificationPanelViewController.expandWithQs();
+
+ verify(mLockscreenShadeTransitionController).goToLockedShade(
+ /* expandedView= */null, /* needsQSAnimation= */false);
+ }
+
+ @Test
public void testUnlockAnimationDoesNotAffectScrim() {
mNotificationPanelViewController.onUnlockHintStarted();
verify(mScrimController).setExpansionAffectsAlpha(false);
@@ -1079,6 +1090,21 @@
}
@Test
+ public void testQsExpansionChangedToDefaultWhenRotatingFromOrToSplitShade() {
+ // to make sure shade is in expanded state
+ mNotificationPanelViewController.startWaitingForOpenPanelGesture();
+ assertThat(mNotificationPanelViewController.isQsExpanded()).isFalse();
+
+ // switch to split shade from portrait (default state)
+ enableSplitShade(/* enabled= */ true);
+ assertThat(mNotificationPanelViewController.isQsExpanded()).isTrue();
+
+ // switch to portrait from split shade
+ enableSplitShade(/* enabled= */ false);
+ assertThat(mNotificationPanelViewController.isQsExpanded()).isFalse();
+ }
+
+ @Test
public void interceptTouchEvent_withinQs_shadeExpanded_startsQsTracking() {
mNotificationPanelViewController.mQs = mQs;
when(mQsFrame.getX()).thenReturn(0f);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
index 9ab88dc..ba29e95 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
@@ -136,6 +136,7 @@
private class UnfoldConfig : UnfoldTransitionConfig {
override var isEnabled: Boolean = false
override var isHingeAngleEnabled: Boolean = false
+ override val halfFoldedTimeoutMillis: Int = 0
}
private class TestTouchEventHandler : PhoneStatusBarView.TouchEventHandler {
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 dce520c..5f8dda3 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
@@ -1490,6 +1490,13 @@
assertAlphaAfterExpansion(mNotificationsScrim, 0f, expansion);
}
+ @Test
+ public void aodStateSetsFrontScrimToNotBlend() {
+ mScrimController.transitionTo(ScrimState.AOD);
+ Assert.assertFalse("Front scrim should not blend with main color",
+ mScrimInFront.shouldBlendWithMainColor());
+ }
+
private void assertAlphaAfterExpansion(ScrimView scrim, float expectedAlpha, float expansion) {
mScrimController.setRawPanelExpansionFraction(expansion);
finishAnimationsImmediately();
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 fa867e2..ecea14c 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
@@ -85,7 +85,6 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.Mockito;
@@ -93,6 +92,7 @@
import org.mockito.stubbing.Answer;
import java.util.ArrayList;
+import java.util.List;
import java.util.Optional;
@SmallTest
@@ -141,12 +141,13 @@
@Mock
private OnUserInteractionCallback mOnUserInteractionCallback;
@Mock
+ private Runnable mFutureDismissalRunnable;
+ @Mock
private StatusBarNotificationActivityStarter mNotificationActivityStarter;
@Mock
private ActivityLaunchAnimator mActivityLaunchAnimator;
@Mock
private InteractionJankMonitor mJankMonitor;
- private StatusBarNotificationActivityStarter.LaunchEventsEmitter mLaunchEventsEmitter;
private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock());
private NotificationTestHelper mNotificationTestHelper;
private ExpandableNotificationRow mNotificationRow;
@@ -187,8 +188,8 @@
when(mEntryManager.getVisibleNotifications()).thenReturn(mActiveNotifications);
when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE);
when(mNotifPipelineFlags.isNewPipelineEnabled()).thenReturn(false);
- when(mOnUserInteractionCallback.getGroupSummaryToDismiss(mNotificationRow.getEntry()))
- .thenReturn(null);
+ when(mOnUserInteractionCallback.registerFutureDismissal(eq(mNotificationRow.getEntry()),
+ anyInt())).thenReturn(mFutureDismissalRunnable);
when(mVisibilityProvider.obtain(anyString(), anyBoolean()))
.thenAnswer(invocation -> NotificationVisibility.obtain(
invocation.getArgument(0), 0, 1, false));
@@ -203,7 +204,6 @@
NotificationListContainer.class),
headsUpManager,
mJankMonitor);
- mLaunchEventsEmitter = new StatusBarNotificationActivityStarter.LaunchEventsEmitter();
mNotificationActivityStarter =
new StatusBarNotificationActivityStarter(
getContext(),
@@ -239,8 +239,7 @@
mock(NotificationPresenter.class),
mock(NotificationPanelViewController.class),
mActivityLaunchAnimator,
- notificationAnimationProvider,
- mLaunchEventsEmitter
+ notificationAnimationProvider
);
// set up dismissKeyguardThenExecute to synchronously invoke the OnDismissAction arg
@@ -264,16 +263,23 @@
@Test
public void testOnNotificationClicked_keyGuardShowing()
throws PendingIntent.CanceledException, RemoteException {
+ // To get the order right, collect posted runnables and run them later
+ List<Runnable> runnables = new ArrayList<>();
+ doAnswer(answerVoid(r -> runnables.add((Runnable) r)))
+ .when(mHandler).post(any(Runnable.class));
// Given
- StatusBarNotification sbn = mNotificationRow.getEntry().getSbn();
- sbn.getNotification().contentIntent = mContentIntent;
- sbn.getNotification().flags |= Notification.FLAG_AUTO_CANCEL;
+ NotificationEntry entry = mNotificationRow.getEntry();
+ Notification notification = entry.getSbn().getNotification();
+ notification.contentIntent = mContentIntent;
+ notification.flags |= Notification.FLAG_AUTO_CANCEL;
when(mKeyguardStateController.isShowing()).thenReturn(true);
when(mCentralSurfaces.isOccluded()).thenReturn(true);
// When
- mNotificationActivityStarter.onNotificationClicked(sbn, mNotificationRow);
+ mNotificationActivityStarter.onNotificationClicked(entry, mNotificationRow);
+ // Run the collected runnables in fifo order, the way post() really does.
+ while (!runnables.isEmpty()) runnables.remove(0).run();
// Then
verify(mShadeController, atLeastOnce()).collapsePanel();
@@ -283,24 +289,27 @@
verify(mAssistManager).hideAssist();
- InOrder orderVerifier = Mockito.inOrder(mClickNotifier, mOnUserInteractionCallback);
- orderVerifier.verify(mClickNotifier).onNotificationClick(
- eq(sbn.getKey()), any(NotificationVisibility.class));
+ InOrder orderVerifier = Mockito.inOrder(mClickNotifier, mOnUserInteractionCallback,
+ mFutureDismissalRunnable);
// Notification calls dismiss callback to remove notification due to FLAG_AUTO_CANCEL
- orderVerifier.verify(mOnUserInteractionCallback).onDismiss(mNotificationRow.getEntry(),
- REASON_CLICK, null);
+ orderVerifier.verify(mOnUserInteractionCallback)
+ .registerFutureDismissal(eq(entry), eq(REASON_CLICK));
+ orderVerifier.verify(mClickNotifier).onNotificationClick(
+ eq(entry.getKey()), any(NotificationVisibility.class));
+ orderVerifier.verify(mFutureDismissalRunnable).run();
}
@Test
public void testOnNotificationClicked_bubble_noContentIntent_noKeyGuard()
throws RemoteException {
- StatusBarNotification sbn = mBubbleNotificationRow.getEntry().getSbn();
+ NotificationEntry entry = mBubbleNotificationRow.getEntry();
+ StatusBarNotification sbn = entry.getSbn();
// Given
sbn.getNotification().contentIntent = null;
// When
- mNotificationActivityStarter.onNotificationClicked(sbn, mBubbleNotificationRow);
+ mNotificationActivityStarter.onNotificationClicked(entry, mBubbleNotificationRow);
// Then
verify(mBubblesManager).expandStackAndSelectBubble(eq(mBubbleNotificationRow.getEntry()));
@@ -311,20 +320,22 @@
verify(mAssistManager).hideAssist();
verify(mClickNotifier).onNotificationClick(
- eq(sbn.getKey()), any(NotificationVisibility.class));
+ eq(entry.getKey()), any(NotificationVisibility.class));
// The content intent should NOT be sent on click.
verifyZeroInteractions(mContentIntent);
// Notification should not be cancelled.
- verify(mOnUserInteractionCallback, never()).onDismiss(eq(mNotificationRow.getEntry()),
- anyInt(), eq(null));
+ verify(mOnUserInteractionCallback, never())
+ .registerFutureDismissal(eq(mNotificationRow.getEntry()), anyInt());
+ verify(mFutureDismissalRunnable, never()).run();
}
@Test
public void testOnNotificationClicked_bubble_noContentIntent_keyGuardShowing()
throws RemoteException {
- StatusBarNotification sbn = mBubbleNotificationRow.getEntry().getSbn();
+ NotificationEntry entry = mBubbleNotificationRow.getEntry();
+ StatusBarNotification sbn = entry.getSbn();
// Given
sbn.getNotification().contentIntent = null;
@@ -332,7 +343,7 @@
when(mCentralSurfaces.isOccluded()).thenReturn(true);
// When
- mNotificationActivityStarter.onNotificationClicked(sbn, mBubbleNotificationRow);
+ mNotificationActivityStarter.onNotificationClicked(entry, mBubbleNotificationRow);
// Then
verify(mBubblesManager).expandStackAndSelectBubble(eq(mBubbleNotificationRow.getEntry()));
@@ -342,7 +353,7 @@
verify(mAssistManager).hideAssist();
verify(mClickNotifier).onNotificationClick(
- eq(sbn.getKey()), any(NotificationVisibility.class));
+ eq(entry.getKey()), any(NotificationVisibility.class));
// The content intent should NOT be sent on click.
verifyZeroInteractions(mContentIntent);
@@ -354,7 +365,8 @@
@Test
public void testOnNotificationClicked_bubble_withContentIntent_keyGuardShowing()
throws RemoteException {
- StatusBarNotification sbn = mBubbleNotificationRow.getEntry().getSbn();
+ NotificationEntry entry = mBubbleNotificationRow.getEntry();
+ StatusBarNotification sbn = entry.getSbn();
// Given
sbn.getNotification().contentIntent = mContentIntent;
@@ -362,7 +374,7 @@
when(mCentralSurfaces.isOccluded()).thenReturn(true);
// When
- mNotificationActivityStarter.onNotificationClicked(sbn, mBubbleNotificationRow);
+ mNotificationActivityStarter.onNotificationClicked(entry, mBubbleNotificationRow);
// Then
verify(mBubblesManager).expandStackAndSelectBubble(mBubbleNotificationRow.getEntry());
@@ -372,7 +384,7 @@
verify(mAssistManager).hideAssist();
verify(mClickNotifier).onNotificationClick(
- eq(sbn.getKey()), any(NotificationVisibility.class));
+ eq(entry.getKey()), any(NotificationVisibility.class));
// The content intent should NOT be sent on click.
verify(mContentIntent).getIntent();
@@ -405,57 +417,4 @@
// THEN display should try wake up for the full screen intent
verify(mCentralSurfaces).wakeUpForFullScreenIntent();
}
-
- @Test
- public void testNotifActivityStarterEventSourceStartEvent_onNotificationClicked() {
- NotifActivityLaunchEvents.Listener listener =
- mock(NotifActivityLaunchEvents.Listener.class);
- mLaunchEventsEmitter.registerListener(listener);
- mNotificationActivityStarter
- .onNotificationClicked(mNotificationRow.getEntry().getSbn(), mNotificationRow);
- verify(listener).onStartLaunchNotifActivity(mNotificationRow.getEntry());
- }
-
- @Test
- public void testNotifActivityStarterEventSourceFinishEvent_dismissKeyguardCancelled() {
- NotifActivityLaunchEvents.Listener listener =
- mock(NotifActivityLaunchEvents.Listener.class);
- mLaunchEventsEmitter.registerListener(listener);
- // set up dismissKeyguardThenExecute to synchronously invoke the cancel runnable arg
- doAnswer(answerVoid(
- (OnDismissAction dismissAction, Runnable cancel, Boolean afterKeyguardGone) ->
- cancel.run()))
- .when(mActivityStarter)
- .dismissKeyguardThenExecute(any(OnDismissAction.class), any(), anyBoolean());
- mNotificationActivityStarter
- .onNotificationClicked(mNotificationRow.getEntry().getSbn(), mNotificationRow);
- verify(listener).onFinishLaunchNotifActivity(mNotificationRow.getEntry());
- }
-
- @Test
- public void testNotifActivityStarterEventSourceFinishEvent_postPanelCollapse()
- throws Exception {
- NotifActivityLaunchEvents.Listener listener =
- mock(NotifActivityLaunchEvents.Listener.class);
- mLaunchEventsEmitter.registerListener(listener);
- mNotificationActivityStarter
- .onNotificationClicked(mNotificationRow.getEntry().getSbn(), mNotificationRow);
- ArgumentCaptor<ActivityLaunchAnimator.Controller> controllerCaptor =
- ArgumentCaptor.forClass(ActivityLaunchAnimator.Controller.class);
- verify(mActivityLaunchAnimator).startPendingIntentWithAnimation(
- controllerCaptor.capture(), anyBoolean(), any(), any());
- controllerCaptor.getValue().onIntentStarted(false);
- verify(listener).onFinishLaunchNotifActivity(mNotificationRow.getEntry());
- }
-
- @Test
- public void testNotifActivityStarterEventSourceFinishEvent_postPanelCollapse_noAnimate() {
- NotifActivityLaunchEvents.Listener listener =
- mock(NotifActivityLaunchEvents.Listener.class);
- mLaunchEventsEmitter.registerListener(listener);
- when(mCentralSurfaces.shouldAnimateLaunch(anyBoolean())).thenReturn(false);
- mNotificationActivityStarter
- .onNotificationClicked(mNotificationRow.getEntry().getSbn(), mNotificationRow);
- verify(listener).onFinishLaunchNotifActivity(mNotificationRow.getEntry());
- }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
index 7e4862e..b94aac2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
@@ -375,7 +375,7 @@
mCommandQueue,
mCarrierConfigTracker,
new CollapsedStatusBarFragmentLogger(
- new LogBuffer("TEST", 1, 1, mock(LogcatEchoTracker.class)),
+ new LogBuffer("TEST", 1, mock(LogcatEchoTracker.class)),
new DisableFlagsLogger()
),
mOperatorNameViewControllerFactory,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
index 3dfc94b..68818f6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
@@ -74,6 +74,8 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.Arrays;
+import java.util.List;
import java.util.Map;
import java.util.concurrent.Executor;
@@ -345,7 +347,9 @@
@Test
public void onSettingChanged_honorThemeStyle() {
when(mDeviceProvisionedController.isUserSetup(anyInt())).thenReturn(true);
- for (Style style : Style.values()) {
+ List<Style> validStyles = Arrays.asList(Style.EXPRESSIVE, Style.SPRITZ, Style.TONAL_SPOT,
+ Style.FRUIT_SALAD, Style.RAINBOW, Style.VIBRANT);
+ for (Style style : validStyles) {
reset(mSecureSettings);
String jsonString = "{\"android.theme.customization.system_palette\":\"A16B00\","
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldStateLoggingProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldStateLoggingProviderTest.kt
index 8076b4e..39e4e64 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldStateLoggingProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldStateLoggingProviderTest.kt
@@ -25,28 +25,20 @@
import com.android.systemui.unfold.updates.FOLD_UPDATE_FINISH_HALF_OPEN
import com.android.systemui.unfold.updates.FOLD_UPDATE_START_CLOSING
import com.android.systemui.unfold.updates.FOLD_UPDATE_START_OPENING
-import com.android.systemui.unfold.updates.FoldStateProvider
import com.android.systemui.unfold.updates.FoldStateProvider.FoldUpdate
+import com.android.systemui.unfold.util.TestFoldStateProvider
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.verify
import org.mockito.MockitoAnnotations
@RunWith(AndroidTestingRunner::class)
@SmallTest
class FoldStateLoggingProviderTest : SysuiTestCase() {
- @Captor
- private lateinit var foldUpdatesListener: ArgumentCaptor<FoldStateProvider.FoldUpdatesListener>
-
- @Mock private lateinit var foldStateProvider: FoldStateProvider
-
+ private val testFoldStateProvider = TestFoldStateProvider()
private val fakeClock = FakeSystemClock()
private lateinit var foldStateLoggingProvider: FoldStateLoggingProvider
@@ -65,12 +57,10 @@
MockitoAnnotations.initMocks(this)
foldStateLoggingProvider =
- FoldStateLoggingProviderImpl(foldStateProvider, fakeClock).apply {
+ FoldStateLoggingProviderImpl(testFoldStateProvider, fakeClock).apply {
addCallback(foldStateLoggingListener)
init()
}
-
- verify(foldStateProvider).addCallback(foldUpdatesListener.capture())
}
@Test
@@ -183,10 +173,10 @@
fun uninit_removesCallback() {
foldStateLoggingProvider.uninit()
- verify(foldStateProvider).removeCallback(foldUpdatesListener.value)
+ assertThat(testFoldStateProvider.hasListeners).isFalse()
}
private fun sendFoldUpdate(@FoldUpdate foldUpdate: Int) {
- foldUpdatesListener.value.onFoldUpdate(foldUpdate)
+ testFoldStateProvider.sendFoldUpdate(foldUpdate)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/config/ResourceUnfoldTransitionConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/config/ResourceUnfoldTransitionConfigTest.kt
new file mode 100644
index 0000000..ab450e2
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/config/ResourceUnfoldTransitionConfigTest.kt
@@ -0,0 +1,54 @@
+/*
+ * 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.unfold.config
+
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+
+/**
+ * A test that checks that we load correct resources in
+ * ResourceUnfoldTransitionConfig as we use strings there instead of R constants.
+ * Internal Android resource constants are not available in public APIs,
+ * so we can't use them there directly.
+ */
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class ResourceUnfoldTransitionConfigTest : SysuiTestCase() {
+
+ private val config = ResourceUnfoldTransitionConfig()
+
+ @Test
+ fun testIsEnabled() {
+ assertThat(config.isEnabled).isEqualTo(mContext.resources
+ .getBoolean(com.android.internal.R.bool.config_unfoldTransitionEnabled))
+ }
+
+ @Test
+ fun testHingeAngleEnabled() {
+ assertThat(config.isHingeAngleEnabled).isEqualTo(mContext.resources
+ .getBoolean(com.android.internal.R.bool.config_unfoldTransitionHingeAngle))
+ }
+
+ @Test
+ fun testHalfFoldedTimeout() {
+ assertThat(config.halfFoldedTimeoutMillis).isEqualTo(mContext.resources
+ .getInteger(com.android.internal.R.integer.config_unfoldTransitionHalfFoldedTimeout))
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt
index 1f1f88b..87fca1f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt
@@ -16,82 +16,69 @@
package com.android.systemui.unfold.updates
-import android.app.ActivityManager
-import android.app.ActivityManager.RunningTaskInfo
-import android.app.WindowConfiguration.ACTIVITY_TYPE_HOME
-import android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD
-import android.app.WindowConfiguration.ActivityType
-import android.hardware.devicestate.DeviceStateManager
-import android.hardware.devicestate.DeviceStateManager.FoldStateListener
import android.os.Handler
import android.testing.AndroidTestingRunner
import androidx.core.util.Consumer
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.unfold.config.ResourceUnfoldTransitionConfig
+import com.android.systemui.unfold.config.UnfoldTransitionConfig
+import com.android.systemui.unfold.system.ActivityManagerActivityTypeProvider
+import com.android.systemui.unfold.updates.FoldProvider.FoldCallback
import com.android.systemui.unfold.updates.hinge.HingeAngleProvider
import com.android.systemui.unfold.updates.screen.ScreenStatusProvider
import com.android.systemui.unfold.updates.screen.ScreenStatusProvider.ScreenListener
-import com.android.systemui.unfold.util.FoldableDeviceStates
-import com.android.systemui.unfold.util.FoldableTestUtils
import com.android.systemui.util.mockito.any
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.verify
-import org.mockito.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations
+import java.util.concurrent.Executor
+import org.mockito.Mockito.`when` as whenever
@RunWith(AndroidTestingRunner::class)
@SmallTest
class DeviceFoldStateProviderTest : SysuiTestCase() {
- @Mock private lateinit var hingeAngleProvider: HingeAngleProvider
+ @Mock
+ private lateinit var activityTypeProvider: ActivityManagerActivityTypeProvider
- @Mock private lateinit var screenStatusProvider: ScreenStatusProvider
+ @Mock
+ private lateinit var handler: Handler
- @Mock private lateinit var deviceStateManager: DeviceStateManager
-
- @Mock private lateinit var activityManager: ActivityManager
-
- @Mock private lateinit var handler: Handler
-
- @Captor private lateinit var foldStateListenerCaptor: ArgumentCaptor<FoldStateListener>
-
- @Captor private lateinit var screenOnListenerCaptor: ArgumentCaptor<ScreenListener>
-
- @Captor private lateinit var hingeAngleCaptor: ArgumentCaptor<Consumer<Float>>
+ private val foldProvider = TestFoldProvider()
+ private val screenOnStatusProvider = TestScreenOnStatusProvider()
+ private val testHingeAngleProvider = TestHingeAngleProvider()
private lateinit var foldStateProvider: DeviceFoldStateProvider
private val foldUpdates: MutableList<Int> = arrayListOf()
private val hingeAngleUpdates: MutableList<Float> = arrayListOf()
- private lateinit var deviceStates: FoldableDeviceStates
-
private var scheduledRunnable: Runnable? = null
private var scheduledRunnableDelay: Long? = null
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
- overrideResource(
- com.android.internal.R.integer.config_unfoldTransitionHalfFoldedTimeout,
- HALF_OPENED_TIMEOUT_MILLIS.toInt())
- deviceStates = FoldableTestUtils.findDeviceStates(context)
+
+ val config = object : UnfoldTransitionConfig by ResourceUnfoldTransitionConfig() {
+ override val halfFoldedTimeoutMillis: Int
+ get() = HALF_OPENED_TIMEOUT_MILLIS.toInt()
+ }
foldStateProvider =
DeviceFoldStateProvider(
- context,
- hingeAngleProvider,
- screenStatusProvider,
- deviceStateManager,
- activityManager,
+ config,
+ testHingeAngleProvider,
+ screenOnStatusProvider,
+ foldProvider,
+ activityTypeProvider,
context.mainExecutor,
- handler)
+ handler
+ )
foldStateProvider.addCallback(
object : FoldStateProvider.FoldUpdatesListener {
@@ -105,10 +92,6 @@
})
foldStateProvider.start()
- verify(deviceStateManager).registerCallback(any(), foldStateListenerCaptor.capture())
- verify(screenStatusProvider).addCallback(screenOnListenerCaptor.capture())
- verify(hingeAngleProvider).addCallback(hingeAngleCaptor.capture())
-
whenever(handler.postDelayed(any<Runnable>(), any())).then { invocationOnMock ->
scheduledRunnable = invocationOnMock.getArgument<Runnable>(0)
scheduledRunnableDelay = invocationOnMock.getArgument<Long>(1)
@@ -125,7 +108,7 @@
}
// By default, we're on launcher.
- setupForegroundActivityType(ACTIVITY_TYPE_HOME)
+ setupForegroundActivityType(isHomeActivity = true)
}
@Test
@@ -146,14 +129,14 @@
fun testOnFolded_stopsHingeAngleProvider() {
setFoldState(folded = true)
- verify(hingeAngleProvider).stop()
+ assertThat(testHingeAngleProvider.isStarted).isFalse()
}
@Test
fun testOnUnfolded_startsHingeAngleProvider() {
setFoldState(folded = false)
- verify(hingeAngleProvider).start()
+ assertThat(testHingeAngleProvider.isStarted).isTrue()
}
@Test
@@ -310,7 +293,7 @@
@Test
fun startClosingEvent_whileNotOnLauncher_doesNotTriggerBeforeThreshold() {
- setupForegroundActivityType(ACTIVITY_TYPE_STANDARD)
+ setupForegroundActivityType(isHomeActivity = false)
sendHingeAngleEvent(180)
sendHingeAngleEvent(START_CLOSING_ON_APPS_THRESHOLD_DEGREES + 1)
@@ -319,8 +302,28 @@
}
@Test
+ fun startClosingEvent_whileActivityTypeNotAvailable_triggerBeforeThreshold() {
+ setupForegroundActivityType(isHomeActivity = null)
+ sendHingeAngleEvent(180)
+
+ sendHingeAngleEvent(START_CLOSING_ON_APPS_THRESHOLD_DEGREES + 1)
+
+ assertThat(foldUpdates).containsExactly(FOLD_UPDATE_START_CLOSING)
+ }
+
+ @Test
+ fun startClosingEvent_whileOnLauncher_doesTriggerBeforeThreshold() {
+ setupForegroundActivityType(isHomeActivity = true)
+ sendHingeAngleEvent(180)
+
+ sendHingeAngleEvent(START_CLOSING_ON_APPS_THRESHOLD_DEGREES + 1)
+
+ assertThat(foldUpdates).containsExactly(FOLD_UPDATE_START_CLOSING)
+ }
+
+ @Test
fun startClosingEvent_whileNotOnLauncher_triggersAfterThreshold() {
- setupForegroundActivityType(ACTIVITY_TYPE_STANDARD)
+ setupForegroundActivityType(isHomeActivity = false)
sendHingeAngleEvent(START_CLOSING_ON_APPS_THRESHOLD_DEGREES)
sendHingeAngleEvent(START_CLOSING_ON_APPS_THRESHOLD_DEGREES - 1)
@@ -328,9 +331,8 @@
assertThat(foldUpdates).containsExactly(FOLD_UPDATE_START_CLOSING)
}
- private fun setupForegroundActivityType(@ActivityType type: Int) {
- val taskInfo = RunningTaskInfo().apply { topActivityType = type }
- whenever(activityManager.getRunningTasks(1)).thenReturn(listOf(taskInfo))
+ private fun setupForegroundActivityType(isHomeActivity: Boolean?) {
+ whenever(activityTypeProvider.isHomeActivity).thenReturn(isHomeActivity)
}
private fun simulateTimeout(waitTime: Long = HALF_OPENED_TIMEOUT_MILLIS) {
@@ -348,16 +350,72 @@
}
private fun setFoldState(folded: Boolean) {
- val state = if (folded) deviceStates.folded else deviceStates.unfolded
- foldStateListenerCaptor.value.onStateChanged(state)
+ foldProvider.notifyFolded(folded)
}
private fun fireScreenOnEvent() {
- screenOnListenerCaptor.value.onScreenTurnedOn()
+ screenOnStatusProvider.notifyScreenTurnedOn()
}
private fun sendHingeAngleEvent(angle: Int) {
- hingeAngleCaptor.value.accept(angle.toFloat())
+ testHingeAngleProvider.notifyAngle(angle.toFloat())
+ }
+
+ private class TestFoldProvider : FoldProvider {
+ private val callbacks = arrayListOf<FoldCallback>()
+
+ override fun registerCallback(callback: FoldCallback, executor: Executor) {
+ callbacks += callback
+ }
+
+ override fun unregisterCallback(callback: FoldCallback) {
+ callbacks -= callback
+ }
+
+ fun notifyFolded(isFolded: Boolean) {
+ callbacks.forEach { it.onFoldUpdated(isFolded) }
+ }
+ }
+
+ private class TestScreenOnStatusProvider : ScreenStatusProvider {
+ private val callbacks = arrayListOf<ScreenListener>()
+
+ override fun addCallback(listener: ScreenListener) {
+ callbacks += listener
+ }
+
+ override fun removeCallback(listener: ScreenListener) {
+ callbacks -= listener
+ }
+
+ fun notifyScreenTurnedOn() {
+ callbacks.forEach { it.onScreenTurnedOn() }
+ }
+ }
+
+ private class TestHingeAngleProvider : HingeAngleProvider {
+ private val callbacks = arrayListOf<Consumer<Float>>()
+ var isStarted: Boolean = false
+
+ override fun start() {
+ isStarted = true;
+ }
+
+ override fun stop() {
+ isStarted = false;
+ }
+
+ override fun addCallback(listener: Consumer<Float>) {
+ callbacks += listener
+ }
+
+ override fun removeCallback(listener: Consumer<Float>) {
+ callbacks -= listener
+ }
+
+ fun notifyAngle(angle: Float) {
+ callbacks.forEach { it.accept(angle) }
+ }
}
companion object {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/util/NaturalRotationUnfoldProgressProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/util/NaturalRotationUnfoldProgressProviderTest.kt
index a3f17aa..b2cedbf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/unfold/util/NaturalRotationUnfoldProgressProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/util/NaturalRotationUnfoldProgressProviderTest.kt
@@ -20,18 +20,18 @@
import android.view.IWindowManager
import android.view.Surface
import androidx.test.filters.SmallTest
-import com.android.systemui.unfold.UnfoldTransitionProgressProvider
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.unfold.TestUnfoldTransitionProvider
import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
import com.android.systemui.util.mockito.any
-import com.android.systemui.SysuiTestCase
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.Mock
-import org.mockito.Mockito.verify
import org.mockito.Mockito.clearInvocations
import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
@RunWith(AndroidTestingRunner::class)
@@ -41,16 +41,13 @@
@Mock
lateinit var windowManager: IWindowManager
- @Mock
- lateinit var sourceProvider: UnfoldTransitionProgressProvider
+ private val sourceProvider = TestUnfoldTransitionProvider()
@Mock
lateinit var transitionListener: TransitionProgressListener
lateinit var progressProvider: NaturalRotationUnfoldProgressProvider
- private val sourceProviderListenerCaptor =
- ArgumentCaptor.forClass(TransitionProgressListener::class.java)
private val rotationWatcherCaptor =
ArgumentCaptor.forClass(IRotationWatcher.Stub::class.java)
@@ -66,7 +63,6 @@
progressProvider.init()
- verify(sourceProvider).addCallback(sourceProviderListenerCaptor.capture())
verify(windowManager).watchRotation(rotationWatcherCaptor.capture(), any())
progressProvider.addCallback(transitionListener)
@@ -76,7 +72,7 @@
fun testNaturalRotation0_sendTransitionStartedEvent_eventReceived() {
onRotationChanged(Surface.ROTATION_0)
- source.onTransitionStarted()
+ sourceProvider.onTransitionStarted()
verify(transitionListener).onTransitionStarted()
}
@@ -85,7 +81,7 @@
fun testNaturalRotation0_sendTransitionProgressEvent_eventReceived() {
onRotationChanged(Surface.ROTATION_0)
- source.onTransitionProgress(0.5f)
+ sourceProvider.onTransitionProgress(0.5f)
verify(transitionListener).onTransitionProgress(0.5f)
}
@@ -94,7 +90,7 @@
fun testNotNaturalRotation90_sendTransitionStartedEvent_eventNotReceived() {
onRotationChanged(Surface.ROTATION_90)
- source.onTransitionStarted()
+ sourceProvider.onTransitionStarted()
verify(transitionListener, never()).onTransitionStarted()
}
@@ -103,7 +99,7 @@
fun testNaturalRotation90_sendTransitionProgressEvent_eventNotReceived() {
onRotationChanged(Surface.ROTATION_90)
- source.onTransitionProgress(0.5f)
+ sourceProvider.onTransitionProgress(0.5f)
verify(transitionListener, never()).onTransitionProgress(0.5f)
}
@@ -111,7 +107,7 @@
@Test
fun testRotationBecameUnnaturalDuringTransition_sendsTransitionFinishedEvent() {
onRotationChanged(Surface.ROTATION_0)
- source.onTransitionStarted()
+ sourceProvider.onTransitionStarted()
clearInvocations(transitionListener)
onRotationChanged(Surface.ROTATION_90)
@@ -122,7 +118,7 @@
@Test
fun testRotationBecameNaturalDuringTransition_sendsTransitionStartedEvent() {
onRotationChanged(Surface.ROTATION_90)
- source.onTransitionStarted()
+ sourceProvider.onTransitionStarted()
clearInvocations(transitionListener)
onRotationChanged(Surface.ROTATION_0)
@@ -133,7 +129,4 @@
private fun onRotationChanged(rotation: Int) {
rotationWatcherCaptor.value.onRotationChanged(rotation)
}
-
- private val source: TransitionProgressListener
- get() = sourceProviderListenerCaptor.value
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/util/ScaleAwareUnfoldProgressProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/util/ScaleAwareUnfoldProgressProviderTest.kt
index db7a8516..fc2a78a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/unfold/util/ScaleAwareUnfoldProgressProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/util/ScaleAwareUnfoldProgressProviderTest.kt
@@ -21,6 +21,7 @@
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.unfold.TestUnfoldTransitionProvider
import com.android.systemui.unfold.UnfoldTransitionProgressProvider
import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
import com.android.systemui.util.mockito.any
@@ -41,15 +42,11 @@
lateinit var contentResolver: ContentResolver
@Mock
- lateinit var sourceProvider: UnfoldTransitionProgressProvider
-
- @Mock
lateinit var sinkProvider: TransitionProgressListener
- lateinit var progressProvider: ScaleAwareTransitionProgressProvider
+ private val sourceProvider = TestUnfoldTransitionProvider()
- private val sourceProviderListenerCaptor =
- ArgumentCaptor.forClass(TransitionProgressListener::class.java)
+ lateinit var progressProvider: ScaleAwareTransitionProgressProvider
private val animatorDurationScaleListenerCaptor =
ArgumentCaptor.forClass(ContentObserver::class.java)
@@ -63,7 +60,6 @@
contentResolver
)
- verify(sourceProvider).addCallback(sourceProviderListenerCaptor.capture())
verify(contentResolver).registerContentObserver(any(), any(),
animatorDurationScaleListenerCaptor.capture())
@@ -74,7 +70,7 @@
fun onTransitionStarted_animationsEnabled_eventReceived() {
setAnimationsEnabled(true)
- source.onTransitionStarted()
+ sourceProvider.onTransitionStarted()
verify(sinkProvider).onTransitionStarted()
}
@@ -83,7 +79,7 @@
fun onTransitionStarted_animationsNotEnabled_eventNotReceived() {
setAnimationsEnabled(false)
- source.onTransitionStarted()
+ sourceProvider.onTransitionStarted()
verifyNoMoreInteractions(sinkProvider)
}
@@ -92,7 +88,7 @@
fun onTransitionEnd_animationsEnabled_eventReceived() {
setAnimationsEnabled(true)
- source.onTransitionFinished()
+ sourceProvider.onTransitionFinished()
verify(sinkProvider).onTransitionFinished()
}
@@ -101,7 +97,7 @@
fun onTransitionEnd_animationsNotEnabled_eventNotReceived() {
setAnimationsEnabled(false)
- source.onTransitionFinished()
+ sourceProvider.onTransitionFinished()
verifyNoMoreInteractions(sinkProvider)
}
@@ -110,7 +106,7 @@
fun onTransitionProgress_animationsEnabled_eventReceived() {
setAnimationsEnabled(true)
- source.onTransitionProgress(42f)
+ sourceProvider.onTransitionProgress(42f)
verify(sinkProvider).onTransitionProgress(42f)
}
@@ -119,7 +115,7 @@
fun onTransitionProgress_animationsNotEnabled_eventNotReceived() {
setAnimationsEnabled(false)
- source.onTransitionProgress(42f)
+ sourceProvider.onTransitionProgress(42f)
verifyNoMoreInteractions(sinkProvider)
}
@@ -133,7 +129,4 @@
ValueAnimator.setDurationScale(durationScale)
animatorDurationScaleListenerCaptor.value.dispatchChange(/* selfChange= */false)
}
-
- private val source: TransitionProgressListener
- get() = sourceProviderListenerCaptor.value
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/util/TestFoldStateProvider.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/util/TestFoldStateProvider.kt
index 8f851ec..a064e8c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/unfold/util/TestFoldStateProvider.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/util/TestFoldStateProvider.kt
@@ -24,6 +24,8 @@
class TestFoldStateProvider : FoldStateProvider {
private val listeners: MutableList<FoldUpdatesListener> = arrayListOf()
+ val hasListeners: Boolean
+ get() = listeners.isNotEmpty()
override fun start() {
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/ChannelsTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/NotificationChannelsTest.java
similarity index 81%
rename from packages/SystemUI/tests/src/com/android/systemui/util/ChannelsTest.java
rename to packages/SystemUI/tests/src/com/android/systemui/util/NotificationChannelsTest.java
index c7bcdef..900d792 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/ChannelsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/NotificationChannelsTest.java
@@ -28,7 +28,6 @@
import androidx.test.runner.AndroidJUnit4;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.util.NotificationChannels;
import org.junit.Before;
import org.junit.Test;
@@ -41,7 +40,7 @@
@SmallTest
@RunWith(AndroidJUnit4.class)
-public class ChannelsTest extends SysuiTestCase {
+public class NotificationChannelsTest extends SysuiTestCase {
private final NotificationManager mMockNotificationManager = mock(NotificationManager.class);
@Before
@@ -55,9 +54,10 @@
NotificationChannels.ALERTS,
NotificationChannels.SCREENSHOTS_HEADSUP,
NotificationChannels.STORAGE,
- NotificationChannels.GENERAL,
+ NotificationChannels.INSTANT,
NotificationChannels.BATTERY,
- NotificationChannels.HINTS
+ NotificationChannels.HINTS,
+ NotificationChannels.SETUP
));
NotificationChannels.createAll(mContext);
ArgumentCaptor<List> captor = ArgumentCaptor.forClass(List.class);
@@ -67,4 +67,11 @@
list.forEach((chan) -> assertTrue(ALL_CHANNELS.contains(chan.getId())));
}
+ @Test
+ public void testChannelCleanup() {
+ new NotificationChannels(mContext).start();
+ ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
+ verify(mMockNotificationManager).deleteNotificationChannel(captor.capture());
+ assertEquals(NotificationChannels.GENERAL, captor.getValue());
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/collection/RingBufferTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/collection/RingBufferTest.kt
new file mode 100644
index 0000000..5e09b81
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/collection/RingBufferTest.kt
@@ -0,0 +1,131 @@
+/*
+ * 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.collection
+
+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.assertSame
+import org.junit.Assert.assertThrows
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class RingBufferTest : SysuiTestCase() {
+
+ private val buffer = RingBuffer(5) { TestElement() }
+
+ private val history = mutableListOf<TestElement>()
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ }
+
+ @Test
+ fun testBarelyFillBuffer() {
+ fillBuffer(5)
+
+ assertEquals(0, buffer[0].id)
+ assertEquals(1, buffer[1].id)
+ assertEquals(2, buffer[2].id)
+ assertEquals(3, buffer[3].id)
+ assertEquals(4, buffer[4].id)
+ }
+
+ @Test
+ fun testPartiallyFillBuffer() {
+ fillBuffer(3)
+
+ assertEquals(3, buffer.size)
+
+ assertEquals(0, buffer[0].id)
+ assertEquals(1, buffer[1].id)
+ assertEquals(2, buffer[2].id)
+
+ assertThrows(IndexOutOfBoundsException::class.java) { buffer[3] }
+ assertThrows(IndexOutOfBoundsException::class.java) { buffer[4] }
+ }
+
+ @Test
+ fun testSpinBuffer() {
+ fillBuffer(277)
+
+ assertEquals(272, buffer[0].id)
+ assertEquals(273, buffer[1].id)
+ assertEquals(274, buffer[2].id)
+ assertEquals(275, buffer[3].id)
+ assertEquals(276, buffer[4].id)
+ assertThrows(IndexOutOfBoundsException::class.java) { buffer[5] }
+
+ assertEquals(5, buffer.size)
+ }
+
+ @Test
+ fun testElementsAreRecycled() {
+ fillBuffer(23)
+
+ assertSame(history[4], buffer[1])
+ assertSame(history[9], buffer[1])
+ assertSame(history[14], buffer[1])
+ assertSame(history[19], buffer[1])
+ }
+
+ @Test
+ fun testIterator() {
+ fillBuffer(13)
+
+ val iterator = buffer.iterator()
+
+ for (i in 0 until 5) {
+ assertEquals(history[8 + i], iterator.next())
+ }
+ assertFalse(iterator.hasNext())
+ assertThrows(NoSuchElementException::class.java) { iterator.next() }
+ }
+
+ @Test
+ fun testForEach() {
+ fillBuffer(13)
+ var i = 8
+
+ buffer.forEach {
+ assertEquals(history[i], it)
+ i++
+ }
+ assertEquals(13, i)
+ }
+
+ private fun fillBuffer(count: Int) {
+ for (i in 0 until count) {
+ val elem = buffer.advance()
+ elem.id = history.size
+ history.add(elem)
+ }
+ }
+}
+
+private class TestElement(var id: Int = 0) {
+ override fun toString(): String {
+ return "{TestElement $id}"
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
index 9493456..312db2d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
@@ -38,6 +38,7 @@
import androidx.test.filters.SmallTest;
+import com.android.internal.jank.InteractionJankMonitor;
import com.android.systemui.Prefs;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
@@ -85,6 +86,8 @@
MediaOutputDialogFactory mMediaOutputDialogFactory;
@Mock
ActivityStarter mActivityStarter;
+ @Mock
+ InteractionJankMonitor mInteractionJankMonitor;
@Before
public void setup() throws Exception {
@@ -99,7 +102,8 @@
mDeviceProvisionedController,
mConfigurationController,
mMediaOutputDialogFactory,
- mActivityStarter);
+ mActivityStarter,
+ mInteractionJankMonitor);
mDialog.init(0, null);
State state = createShellState();
mDialog.onStateChangedH(state);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wallet/controller/QuickAccessWalletControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/wallet/controller/QuickAccessWalletControllerTest.java
index de2efc7..8e4f184 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wallet/controller/QuickAccessWalletControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wallet/controller/QuickAccessWalletControllerTest.java
@@ -100,7 +100,6 @@
mContext,
MoreExecutors.directExecutor(),
MoreExecutors.directExecutor(),
- MoreExecutors.directExecutor(),
mSecureSettings,
mQuickAccessWalletClient,
mClock);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
index 238a4d3..7d4e27f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -66,6 +66,7 @@
import android.os.Handler;
import android.os.PowerManager;
import android.os.UserHandle;
+import android.os.UserManager;
import android.service.dreams.IDreamManager;
import android.service.notification.NotificationListenerService;
import android.service.notification.ZenModeConfig;
@@ -365,6 +366,7 @@
mStatusBarService,
mWindowManager,
mWindowManagerShellWrapper,
+ mock(UserManager.class),
mLauncherApps,
mBubbleLogger,
mTaskStackListener,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
index dff89e0..a6327b9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
@@ -55,6 +55,7 @@
import android.os.Handler;
import android.os.PowerManager;
import android.os.UserHandle;
+import android.os.UserManager;
import android.service.dreams.IDreamManager;
import android.service.notification.NotificationListenerService;
import android.service.notification.ZenModeConfig;
@@ -330,6 +331,7 @@
mStatusBarService,
mWindowManager,
mWindowManagerShellWrapper,
+ mock(UserManager.class),
mLauncherApps,
mBubbleLogger,
mTaskStackListener,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java
index 9646edf..17e5778 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java
@@ -19,6 +19,7 @@
import android.content.Context;
import android.content.pm.LauncherApps;
import android.os.Handler;
+import android.os.UserManager;
import android.view.WindowManager;
import com.android.internal.statusbar.IStatusBarService;
@@ -53,6 +54,7 @@
IStatusBarService statusBarService,
WindowManager windowManager,
WindowManagerShellWrapper windowManagerShellWrapper,
+ UserManager userManager,
LauncherApps launcherApps,
BubbleLogger bubbleLogger,
TaskStackListenerImpl taskStackListener,
@@ -66,10 +68,10 @@
TaskViewTransitions taskViewTransitions,
SyncTransactionQueue syncQueue) {
super(context, data, Runnable::run, floatingContentCoordinator, dataRepository,
- statusBarService, windowManager, windowManagerShellWrapper, launcherApps,
- bubbleLogger, taskStackListener, shellTaskOrganizer, positioner, displayController,
- oneHandedOptional, dragAndDropController, shellMainExecutor, shellMainHandler,
- taskViewTransitions, syncQueue);
+ statusBarService, windowManager, windowManagerShellWrapper, userManager,
+ launcherApps, bubbleLogger, taskStackListener, shellTaskOrganizer, positioner,
+ displayController, oneHandedOptional, dragAndDropController, shellMainExecutor,
+ shellMainHandler, new SyncExecutor(), taskViewTransitions, syncQueue);
setInflateSynchronously(true);
initialize();
}
diff --git a/packages/SystemUI/unfold/Android.bp b/packages/SystemUI/unfold/Android.bp
new file mode 100644
index 0000000..108295b
--- /dev/null
+++ b/packages/SystemUI/unfold/Android.bp
@@ -0,0 +1,39 @@
+// 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_packages_SystemUI_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_packages_SystemUI_license"],
+}
+
+android_library {
+ name: "SystemUIUnfoldLib",
+ srcs: [
+ "src/**/*.java",
+ "src/**/*.kt",
+ "src/**/*.aidl",
+ ],
+ static_libs: [
+ "androidx.dynamicanimation_dynamicanimation",
+ "dagger2",
+ "jsr330",
+ ],
+ java_version: "1.8",
+ min_sdk_version: "current",
+ plugins: ["dagger2-compiler"],
+}
diff --git a/packages/SystemUI/unfold/AndroidManifest.xml b/packages/SystemUI/unfold/AndroidManifest.xml
new file mode 100644
index 0000000..ee8afe1
--- /dev/null
+++ b/packages/SystemUI/unfold/AndroidManifest.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.systemui.unfold">
+
+
+</manifest>
diff --git a/packages/SystemUI/unfold/lint-baseline.xml b/packages/SystemUI/unfold/lint-baseline.xml
new file mode 100644
index 0000000..449ed2e
--- /dev/null
+++ b/packages/SystemUI/unfold/lint-baseline.xml
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<issues format="6" by="lint 7.1.0-dev" type="baseline" client="" name="" variant="all" version="7.1.0-dev">
+</issues>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldSharedComponent.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedComponent.kt
similarity index 79%
rename from packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldSharedComponent.kt
rename to packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedComponent.kt
index 9e5aeb8..a5ec0a4 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldSharedComponent.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedComponent.kt
@@ -16,16 +16,16 @@
package com.android.systemui.unfold
-import android.app.ActivityManager
import android.content.ContentResolver
import android.content.Context
import android.hardware.SensorManager
-import android.hardware.devicestate.DeviceStateManager
import android.os.Handler
-import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.dagger.qualifiers.UiBackground
import com.android.systemui.unfold.config.UnfoldTransitionConfig
+import com.android.systemui.unfold.dagger.UnfoldBackground
+import com.android.systemui.unfold.dagger.UnfoldMain
+import com.android.systemui.unfold.updates.FoldProvider
import com.android.systemui.unfold.updates.screen.ScreenStatusProvider
+import com.android.systemui.unfold.util.CurrentActivityTypeProvider
import com.android.systemui.unfold.util.UnfoldTransitionATracePrefix
import dagger.BindsInstance
import dagger.Component
@@ -51,12 +51,12 @@
@BindsInstance context: Context,
@BindsInstance config: UnfoldTransitionConfig,
@BindsInstance screenStatusProvider: ScreenStatusProvider,
- @BindsInstance deviceStateManager: DeviceStateManager,
- @BindsInstance activityManager: ActivityManager,
+ @BindsInstance foldProvider: FoldProvider,
+ @BindsInstance activityTypeProvider: CurrentActivityTypeProvider,
@BindsInstance sensorManager: SensorManager,
- @BindsInstance @Main handler: Handler,
- @BindsInstance @Main executor: Executor,
- @BindsInstance @UiBackground backgroundExecutor: Executor,
+ @BindsInstance @UnfoldMain handler: Handler,
+ @BindsInstance @UnfoldMain executor: Executor,
+ @BindsInstance @UnfoldBackground backgroundExecutor: Executor,
@BindsInstance @UnfoldTransitionATracePrefix tracingTagPrefix: String,
@BindsInstance contentResolver: ContentResolver = context.contentResolver
): UnfoldSharedComponent
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldSharedModule.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedModule.kt
similarity index 96%
rename from packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldSharedModule.kt
rename to packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedModule.kt
index c612995..8f4ee4d 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldSharedModule.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedModule.kt
@@ -17,8 +17,8 @@
package com.android.systemui.unfold
import android.hardware.SensorManager
-import com.android.systemui.dagger.qualifiers.UiBackground
import com.android.systemui.unfold.config.UnfoldTransitionConfig
+import com.android.systemui.unfold.dagger.UnfoldBackground
import com.android.systemui.unfold.progress.FixedTimingTransitionProgressProvider
import com.android.systemui.unfold.progress.PhysicsBasedUnfoldTransitionProgressProvider
import com.android.systemui.unfold.updates.DeviceFoldStateProvider
@@ -70,7 +70,7 @@
fun hingeAngleProvider(
config: UnfoldTransitionConfig,
sensorManager: SensorManager,
- @UiBackground executor: Executor
+ @UnfoldBackground executor: Executor
): HingeAngleProvider =
if (config.isHingeAngleEnabled) {
HingeSensorAngleProvider(sensorManager, executor)
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt
similarity index 83%
rename from packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt
rename to packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt
index cc56007c..402dd84 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt
@@ -17,14 +17,13 @@
package com.android.systemui.unfold
-import android.app.ActivityManager
import android.content.Context
import android.hardware.SensorManager
-import android.hardware.devicestate.DeviceStateManager
import android.os.Handler
-import com.android.systemui.unfold.config.ResourceUnfoldTransitionConfig
import com.android.systemui.unfold.config.UnfoldTransitionConfig
+import com.android.systemui.unfold.updates.FoldProvider
import com.android.systemui.unfold.updates.screen.ScreenStatusProvider
+import com.android.systemui.unfold.util.CurrentActivityTypeProvider
import java.util.concurrent.Executor
/**
@@ -39,8 +38,8 @@
context: Context,
config: UnfoldTransitionConfig,
screenStatusProvider: ScreenStatusProvider,
- deviceStateManager: DeviceStateManager,
- activityManager: ActivityManager,
+ foldProvider: FoldProvider,
+ activityTypeProvider: CurrentActivityTypeProvider,
sensorManager: SensorManager,
mainHandler: Handler,
mainExecutor: Executor,
@@ -52,8 +51,8 @@
context,
config,
screenStatusProvider,
- deviceStateManager,
- activityManager,
+ foldProvider,
+ activityTypeProvider,
sensorManager,
mainHandler,
mainExecutor,
@@ -64,5 +63,3 @@
?: throw IllegalStateException(
"Trying to create " +
"UnfoldTransitionProgressProvider when the transition is disabled")
-
-fun createConfig(context: Context): UnfoldTransitionConfig = ResourceUnfoldTransitionConfig(context)
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldTransitionProgressProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionProgressProvider.kt
similarity index 93%
rename from packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldTransitionProgressProvider.kt
rename to packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionProgressProvider.kt
index 409dc95..d54481c 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldTransitionProgressProvider.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionProgressProvider.kt
@@ -15,9 +15,9 @@
*/
package com.android.systemui.unfold
-import android.annotation.FloatRange
-import com.android.systemui.statusbar.policy.CallbackController
+import androidx.annotation.FloatRange
import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
+import com.android.systemui.unfold.util.CallbackController
/**
* Interface that allows to receive unfold transition progress updates.
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/compat/ScreenSizeFoldProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/compat/ScreenSizeFoldProvider.kt
new file mode 100644
index 0000000..2044f05
--- /dev/null
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/compat/ScreenSizeFoldProvider.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.unfold.compat
+
+import android.content.Context
+import android.content.res.Configuration
+import com.android.systemui.unfold.updates.FoldProvider
+import com.android.systemui.unfold.updates.FoldProvider.FoldCallback
+import java.util.concurrent.Executor
+
+/**
+ * Fold provider that notifies about fold state based on the screen size
+ * It could be used when no activity context is available
+ * TODO(b/232369816): use Jetpack WM library when non-activity contexts supported b/169740873
+ */
+class ScreenSizeFoldProvider(private val context: Context) : FoldProvider {
+
+ private var callbacks: MutableList<FoldCallback> = arrayListOf()
+ private var lastWidth: Int = 0
+
+ override fun registerCallback(callback: FoldCallback, executor: Executor) {
+ callbacks += callback
+ onConfigurationChange(context.resources.configuration)
+ }
+
+ override fun unregisterCallback(callback: FoldCallback) {
+ callbacks -= callback
+ }
+
+ fun onConfigurationChange(newConfig: Configuration) {
+ if (lastWidth == newConfig.smallestScreenWidthDp) {
+ return
+ }
+
+ if (newConfig.smallestScreenWidthDp > INNER_SCREEN_SMALLEST_SCREEN_WIDTH_THRESHOLD_DP) {
+ callbacks.forEach { it.onFoldUpdated(false) }
+ } else {
+ callbacks.forEach { it.onFoldUpdated(true) }
+ }
+ lastWidth = newConfig.smallestScreenWidthDp
+ }
+}
+
+private const val INNER_SCREEN_SMALLEST_SCREEN_WIDTH_THRESHOLD_DP = 600
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/compat/SizeScreenStatusProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/compat/SizeScreenStatusProvider.kt
new file mode 100644
index 0000000..c405f31
--- /dev/null
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/compat/SizeScreenStatusProvider.kt
@@ -0,0 +1,54 @@
+/*
+ * 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.unfold.compat
+
+import com.android.systemui.unfold.updates.FoldProvider
+import com.android.systemui.unfold.updates.screen.ScreenStatusProvider
+import com.android.systemui.unfold.updates.screen.ScreenStatusProvider.ScreenListener
+import java.util.concurrent.Executor
+
+class SizeScreenStatusProvider(
+ private val foldProvider: FoldProvider,
+ private val executor: Executor
+) : ScreenStatusProvider {
+
+ private val listeners: MutableList<ScreenListener> = arrayListOf()
+ private val callback = object : FoldProvider.FoldCallback {
+ override fun onFoldUpdated(isFolded: Boolean) {
+ if (!isFolded) {
+ listeners.forEach { it.onScreenTurnedOn() }
+ }
+ }
+ }
+
+ fun start() {
+ foldProvider.registerCallback(
+ callback,
+ executor
+ )
+ }
+
+ fun stop() {
+ foldProvider.unregisterCallback(callback)
+ }
+
+ override fun addCallback(listener: ScreenListener) {
+ listeners.add(listener)
+ }
+
+ override fun removeCallback(listener: ScreenListener) {
+ listeners.remove(listener)
+ }
+}
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/config/ResourceUnfoldTransitionConfig.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/config/ResourceUnfoldTransitionConfig.kt
new file mode 100644
index 0000000..c513729
--- /dev/null
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/config/ResourceUnfoldTransitionConfig.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.systemui.unfold.config
+
+import android.content.res.Resources
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class ResourceUnfoldTransitionConfig @Inject constructor() : UnfoldTransitionConfig {
+
+ override val isEnabled: Boolean by lazy {
+ val id = Resources.getSystem()
+ .getIdentifier("config_unfoldTransitionEnabled", "bool", "android")
+ Resources.getSystem().getBoolean(id)
+ }
+
+ override val isHingeAngleEnabled: Boolean by lazy {
+ val id = Resources.getSystem()
+ .getIdentifier("config_unfoldTransitionHingeAngle", "bool", "android")
+ Resources.getSystem().getBoolean(id)
+ }
+
+ override val halfFoldedTimeoutMillis: Int by lazy {
+ val id = Resources.getSystem()
+ .getIdentifier("config_unfoldTransitionHalfFoldedTimeout", "integer", "android")
+ Resources.getSystem().getInteger(id)
+ }
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/config/UnfoldTransitionConfig.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/config/UnfoldTransitionConfig.kt
similarity index 95%
rename from packages/SystemUI/shared/src/com/android/systemui/unfold/config/UnfoldTransitionConfig.kt
rename to packages/SystemUI/unfold/src/com/android/systemui/unfold/config/UnfoldTransitionConfig.kt
index 5b187b3..765e862 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/config/UnfoldTransitionConfig.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/config/UnfoldTransitionConfig.kt
@@ -18,4 +18,5 @@
interface UnfoldTransitionConfig {
val isEnabled: Boolean
val isHingeAngleEnabled: Boolean
+ val halfFoldedTimeoutMillis: Int
}
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/dagger/UnfoldBackground.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/dagger/UnfoldBackground.kt
new file mode 100644
index 0000000..6074795
--- /dev/null
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/dagger/UnfoldBackground.kt
@@ -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.
+ */
+package com.android.systemui.unfold.dagger
+
+import javax.inject.Qualifier
+
+/**
+ * Alternative to [UiBackground] qualifier annotation in unfold module.
+ * It is needed as we can't depend on SystemUI code in this module.
+ */
+@Qualifier
+@Retention(AnnotationRetention.RUNTIME)
+annotation class UnfoldBackground
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/dagger/UnfoldMain.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/dagger/UnfoldMain.kt
new file mode 100644
index 0000000..5553690f
--- /dev/null
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/dagger/UnfoldMain.kt
@@ -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.
+ */
+package com.android.systemui.unfold.dagger
+
+import javax.inject.Qualifier
+
+/**
+ * Alternative to [Main] qualifier annotation in unfold module.
+ * It is needed as we can't depend on SystemUI code in this module.
+ */
+@Qualifier
+@Retention(AnnotationRetention.RUNTIME)
+annotation class UnfoldMain
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/progress/FixedTimingTransitionProgressProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/FixedTimingTransitionProgressProvider.kt
similarity index 100%
rename from packages/SystemUI/shared/src/com/android/systemui/unfold/progress/FixedTimingTransitionProgressProvider.kt
rename to packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/FixedTimingTransitionProgressProvider.kt
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt
similarity index 97%
rename from packages/SystemUI/shared/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt
rename to packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt
index 04d920c..2ab28c6 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt
@@ -16,7 +16,6 @@
package com.android.systemui.unfold.progress
import android.util.Log
-import android.util.MathUtils.saturate
import androidx.dynamicanimation.animation.DynamicAnimation
import androidx.dynamicanimation.animation.FloatPropertyCompat
import androidx.dynamicanimation.animation.SpringAnimation
@@ -70,6 +69,9 @@
springAnimation.animateToFinalPosition(progress)
}
+ private fun saturate(amount: Float, low: Float = 0f, high: Float = 1f): Float =
+ if (amount < low) low else if (amount > high) high else amount
+
override fun onFoldUpdate(@FoldUpdate update: Int) {
when (update) {
FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE -> {
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
similarity index 74%
rename from packages/SystemUI/shared/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
rename to packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
index 14581cc..e8038fd 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
@@ -15,46 +15,46 @@
*/
package com.android.systemui.unfold.updates
-import android.annotation.FloatRange
-import android.app.ActivityManager
-import android.app.WindowConfiguration.ACTIVITY_TYPE_HOME
-import android.content.Context
-import android.hardware.devicestate.DeviceStateManager
import android.os.Handler
import android.util.Log
+import androidx.annotation.FloatRange
import androidx.annotation.VisibleForTesting
import androidx.core.util.Consumer
-import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.unfold.config.UnfoldTransitionConfig
+import com.android.systemui.unfold.dagger.UnfoldMain
import com.android.systemui.unfold.updates.FoldStateProvider.FoldUpdate
import com.android.systemui.unfold.updates.FoldStateProvider.FoldUpdatesListener
import com.android.systemui.unfold.updates.hinge.FULLY_CLOSED_DEGREES
import com.android.systemui.unfold.updates.hinge.FULLY_OPEN_DEGREES
import com.android.systemui.unfold.updates.hinge.HingeAngleProvider
import com.android.systemui.unfold.updates.screen.ScreenStatusProvider
+import com.android.systemui.unfold.util.CurrentActivityTypeProvider
import java.util.concurrent.Executor
import javax.inject.Inject
class DeviceFoldStateProvider
@Inject
constructor(
- context: Context,
+ config: UnfoldTransitionConfig,
private val hingeAngleProvider: HingeAngleProvider,
private val screenStatusProvider: ScreenStatusProvider,
- private val deviceStateManager: DeviceStateManager,
- private val activityManager: ActivityManager,
- @Main private val mainExecutor: Executor,
- @Main private val handler: Handler
+ private val foldProvider: FoldProvider,
+ private val activityTypeProvider: CurrentActivityTypeProvider,
+ @UnfoldMain private val mainExecutor: Executor,
+ @UnfoldMain private val handler: Handler
) : FoldStateProvider {
private val outputListeners: MutableList<FoldUpdatesListener> = mutableListOf()
- @FoldUpdate private var lastFoldUpdate: Int? = null
+ @FoldUpdate
+ private var lastFoldUpdate: Int? = null
- @FloatRange(from = 0.0, to = 180.0) private var lastHingeAngle: Float = 0f
+ @FloatRange(from = 0.0, to = 180.0)
+ private var lastHingeAngle: Float = 0f
private val hingeAngleListener = HingeAngleListener()
private val screenListener = ScreenStatusListener()
- private val foldStateListener = FoldStateListener(context)
+ private val foldStateListener = FoldStateListener()
private val timeoutRunnable = TimeoutRunnable()
/**
@@ -62,22 +62,20 @@
* [FOLD_UPDATE_START_CLOSING] or [FOLD_UPDATE_START_OPENING] event, if an end state is not
* reached.
*/
- private val halfOpenedTimeoutMillis: Int =
- context.resources.getInteger(
- com.android.internal.R.integer.config_unfoldTransitionHalfFoldedTimeout)
+ private val halfOpenedTimeoutMillis: Int = config.halfFoldedTimeoutMillis
private var isFolded = false
private var isUnfoldHandled = true
override fun start() {
- deviceStateManager.registerCallback(mainExecutor, foldStateListener)
+ foldProvider.registerCallback(foldStateListener, mainExecutor)
screenStatusProvider.addCallback(screenListener)
hingeAngleProvider.addCallback(hingeAngleListener)
}
override fun stop() {
screenStatusProvider.removeCallback(screenListener)
- deviceStateManager.unregisterCallback(foldStateListener)
+ foldProvider.unregisterCallback(foldStateListener)
hingeAngleProvider.removeCallback(hingeAngleListener)
hingeAngleProvider.stop()
}
@@ -92,13 +90,13 @@
override val isFinishedOpening: Boolean
get() = !isFolded &&
- (lastFoldUpdate == FOLD_UPDATE_FINISH_FULL_OPEN ||
- lastFoldUpdate == FOLD_UPDATE_FINISH_HALF_OPEN)
+ (lastFoldUpdate == FOLD_UPDATE_FINISH_FULL_OPEN ||
+ lastFoldUpdate == FOLD_UPDATE_FINISH_HALF_OPEN)
private val isTransitionInProgress: Boolean
get() =
lastFoldUpdate == FOLD_UPDATE_START_OPENING ||
- lastFoldUpdate == FOLD_UPDATE_START_CLOSING
+ lastFoldUpdate == FOLD_UPDATE_START_CLOSING
private fun onHingeAngle(angle: Float) {
if (DEBUG) {
@@ -136,39 +134,36 @@
* apps that support table-top/HALF_FOLDED mode. Only for launcher, there is no threshold.
*/
private fun getClosingThreshold(): Int? {
- val activityType =
- activityManager.getRunningTasks(/* maxNum= */ 1)?.getOrNull(0)?.topActivityType
- ?: return null
+ val isHomeActivity = activityTypeProvider.isHomeActivity ?: return null
if (DEBUG) {
- Log.d(TAG, "activityType=" + activityType)
+ Log.d(TAG, "isHomeActivity=$isHomeActivity")
}
- return if (activityType == ACTIVITY_TYPE_HOME) {
+ return if (isHomeActivity) {
null
} else {
START_CLOSING_ON_APPS_THRESHOLD_DEGREES
}
}
- private inner class FoldStateListener(context: Context) :
- DeviceStateManager.FoldStateListener(
- context,
- { folded: Boolean ->
- isFolded = folded
- lastHingeAngle = FULLY_CLOSED_DEGREES
+ private inner class FoldStateListener : FoldProvider.FoldCallback {
+ override fun onFoldUpdated(isFolded: Boolean) {
+ this@DeviceFoldStateProvider.isFolded = isFolded
+ lastHingeAngle = FULLY_CLOSED_DEGREES
- if (folded) {
- hingeAngleProvider.stop()
- notifyFoldUpdate(FOLD_UPDATE_FINISH_CLOSED)
- cancelTimeout()
- isUnfoldHandled = false
- } else {
- notifyFoldUpdate(FOLD_UPDATE_START_OPENING)
- rescheduleAbortAnimationTimeout()
- hingeAngleProvider.start()
- }
- })
+ if (isFolded) {
+ hingeAngleProvider.stop()
+ notifyFoldUpdate(FOLD_UPDATE_FINISH_CLOSED)
+ cancelTimeout()
+ isUnfoldHandled = false
+ } else {
+ notifyFoldUpdate(FOLD_UPDATE_START_OPENING)
+ rescheduleAbortAnimationTimeout()
+ hingeAngleProvider.start()
+ }
+ }
+ }
private fun notifyFoldUpdate(@FoldUpdate update: Int) {
if (DEBUG) {
@@ -234,7 +229,9 @@
private const val DEBUG = false
/** Threshold after which we consider the device fully unfolded. */
-@VisibleForTesting const val FULLY_OPEN_THRESHOLD_DEGREES = 15f
+@VisibleForTesting
+const val FULLY_OPEN_THRESHOLD_DEGREES = 15f
/** Fold animation on top of apps only when the angle exceeds this threshold. */
-@VisibleForTesting const val START_CLOSING_ON_APPS_THRESHOLD_DEGREES = 60
+@VisibleForTesting
+const val START_CLOSING_ON_APPS_THRESHOLD_DEGREES = 60
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/FoldProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/FoldProvider.kt
new file mode 100644
index 0000000..6e87bee
--- /dev/null
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/FoldProvider.kt
@@ -0,0 +1,26 @@
+/*
+ * 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.unfold.updates
+
+import java.util.concurrent.Executor
+
+interface FoldProvider {
+ fun registerCallback(callback: FoldCallback, executor: Executor)
+ fun unregisterCallback(callback: FoldCallback)
+
+ interface FoldCallback {
+ fun onFoldUpdated(isFolded: Boolean)
+ }
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/FoldStateProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/FoldStateProvider.kt
similarity index 91%
rename from packages/SystemUI/shared/src/com/android/systemui/unfold/updates/FoldStateProvider.kt
rename to packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/FoldStateProvider.kt
index 14a3a70..c7a8bf3 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/FoldStateProvider.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/FoldStateProvider.kt
@@ -15,10 +15,10 @@
*/
package com.android.systemui.unfold.updates
-import android.annotation.FloatRange
-import android.annotation.IntDef
-import com.android.systemui.statusbar.policy.CallbackController
+import androidx.annotation.FloatRange
+import androidx.annotation.IntDef
import com.android.systemui.unfold.updates.FoldStateProvider.FoldUpdatesListener
+import com.android.systemui.unfold.util.CallbackController
/**
* Allows to subscribe to main events related to fold/unfold process such as hinge angle update,
@@ -36,7 +36,6 @@
}
@IntDef(
- prefix = ["FOLD_UPDATE_"],
value =
[
FOLD_UPDATE_START_OPENING,
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/hinge/EmptyHingeAngleProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/hinge/EmptyHingeAngleProvider.kt
new file mode 100644
index 0000000..e985506
--- /dev/null
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/hinge/EmptyHingeAngleProvider.kt
@@ -0,0 +1,27 @@
+/*
+ * 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.unfold.updates.hinge
+
+import androidx.core.util.Consumer
+
+internal object EmptyHingeAngleProvider : HingeAngleProvider {
+ override fun start() {}
+
+ override fun stop() {}
+
+ override fun removeCallback(listener: Consumer<Float>) {}
+
+ override fun addCallback(listener: Consumer<Float>) {}
+}
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/hinge/HingeAngleProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/hinge/HingeAngleProvider.kt
new file mode 100644
index 0000000..e464c3f
--- /dev/null
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/hinge/HingeAngleProvider.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.unfold.updates.hinge
+
+import androidx.core.util.Consumer
+import com.android.systemui.unfold.util.CallbackController
+
+/**
+ * Emits device hinge angle values (angle between two integral parts of the device).
+ *
+ * The hinge angle could be from 0 to 360 degrees inclusive. For foldable devices usually 0
+ * corresponds to fully closed (folded) state and 180 degrees corresponds to fully open (flat)
+ * state.
+ */
+interface HingeAngleProvider : CallbackController<Consumer<Float>> {
+ fun start()
+ fun stop()
+}
+
+const val FULLY_OPEN_DEGREES = 180f
+const val FULLY_CLOSED_DEGREES = 0f
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/hinge/HingeSensorAngleProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/hinge/HingeSensorAngleProvider.kt
similarity index 71%
rename from packages/SystemUI/shared/src/com/android/systemui/unfold/updates/hinge/HingeSensorAngleProvider.kt
rename to packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/hinge/HingeSensorAngleProvider.kt
index c93412b..3fc5d61 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/hinge/HingeSensorAngleProvider.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/hinge/HingeSensorAngleProvider.kt
@@ -1,3 +1,17 @@
+/*
+ * 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.unfold.updates.hinge
import android.hardware.Sensor
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/screen/ScreenStatusProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/screen/ScreenStatusProvider.kt
similarity index 93%
rename from packages/SystemUI/shared/src/com/android/systemui/unfold/updates/screen/ScreenStatusProvider.kt
rename to packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/screen/ScreenStatusProvider.kt
index 668c694..d95e050 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/screen/ScreenStatusProvider.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/screen/ScreenStatusProvider.kt
@@ -15,8 +15,8 @@
*/
package com.android.systemui.unfold.updates.screen
-import com.android.systemui.statusbar.policy.CallbackController
import com.android.systemui.unfold.updates.screen.ScreenStatusProvider.ScreenListener
+import com.android.systemui.unfold.util.CallbackController
interface ScreenStatusProvider : CallbackController<ScreenListener> {
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/util/ATraceLoggerTransitionProgressListener.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/util/ATraceLoggerTransitionProgressListener.kt
similarity index 65%
rename from packages/SystemUI/shared/src/com/android/systemui/unfold/util/ATraceLoggerTransitionProgressListener.kt
rename to packages/SystemUI/unfold/src/com/android/systemui/unfold/util/ATraceLoggerTransitionProgressListener.kt
index 1574c8d..d8bc018 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/util/ATraceLoggerTransitionProgressListener.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/util/ATraceLoggerTransitionProgressListener.kt
@@ -1,3 +1,17 @@
+/*
+ * 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.unfold.util
import android.os.Trace
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/util/CallbackController.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/util/CallbackController.kt
new file mode 100644
index 0000000..46ad534
--- /dev/null
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/util/CallbackController.kt
@@ -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.
+ */
+package com.android.systemui.unfold.util
+
+interface CallbackController<T> {
+ fun addCallback(listener: T)
+ fun removeCallback(listener: T)
+}
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/util/CurrentActivityTypeProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/util/CurrentActivityTypeProvider.kt
new file mode 100644
index 0000000..d0e6cdc
--- /dev/null
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/util/CurrentActivityTypeProvider.kt
@@ -0,0 +1,22 @@
+/*
+ * 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.unfold.util
+
+interface CurrentActivityTypeProvider {
+ val isHomeActivity: Boolean?
+}
+
+class EmptyCurrentActivityTypeProvider(override val isHomeActivity: Boolean? = null) :
+ CurrentActivityTypeProvider
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/util/ScaleAwareTransitionProgressProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/util/ScaleAwareTransitionProgressProvider.kt
similarity index 78%
rename from packages/SystemUI/shared/src/com/android/systemui/unfold/util/ScaleAwareTransitionProgressProvider.kt
rename to packages/SystemUI/unfold/src/com/android/systemui/unfold/util/ScaleAwareTransitionProgressProvider.kt
index dfe8792..5c92b34 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/util/ScaleAwareTransitionProgressProvider.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/util/ScaleAwareTransitionProgressProvider.kt
@@ -1,3 +1,17 @@
+/*
+ * 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.unfold.util
import android.animation.ValueAnimator
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/util/ScopedUnfoldTransitionProgressProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/util/ScopedUnfoldTransitionProgressProvider.kt
similarity index 100%
rename from packages/SystemUI/shared/src/com/android/systemui/unfold/util/ScopedUnfoldTransitionProgressProvider.kt
rename to packages/SystemUI/unfold/src/com/android/systemui/unfold/util/ScopedUnfoldTransitionProgressProvider.kt
diff --git a/packages/VpnDialogs/res/values-gl/strings.xml b/packages/VpnDialogs/res/values-gl/strings.xml
index cd8ee8d..08ab9ae 100644
--- a/packages/VpnDialogs/res/values-gl/strings.xml
+++ b/packages/VpnDialogs/res/values-gl/strings.xml
@@ -33,5 +33,5 @@
<string name="configure" msgid="4905518375574791375">"Configurar"</string>
<string name="disconnect" msgid="971412338304200056">"Desconectar"</string>
<string name="open_app" msgid="3717639178595958667">"Abrir aplicación"</string>
- <string name="dismiss" msgid="6192859333764711227">"Ignorar"</string>
+ <string name="dismiss" msgid="6192859333764711227">"Pechar"</string>
</resources>
diff --git a/packages/VpnDialogs/res/values-km/strings.xml b/packages/VpnDialogs/res/values-km/strings.xml
index 0ed2e84b..de18aba 100644
--- a/packages/VpnDialogs/res/values-km/strings.xml
+++ b/packages/VpnDialogs/res/values-km/strings.xml
@@ -33,5 +33,5 @@
<string name="configure" msgid="4905518375574791375">"កំណត់រចនាសម្ព័ន្ធ"</string>
<string name="disconnect" msgid="971412338304200056">"ផ្ដាច់"</string>
<string name="open_app" msgid="3717639178595958667">"បើកកម្មវិធី"</string>
- <string name="dismiss" msgid="6192859333764711227">"បដិសេធ"</string>
+ <string name="dismiss" msgid="6192859333764711227">"ច្រានចោល"</string>
</resources>
diff --git a/packages/VpnDialogs/res/values-sq/strings.xml b/packages/VpnDialogs/res/values-sq/strings.xml
index 0b4ce4df..eb73baa 100644
--- a/packages/VpnDialogs/res/values-sq/strings.xml
+++ b/packages/VpnDialogs/res/values-sq/strings.xml
@@ -33,5 +33,5 @@
<string name="configure" msgid="4905518375574791375">"Konfiguro"</string>
<string name="disconnect" msgid="971412338304200056">"Shkëputu"</string>
<string name="open_app" msgid="3717639178595958667">"Hap aplikacionin"</string>
- <string name="dismiss" msgid="6192859333764711227">"Largoje"</string>
+ <string name="dismiss" msgid="6192859333764711227">"Hiq"</string>
</resources>
diff --git a/packages/overlays/NavigationBarModeGesturalOverlay/res/values/dimens.xml b/packages/overlays/NavigationBarModeGesturalOverlay/res/values/dimens.xml
index ac1f022..674bc74 100644
--- a/packages/overlays/NavigationBarModeGesturalOverlay/res/values/dimens.xml
+++ b/packages/overlays/NavigationBarModeGesturalOverlay/res/values/dimens.xml
@@ -18,11 +18,11 @@
-->
<resources>
<!-- Height of the bottom navigation / system bar. -->
- <dimen name="navigation_bar_height">16dp</dimen>
+ <dimen name="navigation_bar_height">24dp</dimen>
<!-- Height of the bottom navigation bar in portrait; often the same as @dimen/navigation_bar_height -->
- <dimen name="navigation_bar_height_landscape">16dp</dimen>
+ <dimen name="navigation_bar_height_landscape">24dp</dimen>
<!-- Width of the navigation bar when it is placed vertically on the screen -->
- <dimen name="navigation_bar_width">16dp</dimen>
+ <dimen name="navigation_bar_width">24dp</dimen>
<!-- Height of the bottom navigation / system bar. -->
<dimen name="navigation_bar_frame_height">48dp</dimen>
<!-- The height of the bottom navigation gesture area. -->
diff --git a/packages/overlays/NavigationBarModeGesturalOverlayExtraWideBack/res/values/dimens.xml b/packages/overlays/NavigationBarModeGesturalOverlayExtraWideBack/res/values/dimens.xml
index ac1f022..674bc74 100644
--- a/packages/overlays/NavigationBarModeGesturalOverlayExtraWideBack/res/values/dimens.xml
+++ b/packages/overlays/NavigationBarModeGesturalOverlayExtraWideBack/res/values/dimens.xml
@@ -18,11 +18,11 @@
-->
<resources>
<!-- Height of the bottom navigation / system bar. -->
- <dimen name="navigation_bar_height">16dp</dimen>
+ <dimen name="navigation_bar_height">24dp</dimen>
<!-- Height of the bottom navigation bar in portrait; often the same as @dimen/navigation_bar_height -->
- <dimen name="navigation_bar_height_landscape">16dp</dimen>
+ <dimen name="navigation_bar_height_landscape">24dp</dimen>
<!-- Width of the navigation bar when it is placed vertically on the screen -->
- <dimen name="navigation_bar_width">16dp</dimen>
+ <dimen name="navigation_bar_width">24dp</dimen>
<!-- Height of the bottom navigation / system bar. -->
<dimen name="navigation_bar_frame_height">48dp</dimen>
<!-- The height of the bottom navigation gesture area. -->
diff --git a/packages/overlays/NavigationBarModeGesturalOverlayNarrowBack/res/values/dimens.xml b/packages/overlays/NavigationBarModeGesturalOverlayNarrowBack/res/values/dimens.xml
index ac1f022..674bc74 100644
--- a/packages/overlays/NavigationBarModeGesturalOverlayNarrowBack/res/values/dimens.xml
+++ b/packages/overlays/NavigationBarModeGesturalOverlayNarrowBack/res/values/dimens.xml
@@ -18,11 +18,11 @@
-->
<resources>
<!-- Height of the bottom navigation / system bar. -->
- <dimen name="navigation_bar_height">16dp</dimen>
+ <dimen name="navigation_bar_height">24dp</dimen>
<!-- Height of the bottom navigation bar in portrait; often the same as @dimen/navigation_bar_height -->
- <dimen name="navigation_bar_height_landscape">16dp</dimen>
+ <dimen name="navigation_bar_height_landscape">24dp</dimen>
<!-- Width of the navigation bar when it is placed vertically on the screen -->
- <dimen name="navigation_bar_width">16dp</dimen>
+ <dimen name="navigation_bar_width">24dp</dimen>
<!-- Height of the bottom navigation / system bar. -->
<dimen name="navigation_bar_frame_height">48dp</dimen>
<!-- The height of the bottom navigation gesture area. -->
diff --git a/packages/overlays/NavigationBarModeGesturalOverlayWideBack/res/values/dimens.xml b/packages/overlays/NavigationBarModeGesturalOverlayWideBack/res/values/dimens.xml
index ac1f022..674bc74 100644
--- a/packages/overlays/NavigationBarModeGesturalOverlayWideBack/res/values/dimens.xml
+++ b/packages/overlays/NavigationBarModeGesturalOverlayWideBack/res/values/dimens.xml
@@ -18,11 +18,11 @@
-->
<resources>
<!-- Height of the bottom navigation / system bar. -->
- <dimen name="navigation_bar_height">16dp</dimen>
+ <dimen name="navigation_bar_height">24dp</dimen>
<!-- Height of the bottom navigation bar in portrait; often the same as @dimen/navigation_bar_height -->
- <dimen name="navigation_bar_height_landscape">16dp</dimen>
+ <dimen name="navigation_bar_height_landscape">24dp</dimen>
<!-- Width of the navigation bar when it is placed vertically on the screen -->
- <dimen name="navigation_bar_width">16dp</dimen>
+ <dimen name="navigation_bar_width">24dp</dimen>
<!-- Height of the bottom navigation / system bar. -->
<dimen name="navigation_bar_frame_height">48dp</dimen>
<!-- The height of the bottom navigation gesture area. -->
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index d5bd188..17dfc7b 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -2038,15 +2038,6 @@
}
}
}
- final AutofillId[] fieldClassificationIds = lastResponse.getFieldClassificationIds();
-
- if (!hasAtLeastOneDataset && fieldClassificationIds == null) {
- if (sVerbose) {
- Slog.v(TAG, "logContextCommittedLocked(): skipped (no datasets nor fields "
- + "classification ids)");
- }
- return;
- }
for (int i = 0; i < mViewStates.size(); i++) {
final ViewState viewState = mViewStates.valueAt(i);
@@ -2095,6 +2086,7 @@
}
continue;
}
+
// Check if value match a dataset.
if (hasAtLeastOneDataset) {
for (int j = 0; j < responseCount; j++) {
@@ -2151,7 +2143,6 @@
} // else
} // for j
}
-
} // else
} // else
}
diff --git a/services/backup/backuplib/java/com/android/server/backup/transport/TransportStatusCallback.java b/services/backup/backuplib/java/com/android/server/backup/transport/TransportStatusCallback.java
index bc5cb02..99526b7 100644
--- a/services/backup/backuplib/java/com/android/server/backup/transport/TransportStatusCallback.java
+++ b/services/backup/backuplib/java/com/android/server/backup/transport/TransportStatusCallback.java
@@ -26,7 +26,7 @@
public class TransportStatusCallback extends ITransportStatusCallback.Stub {
private static final String TAG = "TransportStatusCallback";
- private static final int TIMEOUT_MILLIS = 600 * 1000; // 10 minutes.
+ private static final int TIMEOUT_MILLIS = 300 * 1000; // 5 minutes.
private static final int OPERATION_STATUS_DEFAULT = 0;
private final int mOperationTimeout;
diff --git a/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java b/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java
index 47d2640..5457ef9 100644
--- a/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java
+++ b/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java
@@ -182,7 +182,7 @@
// 2b.1. Populate the request with required info.
request.setPackageName(packageName);
request.setUserId(userId);
- request.setSkipPrompt(mayAssociateWithoutPrompt(request, packageName, userId));
+ request.setSkipPrompt(mayAssociateWithoutPrompt(packageName, userId));
// 2b.2. Prepare extras and create an Intent.
final Bundle extras = new Bundle();
@@ -321,18 +321,7 @@
}
};
- private boolean mayAssociateWithoutPrompt(@NonNull AssociationRequest request,
- @NonNull String packageName, @UserIdInt int userId) {
- final String deviceProfile = request.getDeviceProfile();
- if (deviceProfile != null) {
- final boolean isRoleHolder = Binder.withCleanCallingIdentity(
- () -> isRoleHolder(mContext, userId, packageName, deviceProfile));
- if (isRoleHolder) {
- // Don't need to collect user's consent since app already holds the role.
- return true;
- }
- }
-
+ private boolean mayAssociateWithoutPrompt(@NonNull String packageName, @UserIdInt int userId) {
// Below we check if the requesting package is allowlisted (usually by the OEM) for creating
// CDM associations without user confirmation (prompt).
// For this we'll check to config arrays:
diff --git a/services/companion/java/com/android/server/companion/CompanionApplicationController.java b/services/companion/java/com/android/server/companion/CompanionApplicationController.java
index 943599c..0deb039 100644
--- a/services/companion/java/com/android/server/companion/CompanionApplicationController.java
+++ b/services/companion/java/com/android/server/companion/CompanionApplicationController.java
@@ -103,7 +103,10 @@
mCompanionServicesRegister.invalidate(userId);
}
- void bindCompanionApplication(@UserIdInt int userId, @NonNull String packageName,
+ /**
+ * CDM binds to the companion app.
+ */
+ public void bindCompanionApplication(@UserIdInt int userId, @NonNull String packageName,
boolean bindImportant) {
if (DEBUG) {
Log.i(TAG, "bind() u" + userId + "/" + packageName
@@ -143,7 +146,10 @@
}
}
- void unbindCompanionApplication(@UserIdInt int userId, @NonNull String packageName) {
+ /**
+ * CDM unbinds the companion app.
+ */
+ public void unbindCompanionApplication(@UserIdInt int userId, @NonNull String packageName) {
if (DEBUG) Log.i(TAG, "unbind() u" + userId + "/" + packageName);
final List<CompanionDeviceServiceConnector> serviceConnectors;
@@ -237,9 +243,9 @@
primaryServiceConnector.postOnDeviceDisappeared(association);
}
- /** Pass an encryped secure message to the companion application for transporting. */
+ /** Pass an encrypted secure message to the companion application for transporting. */
public void dispatchMessage(@UserIdInt int userId, @NonNull String packageName,
- int associationId, @NonNull byte[] message) {
+ int associationId, int messageId, @NonNull byte[] message) {
if (DEBUG) {
Log.i(TAG, "dispatchMessage() u" + userId + "/" + packageName
+ " associationId=" + associationId);
@@ -256,7 +262,8 @@
return;
}
- primaryServiceConnector.postOnMessageDispatchedFromSystem(associationId, message);
+ primaryServiceConnector.postOnMessageDispatchedFromSystem(associationId, messageId,
+ message);
}
private void onPrimaryServiceBindingDied(@UserIdInt int userId, @NonNull String packageName) {
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index fce7bad..7af629c 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -78,6 +78,7 @@
import android.os.ResultReceiver;
import android.os.ServiceManager;
import android.os.ShellCallback;
+import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.ArraySet;
@@ -126,8 +127,10 @@
private static final String PREF_FILE_NAME = "companion_device_preferences.xml";
private static final String PREF_KEY_AUTO_REVOKE_GRANTS_DONE = "auto_revoke_grants_done";
+ private static final String SYS_PROP_DEBUG_REMOVAL_TIME_WINDOW =
+ "debug.cdm.cdmservice.removal_time_window";
- private static final long ASSOCIATION_CLEAN_UP_TIME_WINDOW = DAYS.toMillis(3 * 30); // 3 months
+ private static final long ASSOCIATION_REMOVAL_TIME_WINDOW_DEFAULT = DAYS.toMillis(90);
private PersistentDataStore mPersistentStore;
private final PersistUserStateHandler mUserPersistenceHandler;
@@ -226,8 +229,8 @@
mPackageMonitor.register(context, FgThread.get().getLooper(), UserHandle.ALL, true);
mDevicePresenceMonitor.init(context);
} else if (phase == PHASE_BOOT_COMPLETED) {
- // Run the Association CleanUp job service daily.
- AssociationCleanUpService.schedule(getContext());
+ // Run the Inactive Association Removal job service daily.
+ InactiveAssociationsRemovalService.schedule(getContext());
}
}
@@ -307,14 +310,13 @@
private boolean onCompanionApplicationBindingDiedInternal(
@UserIdInt int userId, @NonNull String packageName) {
- // Update the current connected devices sets when binderDied, so that application is able
- // to call notifyDeviceAppeared after re-launch the application.
for (AssociationInfo ai :
mAssociationStore.getAssociationsForPackage(userId, packageName)) {
- int id = ai.getId();
- Slog.i(TAG, "Removing association id: " + id + " for package: "
- + packageName + " due to binderDied.");
- mDevicePresenceMonitor.removeDeviceFromMonitoring(id);
+ final int associationId = ai.getId();
+ if (ai.isSelfManaged()
+ && mDevicePresenceMonitor.isDevicePresent(associationId)) {
+ mDevicePresenceMonitor.onSelfManagedDeviceReporterBinderDied(associationId);
+ }
}
// TODO(b/218613015): implement.
return false;
@@ -426,17 +428,20 @@
mCompanionAppController.onPackagesChanged(userId);
}
- // Revoke associations if the selfManaged companion device does not connect for 3
- // months for specific profile.
- private void associationCleanUp(String profile) {
+ // Revoke associations if the selfManaged companion device does not connect for 3 months.
+ void removeInactiveSelfManagedAssociations() {
+ final long currentTime = System.currentTimeMillis();
+ long removalWindow = SystemProperties.getLong(SYS_PROP_DEBUG_REMOVAL_TIME_WINDOW, -1);
+ if (removalWindow <= 0) {
+ // 0 or negative values indicate that the sysprop was never set or should be ignored.
+ removalWindow = ASSOCIATION_REMOVAL_TIME_WINDOW_DEFAULT;
+ }
+
for (AssociationInfo ai : mAssociationStore.getAssociations()) {
- if (ai.isSelfManaged()
- && profile.equals(ai.getDeviceProfile())
- && System.currentTimeMillis() - ai.getLastTimeConnectedMs()
- >= ASSOCIATION_CLEAN_UP_TIME_WINDOW) {
- Slog.i(TAG, "Removing the association for associationId: "
- + ai.getId()
- + " due to the device does not connect for 3 months.");
+ if (!ai.isSelfManaged()) continue;
+ final boolean isInactive = currentTime - ai.getLastTimeConnectedMs() >= removalWindow;
+ if (isInactive) {
+ Slog.i(TAG, "Removing inactive self-managed association: " + ai.getId());
disassociateInternal(ai.getId());
}
}
@@ -616,7 +621,15 @@
+ " message(Base64)=" + Base64.encodeToString(message, 0));
}
- mSecureCommsManager.receiveSecureMessage(associationId, message);
+ AssociationInfo association = getAssociationWithCallerChecks(associationId);
+ if (association == null) {
+ throw new IllegalArgumentException("Association with ID " + associationId + " "
+ + "does not exist "
+ + "or belongs to a different package "
+ + "or belongs to a different user");
+ }
+
+ mSecureCommsManager.receiveSecureMessage(messageId, associationId, message);
}
@Override
@@ -682,6 +695,12 @@
private void registerDevicePresenceListenerActive(String packageName, String deviceAddress,
boolean active) throws RemoteException {
+ if (DEBUG) {
+ Log.i(TAG, "registerDevicePresenceListenerActive()"
+ + " active=" + active
+ + " deviceAddress=" + deviceAddress);
+ }
+
getContext().enforceCallingOrSelfPermission(
android.Manifest.permission.REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE,
"[un]registerDevicePresenceListenerService");
@@ -697,6 +716,12 @@
+ " for user " + userId));
}
+ // If already at specified state, then no-op.
+ if (active == association.isNotifyOnDeviceNearby()) {
+ if (DEBUG) Log.d(TAG, "Device presence listener is already at desired state.");
+ return;
+ }
+
// AssociationInfo class is immutable: create a new AssociationInfo object with updated
// flag.
association = AssociationInfo.builder(association)
@@ -707,7 +732,17 @@
// an application sets/unsets the mNotifyOnDeviceNearby flag.
mAssociationStore.updateAssociation(association);
- // TODO(b/218615198): correctly handle the case when the device is currently present.
+ // If device is already present, then trigger callback.
+ if (active && mDevicePresenceMonitor.isDevicePresent(association.getId())) {
+ if (DEBUG) Log.d(TAG, "Device is already present. Triggering callback.");
+ onDeviceAppearedInternal(association.getId());
+ }
+
+ // If last listener is unregistered, then unbind application.
+ if (!active && !shouldBindPackage(userId, packageName)) {
+ if (DEBUG) Log.d(TAG, "Last listener unregistered. Unbinding application.");
+ mCompanionAppController.unbindCompanionApplication(userId, packageName);
+ }
}
@Override
@@ -1092,10 +1127,10 @@
return ArrayUtils.contains(array, a) || ArrayUtils.contains(array, b);
}
- private class LocalService extends CompanionDeviceManagerServiceInternal {
+ private class LocalService implements CompanionDeviceManagerServiceInternal {
@Override
- public void associationCleanUp(String profile) {
- CompanionDeviceManagerService.this.associationCleanUp(profile);
+ public void removeInactiveSelfManagedAssociations() {
+ CompanionDeviceManagerService.this.removeInactiveSelfManagedAssociations();
}
}
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerServiceInternal.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerServiceInternal.java
index 326fefe..3649240 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerServiceInternal.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerServiceInternal.java
@@ -18,12 +18,10 @@
/**
* Companion Device Manager Local System Service Interface.
- *
- * @hide Only for use within the system server.
*/
-public abstract class CompanionDeviceManagerServiceInternal {
+interface CompanionDeviceManagerServiceInternal {
/**
- * @see CompanionDeviceManagerService#associationCleanUp
+ * @see CompanionDeviceManagerService#removeInactiveSelfManagedAssociations
*/
- public abstract void associationCleanUp(String profile);
+ void removeInactiveSelfManagedAssociations();
}
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceServiceConnector.java b/services/companion/java/com/android/server/companion/CompanionDeviceServiceConnector.java
index ef39b4b..b9b29ff 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceServiceConnector.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceServiceConnector.java
@@ -98,15 +98,10 @@
post(companionService -> companionService.onDeviceDisappeared(associationInfo));
}
- void postOnMessageDispatchedFromSystem(int associationId, @NonNull byte[] message) {
- // We always use messageId 0 (at least for now).
- // Unlike the message itself, the messageId is not encoded, which means that the CDM on the
- // other (receiving) end CAN NOT and MUST NOT trust this messageId.
- // If CDM needs to pass messageId around to the other side - it should embed it in the
- // message body.
+ void postOnMessageDispatchedFromSystem(int associationId, int messageId,
+ @NonNull byte[] message) {
post(companionService ->
- companionService.onMessageDispatchedFromSystem(
- /* messageId*/ 0, associationId, message));
+ companionService.onMessageDispatchedFromSystem(messageId, associationId, message));
}
/**
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java b/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
index 9e5be40..0b7bc03 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
@@ -19,6 +19,7 @@
import static java.nio.charset.StandardCharsets.UTF_8;
import android.companion.AssociationInfo;
+import android.os.Binder;
import android.os.ShellCommand;
import android.util.Base64;
@@ -113,7 +114,8 @@
message = sb.toString().getBytes(UTF_8);
}
- mSecureCommsManager.sendSecureMessage(associationId, message);
+ mSecureCommsManager.sendSecureMessage(associationId, /* messageId */ 0,
+ message);
break;
case "simulate-device-appeared":
@@ -126,6 +128,16 @@
mDevicePresenceMonitor.simulateDeviceDisappeared(associationId);
break;
+ case "remove-inactive-associations": {
+ // This command should trigger the same "clean-up" job as performed by the
+ // InactiveAssociationsRemovalService JobService. However, since the
+ // InactiveAssociationsRemovalService run as system, we want to run this
+ // as system (not as shell/root) as well.
+ Binder.withCleanCallingIdentity(
+ mService::removeInactiveSelfManagedAssociations);
+ }
+ break;
+
default:
return handleDefaultCommands(cmd);
}
@@ -180,5 +192,11 @@
pw.println(" invoked for the same device (same ASSOCIATION_ID) no longer than");
pw.println(" 60 seconds ago.");
pw.println(" USE FOR DEBUGGING AND/OR TESTING PURPOSES ONLY.");
+
+ pw.println(" remove-inactive-associations");
+ pw.println(" Remove self-managed associations that have not been active ");
+ pw.println(" for a long time (90 days or as configured via ");
+ pw.println(" \"debug.cdm.cdmservice.cleanup_time_window\" system property). ");
+ pw.println(" USE FOR DEBUGGING AND/OR TESTING PURPOSES ONLY.");
}
}
diff --git a/services/companion/java/com/android/server/companion/AssociationCleanUpService.java b/services/companion/java/com/android/server/companion/InactiveAssociationsRemovalService.java
similarity index 68%
rename from services/companion/java/com/android/server/companion/AssociationCleanUpService.java
rename to services/companion/java/com/android/server/companion/InactiveAssociationsRemovalService.java
index 55246e1..3482863 100644
--- a/services/companion/java/com/android/server/companion/AssociationCleanUpService.java
+++ b/services/companion/java/com/android/server/companion/InactiveAssociationsRemovalService.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,10 +24,8 @@
import android.app.job.JobParameters;
import android.app.job.JobScheduler;
import android.app.job.JobService;
-import android.companion.AssociationRequest;
import android.content.ComponentName;
import android.content.Context;
-import android.os.AsyncTask;
import android.util.Slog;
import com.android.server.LocalServices;
@@ -37,26 +35,24 @@
* The job will be executed only if the device is charging and in idle mode due to the application
* will be killed if association/role are revoked.
*/
-public class AssociationCleanUpService extends JobService {
- private static final int JOB_ID = AssociationCleanUpService.class.hashCode();
+public class InactiveAssociationsRemovalService extends JobService {
+ private static final int JOB_ID = InactiveAssociationsRemovalService.class.hashCode();
private static final long ONE_DAY_INTERVAL = DAYS.toMillis(1);
@Override
public boolean onStartJob(final JobParameters params) {
- Slog.i(TAG, "Execute the Association CleanUp job");
- // Special policy for APP_STREAMING role that need to revoke associations if the device
- // does not connect for 3 months.
- AsyncTask.execute(() -> {
- LocalServices.getService(CompanionDeviceManagerServiceInternal.class)
- .associationCleanUp(AssociationRequest.DEVICE_PROFILE_APP_STREAMING);
- jobFinished(params, false);
- });
+ Slog.i(TAG, "Execute the Association Removal job");
+ // Special policy for selfManaged that need to revoke associations if the device
+ // does not connect for 90 days.
+ LocalServices.getService(CompanionDeviceManagerServiceInternal.class)
+ .removeInactiveSelfManagedAssociations();
+ jobFinished(params, false);
return true;
}
@Override
public boolean onStopJob(final JobParameters params) {
- Slog.i(TAG, "Association cleanup job stopped; id=" + params.getJobId()
+ Slog.i(TAG, "Association removal job stopped; id=" + params.getJobId()
+ ", reason="
+ JobParameters.getInternalReasonCodeDescription(
params.getInternalStopReasonCode()));
@@ -64,10 +60,10 @@
}
static void schedule(Context context) {
- Slog.i(TAG, "Scheduling the Association Cleanup job");
+ Slog.i(TAG, "Scheduling the Association Removal job");
final JobScheduler jobScheduler = context.getSystemService(JobScheduler.class);
final JobInfo job = new JobInfo.Builder(JOB_ID,
- new ComponentName(context, AssociationCleanUpService.class))
+ new ComponentName(context, InactiveAssociationsRemovalService.class))
.setRequiresCharging(true)
.setRequiresDeviceIdle(true)
.setPeriodic(ONE_DAY_INTERVAL)
@@ -75,3 +71,4 @@
jobScheduler.schedule(job);
}
}
+
diff --git a/services/companion/java/com/android/server/companion/datatransfer/CompanionMessageProcessor.java b/services/companion/java/com/android/server/companion/datatransfer/CompanionMessageProcessor.java
index 826bafa..98a00aa6 100644
--- a/services/companion/java/com/android/server/companion/datatransfer/CompanionMessageProcessor.java
+++ b/services/companion/java/com/android/server/companion/datatransfer/CompanionMessageProcessor.java
@@ -16,6 +16,8 @@
package com.android.server.companion.datatransfer;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.util.Slog;
import android.util.proto.ProtoInputStream;
import android.util.proto.ProtoOutputStream;
@@ -39,6 +41,12 @@
private static final String LOG_TAG = CompanionMessageProcessor.class.getSimpleName();
+ /** Listener for incoming complete messages. */
+ interface Listener {
+ /** When a complete message is received from the companion app. */
+ void onCompleteMessageReceived(@NonNull CompanionMessageInfo message);
+ }
+
// Rough size for each CompanionMessage, each message can exceed 50K for a little, but not
// too much. Hard limit is 100K, WCS data processing limit. Closer to 100K, less stable at
// the WCS data processing layer. Refer to
@@ -48,6 +56,9 @@
private final CompanionSecureCommunicationsManager mSecureCommsManager;
+ @Nullable
+ private Listener mListener;
+
// Association id -> (parent id -> received messages)
private final Map<Integer, Map<Integer, List<CompanionMessageInfo>>> mAssociationsMessagesMap =
new HashMap<>();
@@ -56,6 +67,11 @@
public CompanionMessageProcessor(CompanionSecureCommunicationsManager secureCommsManager) {
mSecureCommsManager = secureCommsManager;
+ mSecureCommsManager.setListener(this::onDecryptedMessageReceived);
+ }
+
+ public void setListener(@NonNull Listener listener) {
+ mListener = listener;
}
/**
@@ -72,7 +88,8 @@
for (int i = 0; i < totalMessageCount; i++) {
ProtoOutputStream proto = new ProtoOutputStream();
- proto.write(CompanionMessage.ID, parentMessageId + i + 1);
+ int messageId = parentMessageId + i + 1;
+ proto.write(CompanionMessage.ID, messageId);
long paginationInfoToken = proto.start(CompanionMessage.PAGINATION_INFO);
proto.write(CompanionMessage.PaginationInfo.PARENT_ID, parentMessageId);
@@ -85,31 +102,75 @@
Math.min((i + 1) * MESSAGE_SIZE_IN_BYTES, data.length));
proto.write(CompanionMessage.DATA, currentData);
- Slog.i(LOG_TAG, "Sending " + currentData.length + " bytes to " + packageName);
+ byte[] message = proto.getBytes();
- mSecureCommsManager.sendSecureMessage(associationId, proto.getBytes());
+ Slog.i(LOG_TAG, "Sending [" + message.length + "] bytes to " + packageName);
+
+ mSecureCommsManager.sendSecureMessage(associationId, messageId, message);
}
}
/**
- * Process message and store it. If all the messages with the same parent id have been received,
- * return the message with combined message data. Otherwise, return null if there's still data
- * parts missing.
+ * Process the message and store it. If all the messages with the same parent id have been
+ * received, return the message with combined message data. Otherwise, return null if there's
+ * still data parts missing.
*/
- public CompanionMessageInfo processMessage(int messageId, int associationId, byte[] message) {
+ public CompanionMessageInfo onDecryptedMessageReceived(int messageId, int associationId,
+ byte[] message) {
+ Slog.i(LOG_TAG, "Partial message received, size [" + message.length
+ + "], reading from protobuf.");
+
ProtoInputStream proto = new ProtoInputStream(message);
try {
- int id = proto.readInt(CompanionMessage.ID);
- if (id == messageId) {
- // Read proto data
- long paginationToken = proto.start(CompanionMessage.PAGINATION_INFO);
- int parentId = proto.readInt(CompanionMessage.PaginationInfo.PARENT_ID);
- int page = proto.readInt(CompanionMessage.PaginationInfo.PAGE);
- int total = proto.readInt(CompanionMessage.PaginationInfo.TOTAL);
- proto.end(paginationToken);
- int type = proto.readInt(CompanionMessage.TYPE);
- byte[] data = proto.readBytes(CompanionMessage.DATA);
+ int id = 0;
+ int parentId = 0;
+ int page = 0;
+ int total = 0;
+ int type = CompanionMessage.UNKNOWN;
+ byte[] data = null;
+ // Read proto data
+ while (proto.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+ switch (proto.getFieldNumber()) {
+ case (int) CompanionMessage.ID:
+ id = proto.readInt(CompanionMessage.ID);
+ break;
+ case (int) CompanionMessage.PAGINATION_INFO:
+ long paginationToken = proto.start(CompanionMessage.PAGINATION_INFO);
+ while (proto.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+ switch (proto.getFieldNumber()) {
+ case (int) CompanionMessage.PaginationInfo.PARENT_ID:
+ parentId = proto.readInt(
+ CompanionMessage.PaginationInfo.PARENT_ID);
+ break;
+ case (int) CompanionMessage.PaginationInfo.PAGE:
+ page = proto.readInt(CompanionMessage.PaginationInfo.PAGE);
+ break;
+ case (int) CompanionMessage.PaginationInfo.TOTAL:
+ total = proto.readInt(CompanionMessage.PaginationInfo.TOTAL);
+ break;
+ default:
+ Slog.e(LOG_TAG, "Unexpected field id "
+ + proto.getFieldNumber() + " for PaginationInfo.");
+ break;
+ }
+ }
+ proto.end(paginationToken);
+ break;
+ case (int) CompanionMessage.TYPE:
+ type = proto.readInt(CompanionMessage.TYPE);
+ break;
+ case (int) CompanionMessage.DATA:
+ data = proto.readBytes(CompanionMessage.DATA);
+ break;
+ default:
+ Slog.e(LOG_TAG, "Unexpected field id " + proto.getFieldNumber()
+ + " for CompanionMessage.");
+ break;
+ }
+ }
+
+ if (id == messageId) {
CompanionMessageInfo messageInfo = new CompanionMessageInfo(id, page, total, type,
data);
// Add the message into mAssociationsMessagesMap
@@ -122,28 +183,36 @@
mAssociationsMessagesMap.put(associationId, associationMessages);
// Check if all the messages with the same parentId are received.
if (childMessages.size() == total) {
+ Slog.i(LOG_TAG, "All [" + total + "] messages are received for parentId ["
+ + parentId + "]. Processing.");
+
childMessages.sort(Comparator.comparing(CompanionMessageInfo::getPage));
ByteArrayOutputStream stream = new ByteArrayOutputStream();
for (int i = 0; i < childMessages.size(); i++) {
stream.write(childMessages.get(i).getData());
}
mAssociationsMessagesMap.remove(parentId);
- return new CompanionMessageInfo(parentId, 0, total, type, stream.toByteArray());
+ mListener.onCompleteMessageReceived(
+ new CompanionMessageInfo(parentId, 0, total, type,
+ stream.toByteArray()));
+ } else {
+ Slog.i(LOG_TAG, "[" + childMessages.size() + "/" + total
+ + "] messages are received for parentId [" + parentId + "]");
}
} else {
Slog.e(LOG_TAG, "Message id mismatch.");
return null;
}
} catch (IOException e) {
- Slog.e(LOG_TAG, "Can't read proto message id: " + messageId + ", message: "
- + new String(message) + ".");
+ Slog.e(LOG_TAG, "Can't read proto from the message.");
return null;
}
return null;
}
/**
- * Find the next parent id. The parent and child ids are incremental.
+ * Find the next parent id from [1, Integer.MAX_VALUE].
+ * The parent and child ids are incremental.
*/
private int findNextParentId(int associationId, int totalMessageCount) {
int nextParentId = mNextParentId.getOrDefault(associationId, 1);
diff --git a/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java b/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java
index cafa78f..395cf18 100644
--- a/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java
+++ b/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java
@@ -26,6 +26,7 @@
import static java.nio.charset.StandardCharsets.UTF_8;
+import android.annotation.NonNull;
import android.annotation.UserIdInt;
import android.app.PendingIntent;
import android.companion.AssociationInfo;
@@ -91,6 +92,7 @@
mAssociationStore = associationStore;
mSystemDataTransferRequestStore = systemDataTransferRequestStore;
mCompanionMessageProcessor = companionMessageProcessor;
+ mCompanionMessageProcessor.setListener(this::onCompleteMessageReceived);
}
/**
@@ -201,44 +203,40 @@
}
/**
- * Process message reported by the companion app.
+ * Process a complete decrypted message reported by the companion app.
*/
- public void processMessage(String packageName, int userId, int associationId,
- int messageId, byte[] message) {
- Slog.i(LOG_TAG, "Start processing message [" + messageId + "] from package ["
- + packageName + "] userId [" + userId + "] associationId [" + associationId + "]");
-
- AssociationInfo association = mAssociationStore.getAssociationById(associationId);
- association = PermissionsUtils.sanitizeWithCallerChecks(mContext, association);
- if (association == null) {
- throw new DeviceNotAssociatedException("Association "
- + associationId + " is not associated with the app " + packageName
- + " for user " + userId);
+ public void onCompleteMessageReceived(@NonNull CompanionMessageInfo completeMessage) {
+ switch (completeMessage.getType()) {
+ case CompanionMessage.PERMISSION_SYNC:
+ processPermissionSyncMessage(completeMessage);
+ break;
+ default:
+ Slog.e(LOG_TAG, "Unknown message type [" + completeMessage.getType()
+ + "]. Unable to process.");
}
+ }
- PermissionsUtils.enforceCallerIsSystemOr(userId, packageName);
+ private void processPermissionSyncMessage(CompanionMessageInfo messageInfo) {
+ Slog.i(LOG_TAG, "Applying permissions.");
+ // Start applying permissions
+ final long callingIdentityToken = Binder.clearCallingIdentity();
+ try {
+ BackupHelper backupHelper = new BackupHelper(mContext, mContext.getUser());
+ XmlPullParser parser = Xml.newPullParser();
+ ByteArrayInputStream stream = new ByteArrayInputStream(
+ messageInfo.getData());
+ parser.setInput(stream, UTF_8.name());
- CompanionMessageInfo completeMessage = mCompanionMessageProcessor.processMessage(messageId,
- associationId, message);
- if (completeMessage != null) {
- if (completeMessage.getType() == CompanionMessage.PERMISSION_SYNC) {
- // Start applying permissions
- BackupHelper backupHelper = new BackupHelper(mContext, UserHandle.of(userId));
- try {
- XmlPullParser parser = Xml.newPullParser();
- ByteArrayInputStream stream = new ByteArrayInputStream(
- completeMessage.getData());
- parser.setInput(stream, UTF_8.name());
-
- backupHelper.restoreState(parser);
- } catch (IOException e) {
- Slog.e(LOG_TAG, "IOException reading message: "
- + new String(completeMessage.getData()));
- } catch (XmlPullParserException e) {
- Slog.e(LOG_TAG, "Error parsing message: "
- + new String(completeMessage.getData()));
- }
- }
+ backupHelper.restoreState(parser);
+ } catch (IOException e) {
+ Slog.e(LOG_TAG, "IOException reading message: "
+ + new String(messageInfo.getData()));
+ } catch (XmlPullParserException e) {
+ Slog.e(LOG_TAG, "Error parsing message: "
+ + new String(messageInfo.getData()));
+ } finally {
+ Slog.i(LOG_TAG, "Permissions applied.");
+ Binder.restoreCallingIdentity(callingIdentityToken);
}
}
diff --git a/services/companion/java/com/android/server/companion/datatransfer/permbackup/BackupHelper.java b/services/companion/java/com/android/server/companion/datatransfer/permbackup/BackupHelper.java
index f41aa2f..5e3c4c7 100644
--- a/services/companion/java/com/android/server/companion/datatransfer/permbackup/BackupHelper.java
+++ b/services/companion/java/com/android/server/companion/datatransfer/permbackup/BackupHelper.java
@@ -49,6 +49,7 @@
import org.xmlpull.v1.XmlSerializer;
import java.io.IOException;
+import java.security.cert.CertificateException;
import java.util.ArrayList;
import java.util.List;
@@ -68,6 +69,7 @@
private static final String ATTR_HAS_MULTIPLE_SIGNERS = "multi-signers";
private static final String TAG_SIGNATURE = "sig";
+ private static final String ATTR_SIGNATURE_VALUE = "v";
private static final String TAG_PERMISSION = "perm";
private static final String ATTR_PERMISSION_NAME = "name";
@@ -584,7 +586,8 @@
skipToEndOfTag(parser);
break;
case TAG_SIGNATURE:
- signatureList.add(new Signature(parser.getText()));
+ signatureList.add(new Signature(
+ parser.getAttributeValue(null, ATTR_SIGNATURE_VALUE)));
skipToEndOfTag(parser);
break;
default:
@@ -681,7 +684,7 @@
String.valueOf(mHasMultipleSigners));
for (Signature signature : mSignatures) {
serializer.startTag(null, TAG_SIGNATURE);
- serializer.text(signature.toCharsString());
+ serializer.attribute(null, ATTR_SIGNATURE_VALUE, signature.toCharsString());
serializer.endTag(null, TAG_SIGNATURE);
}
@@ -700,6 +703,47 @@
* @param pkgInfo The package to restore.
*/
void restore(@NonNull Context context, @NonNull PackageInfo pkgInfo) {
+ Slog.e(LOG_TAG, "Restoring permissions for package [" + mPackageName + "]");
+
+ // Verify signature info
+ try {
+ if (mHasMultipleSigners && pkgInfo.signingInfo.hasMultipleSigners()) {
+ // If both packages are signed by multi signers, check if two signature sets are
+ // effectively matched.
+ if (!Signature.areEffectiveMatch(mSignatures,
+ pkgInfo.signingInfo.getApkContentsSigners())) {
+ Slog.e(LOG_TAG, "Multi-signers signatures don't match for package ["
+ + mPackageName + "], skipped.");
+ return;
+ }
+ } else if (!mHasMultipleSigners && !pkgInfo.signingInfo.hasMultipleSigners()) {
+ // If both packages are not signed by multi signers, check if two signature sets
+ // have overlaps.
+ Signature[] signatures = pkgInfo.signingInfo.getSigningCertificateHistory();
+ if (signatures == null) {
+ Slog.e(LOG_TAG, "The dest package is unsigned.");
+ return;
+ }
+ boolean isMatched = false;
+ for (int i = 0; i < mSignatures.length; i++) {
+ for (int j = 0; j < signatures.length; j++) {
+ isMatched = Signature.areEffectiveMatch(mSignatures[i], signatures[j]);
+ }
+ }
+ if (!isMatched) {
+ Slog.e(LOG_TAG, "Single signer signatures don't match for package ["
+ + mPackageName + "], skipped.");
+ return;
+ }
+ } else {
+ Slog.e(LOG_TAG, "Number of signers don't match.");
+ return;
+ }
+ } catch (CertificateException ce) {
+ Slog.e(LOG_TAG, "Either the source or the dest package's bounced cert length "
+ + "looks fishy, skipped package [" + pkgInfo.packageName + "]");
+ }
+
AppPermissions appPerms = new AppPermissions(context, pkgInfo, false, true, null);
ArraySet<String> affectedPermissions = new ArraySet<>();
diff --git a/services/companion/java/com/android/server/companion/datatransfer/permbackup/model/AppPermissionGroup.java b/services/companion/java/com/android/server/companion/datatransfer/permbackup/model/AppPermissionGroup.java
index 71d561e..cf146ac 100644
--- a/services/companion/java/com/android/server/companion/datatransfer/permbackup/model/AppPermissionGroup.java
+++ b/services/companion/java/com/android/server/companion/datatransfer/permbackup/model/AppPermissionGroup.java
@@ -37,7 +37,6 @@
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
-import android.os.Binder;
import android.os.Build;
import android.os.UserHandle;
import android.permission.PermissionManager;
@@ -1438,29 +1437,30 @@
}
}
- int flags = (permission.isUserSet() ? PackageManager.FLAG_PERMISSION_USER_SET : 0)
- | (permission.isUserFixed() ? PackageManager.FLAG_PERMISSION_USER_FIXED : 0)
- | (permission.isRevokedCompat()
- ? PackageManager.FLAG_PERMISSION_REVOKED_COMPAT : 0)
- | (permission.isPolicyFixed() ? PackageManager.FLAG_PERMISSION_POLICY_FIXED : 0)
- | (permission.isReviewRequired()
- ? PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED : 0)
- | (permission.isOneTime() ? PackageManager.FLAG_PERMISSION_ONE_TIME : 0)
- | (permission.isSelectedLocationAccuracy()
- ? PackageManager.FLAG_PERMISSION_SELECTED_LOCATION_ACCURACY : 0);
+// int flags = (permission.isUserSet() ? PackageManager.FLAG_PERMISSION_USER_SET : 0)
+// | (permission.isUserFixed() ? PackageManager.FLAG_PERMISSION_USER_FIXED : 0)
+// | (permission.isRevokedCompat()
+// ? PackageManager.FLAG_PERMISSION_REVOKED_COMPAT : 0)
+// | (permission.isPolicyFixed() ?
+// PackageManager.FLAG_PERMISSION_POLICY_FIXED : 0)
+// | (permission.isReviewRequired()
+// ? PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED : 0)
+// | (permission.isOneTime() ? PackageManager.FLAG_PERMISSION_ONE_TIME : 0)
+// | (permission.isSelectedLocationAccuracy()
+// ? PackageManager.FLAG_PERMISSION_SELECTED_LOCATION_ACCURACY : 0);
- mPackageManager.updatePermissionFlags(permission.getName(),
- mPackageInfo.packageName,
- PackageManager.FLAG_PERMISSION_USER_SET
- | PackageManager.FLAG_PERMISSION_USER_FIXED
- | PackageManager.FLAG_PERMISSION_REVOKED_COMPAT
- | PackageManager.FLAG_PERMISSION_POLICY_FIXED
- | (permission.isReviewRequired()
- ? 0 : PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED)
- | PackageManager.FLAG_PERMISSION_ONE_TIME
- | PackageManager.FLAG_PERMISSION_AUTO_REVOKED // clear auto revoke
- | PackageManager.FLAG_PERMISSION_SELECTED_LOCATION_ACCURACY,
- flags, mUserHandle);
+// mPackageManager.updatePermissionFlags(permission.getName(),
+// mPackageInfo.packageName,
+// PackageManager.FLAG_PERMISSION_USER_SET
+// | PackageManager.FLAG_PERMISSION_USER_FIXED
+// | PackageManager.FLAG_PERMISSION_REVOKED_COMPAT
+// | PackageManager.FLAG_PERMISSION_POLICY_FIXED
+// | (permission.isReviewRequired()
+// ? 0 : PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED)
+// | PackageManager.FLAG_PERMISSION_ONE_TIME
+// | PackageManager.FLAG_PERMISSION_AUTO_REVOKED // clear auto revoke
+// | PackageManager.FLAG_PERMISSION_SELECTED_LOCATION_ACCURACY,
+// flags, mUserHandle);
if (permission.affectsAppOp()) {
if (!permission.isSystemFixed()) {
@@ -1486,18 +1486,18 @@
// mTriggerLocationAccessCheckOnPersist = false;
// }
- String packageName = mPackageInfo.packageName;
- if (areRuntimePermissionsGranted(null, true, false)) {
- // Required to read device config in Utils.getOneTimePermissions*().
- final long token = Binder.clearCallingIdentity();
- try {
+// String packageName = mPackageInfo.packageName;
+// if (areRuntimePermissionsGranted(null, true, false)) {
+// // Required to read device config in Utils.getOneTimePermissions*().
+// final long token = Binder.clearCallingIdentity();
+// try {
// if (SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
- mContext.getSystemService(PermissionManager.class)
- .startOneTimePermissionSession(packageName,
- Utils.getOneTimePermissionsTimeout(),
- Utils.getOneTimePermissionsKilledDelay(mIsSelfRevoked),
- ONE_TIME_PACKAGE_IMPORTANCE_LEVEL_TO_RESET_TIMER,
- ONE_TIME_PACKAGE_IMPORTANCE_LEVEL_TO_KEEP_SESSION_ALIVE);
+// mContext.getSystemService(PermissionManager.class)
+// .startOneTimePermissionSession(packageName,
+// Utils.getOneTimePermissionsTimeout(),
+// Utils.getOneTimePermissionsKilledDelay(mIsSelfRevoked),
+// ONE_TIME_PACKAGE_IMPORTANCE_LEVEL_TO_RESET_TIMER,
+// ONE_TIME_PACKAGE_IMPORTANCE_LEVEL_TO_KEEP_SESSION_ALIVE);
// } else {
// mContext.getSystemService(PermissionManager.class)
// .startOneTimePermissionSession(packageName,
@@ -1505,13 +1505,13 @@
// ONE_TIME_PACKAGE_IMPORTANCE_LEVEL_TO_RESET_TIMER,
// ONE_TIME_PACKAGE_IMPORTANCE_LEVEL_TO_KEEP_SESSION_ALIVE);
// }
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- } else {
- mContext.getSystemService(PermissionManager.class)
- .stopOneTimePermissionSession(packageName);
- }
+// } finally {
+// Binder.restoreCallingIdentity(token);
+// }
+// } else {
+// mContext.getSystemService(PermissionManager.class)
+// .stopOneTimePermissionSession(packageName);
+// }
}
/**
diff --git a/services/companion/java/com/android/server/companion/presence/CompanionDevicePresenceMonitor.java b/services/companion/java/com/android/server/companion/presence/CompanionDevicePresenceMonitor.java
index 37e8369..89ed301e 100644
--- a/services/companion/java/com/android/server/companion/presence/CompanionDevicePresenceMonitor.java
+++ b/services/companion/java/com/android/server/companion/presence/CompanionDevicePresenceMonitor.java
@@ -149,6 +149,13 @@
onDeviceGone(mReportedSelfManagedDevices, associationId, "application-reported");
}
+ /**
+ * Marks a "self-managed" device as disconnected when binderDied.
+ */
+ public void onSelfManagedDeviceReporterBinderDied(int associationId) {
+ onDeviceGone(mReportedSelfManagedDevices, associationId, "application-reported");
+ }
+
@Override
public void onBluetoothCompanionDeviceConnected(int associationId) {
onDevicePresent(mConnectedBtDevices, associationId, /* sourceLoggingTag */ "bt");
@@ -259,16 +266,6 @@
}
/**
- * Remove the current connected devices by associationId.
- */
- public void removeDeviceFromMonitoring(int associationId) {
- mConnectedBtDevices.remove(associationId);
- mNearbyBleDevices.remove(associationId);
- mReportedSelfManagedDevices.remove(associationId);
- mSimulated.remove(associationId);
- }
-
- /**
* Implements
* {@link AssociationStore.OnChangeListener#onAssociationRemoved(AssociationInfo)}
*/
@@ -280,7 +277,9 @@
Log.d(TAG, " > association=" + association);
}
- removeDeviceFromMonitoring(id);
+ mConnectedBtDevices.remove(id);
+ mNearbyBleDevices.remove(id);
+ mReportedSelfManagedDevices.remove(id);
// Do NOT call mCallback.onDeviceDisappeared()!
// CompanionDeviceManagerService will know that the association is removed, and will do
diff --git a/services/companion/java/com/android/server/companion/proto/companion_message.proto b/services/companion/java/com/android/server/companion/proto/companion_message.proto
index 4e8027f..893a0db 100644
--- a/services/companion/java/com/android/server/companion/proto/companion_message.proto
+++ b/services/companion/java/com/android/server/companion/proto/companion_message.proto
@@ -22,7 +22,7 @@
/* Represents a message between companion devices */
message CompanionMessage {
- int64 id = 1;
+ int32 id = 1;
PaginationInfo paginationInfo = 2;
@@ -34,7 +34,7 @@
/* Message pagination info */
message PaginationInfo {
// id of the parent message, which should be the same for all the paginated messages
- int64 parentId = 1;
+ int32 parentId = 1;
// page number of the current message in [1, total]
int32 page = 2;
diff --git a/services/companion/java/com/android/server/companion/securechannel/CompanionSecureCommunicationsManager.java b/services/companion/java/com/android/server/companion/securechannel/CompanionSecureCommunicationsManager.java
index 625360e..16a74ec 100644
--- a/services/companion/java/com/android/server/companion/securechannel/CompanionSecureCommunicationsManager.java
+++ b/services/companion/java/com/android/server/companion/securechannel/CompanionSecureCommunicationsManager.java
@@ -17,10 +17,12 @@
package com.android.server.companion.securechannel;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.companion.AssociationInfo;
import android.util.Base64;
import android.util.Log;
+import android.util.Slog;
import com.android.server.companion.AssociationStore;
import com.android.server.companion.CompanionApplicationController;
@@ -31,9 +33,18 @@
static final String TAG = "CompanionDevice_SecureComms";
static final boolean DEBUG = false;
+ /** Listener for incoming decrypted messages. */
+ public interface Listener {
+ /** When an incoming message is decrypted. */
+ void onDecryptedMessageReceived(int messageId, int associationId, byte[] message);
+ }
+
private final AssociationStore mAssociationStore;
private final CompanionApplicationController mCompanionAppController;
+ @Nullable
+ private Listener mListener;
+
/** Constructor */
public CompanionSecureCommunicationsManager(AssociationStore associationStore,
CompanionApplicationController companionApplicationController) {
@@ -41,13 +52,18 @@
mCompanionAppController = companionApplicationController;
}
+ public void setListener(@NonNull Listener listener) {
+ mListener = listener;
+ }
+
/**
* Send a data to the associated companion device via secure channel (establishing one if
* needed).
* @param associationId associationId of the "recipient" companion device.
+ * @param messageId id of the message
* @param message data to be sent securely.
*/
- public void sendSecureMessage(int associationId, @NonNull byte[] message) {
+ public void sendSecureMessage(int associationId, int messageId, @NonNull byte[] message) {
if (DEBUG) {
Log.d(TAG, "sendSecureMessage() associationId=" + associationId + "\n"
+ " message (Base64)=\"" + Base64.encodeToString(message, 0) + "\"");
@@ -62,13 +78,28 @@
final int userId = association.getUserId();
final String packageName = association.getPackageName();
+
+ // Bind to the app if it hasn't been bound.
if (!mCompanionAppController.isCompanionApplicationBound(userId, packageName)) {
- throw new IllegalStateException("u" + userId + "\\" + packageName + " is NOT bound");
+ Slog.d(TAG, "userId [" + userId + "] packageName [" + packageName
+ + "] is not bound. Binding it now to send a secure message.");
+ mCompanionAppController.bindCompanionApplication(userId, packageName,
+ association.isSelfManaged());
+
+ // TODO(b/202926196): implement: encrypt and pass on the companion application for
+ // transporting
+ mCompanionAppController.dispatchMessage(userId, packageName, associationId, messageId,
+ message);
+
+ Slog.d(TAG, "Unbinding userId [" + userId + "] packageName [" + packageName
+ + "]");
+ mCompanionAppController.unbindCompanionApplication(userId, packageName);
}
// TODO(b/202926196): implement: encrypt and pass on the companion application for
// transporting
- mCompanionAppController.dispatchMessage(userId, packageName, associationId, message);
+ mCompanionAppController.dispatchMessage(userId, packageName, associationId, messageId,
+ message);
}
/**
@@ -76,12 +107,15 @@
* @param associationId associationId of the "sender" companion device.
* @param encryptedMessage data.
*/
- public void receiveSecureMessage(int associationId, @NonNull byte[] encryptedMessage) {
+ public void receiveSecureMessage(int messageId, int associationId,
+ @NonNull byte[] encryptedMessage) {
if (DEBUG) {
Log.d(TAG, "sendSecureMessage() associationId=" + associationId + "\n"
+ " message (Base64)=\"" + Base64.encodeToString(encryptedMessage, 0) + "\"");
}
- // TODO(b/202926196): implement: decrypt and dispatch.
+ // TODO(b/202926196): implement: decrypt and dispatch
+
+ mListener.onDecryptedMessageReceived(messageId, associationId, encryptedMessage);
}
}
diff --git a/services/companion/java/com/android/server/companion/virtual/InputController.java b/services/companion/java/com/android/server/companion/virtual/InputController.java
index ab9023b..05e85e3 100644
--- a/services/companion/java/com/android/server/companion/virtual/InputController.java
+++ b/services/companion/java/com/android/server/companion/virtual/InputController.java
@@ -37,6 +37,7 @@
import android.util.Slog;
import android.view.Display;
import android.view.InputDevice;
+import android.view.WindowManager;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -83,22 +84,26 @@
private final NativeWrapper mNativeWrapper;
private final DisplayManagerInternal mDisplayManagerInternal;
private final InputManagerInternal mInputManagerInternal;
+ private final WindowManager mWindowManager;
private final DeviceCreationThreadVerifier mThreadVerifier;
- InputController(@NonNull Object lock, @NonNull Handler handler) {
- this(lock, new NativeWrapper(), handler,
+ InputController(@NonNull Object lock, @NonNull Handler handler,
+ @NonNull WindowManager windowManager) {
+ this(lock, new NativeWrapper(), handler, windowManager,
// Verify that virtual devices are not created on the handler thread.
() -> !handler.getLooper().isCurrentThread());
}
@VisibleForTesting
InputController(@NonNull Object lock, @NonNull NativeWrapper nativeWrapper,
- @NonNull Handler handler, @NonNull DeviceCreationThreadVerifier threadVerifier) {
+ @NonNull Handler handler, @NonNull WindowManager windowManager,
+ @NonNull DeviceCreationThreadVerifier threadVerifier) {
mLock = lock;
mHandler = handler;
mNativeWrapper = nativeWrapper;
mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
+ mWindowManager = windowManager;
mThreadVerifier = threadVerifier;
}
@@ -209,6 +214,15 @@
mInputManagerInternal.setDisplayEligibilityForPointerCapture(displayId, isEligible);
}
+ void setLocalIme(int displayId) {
+ // WM throws a SecurityException if the display is untrusted.
+ if ((mDisplayManagerInternal.getDisplayInfo(displayId).flags & Display.FLAG_TRUSTED)
+ == Display.FLAG_TRUSTED) {
+ mWindowManager.setDisplayImePolicy(displayId,
+ WindowManager.DISPLAY_IME_POLICY_LOCAL);
+ }
+ }
+
@GuardedBy("mLock")
private void updateActivePointerDisplayIdLocked() {
InputDeviceDescriptor mostRecentlyCreatedMouse = null;
diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
index 9802b97..638b3ae 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
@@ -62,6 +62,7 @@
import android.util.Slog;
import android.util.SparseArray;
import android.view.Display;
+import android.view.WindowManager;
import android.widget.Toast;
import android.window.DisplayWindowPolicyController;
@@ -167,7 +168,9 @@
mParams = params;
if (inputController == null) {
mInputController = new InputController(
- mVirtualDeviceLock, context.getMainThreadHandler());
+ mVirtualDeviceLock,
+ context.getMainThreadHandler(),
+ context.getSystemService(WindowManager.class));
} else {
mInputController = inputController;
}
@@ -537,6 +540,7 @@
mInputController.setPointerAcceleration(1f, displayId);
mInputController.setDisplayEligibilityForPointerCapture(/* isEligible= */ false,
displayId);
+ mInputController.setLocalIme(displayId);
// Since we're being called in the middle of the display being created, we post a
// task to grab the wakelock instead of doing it synchronously here, to avoid
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
index 61d784e..ad6e7db 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
@@ -730,7 +730,7 @@
String serviceName = mServiceNameResolver.getServiceName(userId);
ContentCaptureMetricsLogger.writeServiceEvent(
EVENT__DATA_SHARE_ERROR_CONCURRENT_REQUEST,
- serviceName, request.getPackageName());
+ serviceName);
clientAdapter.error(
ContentCaptureManager.DATA_SHARE_ERROR_CONCURRENT_REQUEST);
} catch (RemoteException e) {
@@ -1303,8 +1303,7 @@
private void logServiceEvent(int eventType) {
int userId = UserHandle.getCallingUserId();
String serviceName = mParentService.mServiceNameResolver.getServiceName(userId);
- ContentCaptureMetricsLogger.writeServiceEvent(eventType, serviceName,
- mDataShareRequest.getPackageName());
+ ContentCaptureMetricsLogger.writeServiceEvent(eventType, serviceName);
}
}
}
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureMetricsLogger.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureMetricsLogger.java
index 7ea4eff..10bec64 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureMetricsLogger.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureMetricsLogger.java
@@ -34,72 +34,47 @@
}
/** @hide */
- public static void writeServiceEvent(int eventType, @NonNull String serviceName,
- @Nullable String targetPackage) {
+ public static void writeServiceEvent(int eventType, @NonNull String serviceName) {
+ // we should not logging the application package name
FrameworkStatsLog.write(FrameworkStatsLog.CONTENT_CAPTURE_SERVICE_EVENTS, eventType,
- serviceName, targetPackage);
- }
-
- /** @hide */
- public static void writeServiceEvent(int eventType, @NonNull ComponentName service,
- @Nullable ComponentName target) {
- writeServiceEvent(eventType, ComponentName.flattenToShortString(service),
- ComponentName.flattenToShortString(target));
- }
-
- /** @hide */
- public static void writeServiceEvent(int eventType, @NonNull ComponentName service,
- @Nullable String targetPackage) {
- writeServiceEvent(eventType, ComponentName.flattenToShortString(service), targetPackage);
+ serviceName, /* componentName= */ null, 0, 0);
}
/** @hide */
public static void writeServiceEvent(int eventType, @NonNull ComponentName service) {
- writeServiceEvent(eventType, ComponentName.flattenToShortString(service), null);
+ writeServiceEvent(eventType, ComponentName.flattenToShortString(service));
}
/** @hide */
public static void writeSetWhitelistEvent(@Nullable ComponentName service,
@Nullable List<String> packages, @Nullable List<ComponentName> activities) {
final String serviceName = ComponentName.flattenToShortString(service);
- StringBuilder stringBuilder = new StringBuilder();
- if (packages != null && packages.size() > 0) {
- final int size = packages.size();
- stringBuilder.append(packages.get(0));
- for (int i = 1; i < size; i++) {
- stringBuilder.append(" ");
- stringBuilder.append(packages.get(i));
- }
- }
- if (activities != null && activities.size() > 0) {
- stringBuilder.append(" ");
- stringBuilder.append(activities.get(0).flattenToShortString());
- final int size = activities.size();
- for (int i = 1; i < size; i++) {
- stringBuilder.append(" ");
- stringBuilder.append(activities.get(i).flattenToShortString());
- }
- }
+ int packageCount = packages != null ? packages.size() : 0;
+ int activityCount = activities != null ? activities.size() : 0;
+ // we should not logging the application package name
+ // log the allow list package and activity count instead
FrameworkStatsLog.write(FrameworkStatsLog.CONTENT_CAPTURE_SERVICE_EVENTS,
FrameworkStatsLog.CONTENT_CAPTURE_SERVICE_EVENTS__EVENT__SET_WHITELIST,
- serviceName, stringBuilder.toString());
+ serviceName, /* allowListStr= */ null, packageCount, activityCount);
}
/** @hide */
public static void writeSessionEvent(int sessionId, int event, int flags,
- @NonNull ComponentName service, @Nullable ComponentName app, boolean isChildSession) {
+ @NonNull ComponentName service, boolean isChildSession) {
+ // we should not logging the application package name
FrameworkStatsLog.write(FrameworkStatsLog.CONTENT_CAPTURE_SESSION_EVENTS, sessionId, event,
flags, ComponentName.flattenToShortString(service),
- ComponentName.flattenToShortString(app), isChildSession);
+ /* componentName= */ null, isChildSession);
}
/** @hide */
public static void writeSessionFlush(int sessionId, @NonNull ComponentName service,
- @Nullable ComponentName app, @NonNull FlushMetrics fm,
- @NonNull ContentCaptureOptions options, int flushReason) {
+ @NonNull FlushMetrics fm, @NonNull ContentCaptureOptions options,
+ int flushReason) {
+ // we should not logging the application package name
FrameworkStatsLog.write(FrameworkStatsLog.CONTENT_CAPTURE_FLUSHED, sessionId,
ComponentName.flattenToShortString(service),
- ComponentName.flattenToShortString(app), fm.sessionStarted, fm.sessionFinished,
+ /* componentName= */ null, fm.sessionStarted, fm.sessionFinished,
fm.viewAppearedCount, fm.viewDisappearedCount, fm.viewTextChangedCount,
options.maxBufferSize, options.idleFlushingFrequencyMs,
options.textChangeFlushingFrequencyMs, flushReason);
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
index 822a42b..9bc1cee 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
@@ -330,7 +330,7 @@
writeSessionEvent(sessionId,
FrameworkStatsLog.CONTENT_CAPTURE_SESSION_EVENTS__EVENT__SESSION_NOT_CREATED,
STATE_DISABLED | STATE_NO_SERVICE, serviceComponentName,
- componentName, /* isChildSession= */ false);
+ /* isChildSession= */ false);
return;
}
if (serviceComponentName == null) {
@@ -354,7 +354,7 @@
writeSessionEvent(sessionId,
FrameworkStatsLog.CONTENT_CAPTURE_SESSION_EVENTS__EVENT__SESSION_NOT_CREATED,
STATE_DISABLED | STATE_NOT_WHITELISTED, serviceComponentName,
- componentName, /* isChildSession= */ false);
+ /* isChildSession= */ false);
return;
}
@@ -368,7 +368,7 @@
writeSessionEvent(sessionId,
FrameworkStatsLog.CONTENT_CAPTURE_SESSION_EVENTS__EVENT__SESSION_NOT_CREATED,
STATE_DISABLED | STATE_DUPLICATED_ID,
- serviceComponentName, componentName, /* isChildSession= */ false);
+ serviceComponentName, /* isChildSession= */ false);
return;
}
@@ -385,7 +385,7 @@
writeSessionEvent(sessionId,
FrameworkStatsLog.CONTENT_CAPTURE_SESSION_EVENTS__EVENT__SESSION_NOT_CREATED,
STATE_DISABLED | STATE_NO_SERVICE, serviceComponentName,
- componentName, /* isChildSession= */ false);
+ /* isChildSession= */ false);
return;
}
@@ -740,7 +740,7 @@
@Override
public void writeSessionFlush(int sessionId, ComponentName app, FlushMetrics flushMetrics,
ContentCaptureOptions options, int flushReason) {
- ContentCaptureMetricsLogger.writeSessionFlush(sessionId, getServiceComponentName(), app,
+ ContentCaptureMetricsLogger.writeSessionFlush(sessionId, getServiceComponentName(),
flushMetrics, options, flushReason);
}
diff --git a/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java b/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java
index 08e6a05..1efe55a 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java
@@ -119,8 +119,7 @@
// Metrics logging.
writeSessionEvent(sessionId,
FrameworkStatsLog.CONTENT_CAPTURE_SESSION_EVENTS__EVENT__ON_SESSION_STARTED,
- initialState, getComponentName(), context.getActivityComponent(),
- /* is_child_session= */ false);
+ initialState, getComponentName(), /* is_child_session= */ false);
}
/**
@@ -132,8 +131,7 @@
// Metrics logging.
writeSessionEvent(sessionId,
FrameworkStatsLog.CONTENT_CAPTURE_SESSION_EVENTS__EVENT__ON_SESSION_FINISHED,
- /* flags= */ 0, getComponentName(), /* app= */ null,
- /* is_child_session= */ false);
+ /* flags= */ 0, getComponentName(), /* is_child_session= */ false);
}
/**
@@ -158,7 +156,7 @@
scheduleAsyncRequest((s) -> s.onDataShared(request, dataShareCallback));
writeServiceEvent(
FrameworkStatsLog.CONTENT_CAPTURE_SERVICE_EVENTS__EVENT__ON_DATA_SHARE_REQUEST,
- mComponentName, request.getPackageName());
+ mComponentName);
}
/**
diff --git a/services/core/OWNERS b/services/core/OWNERS
deleted file mode 100644
index 88d0b61..0000000
--- a/services/core/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-per-file Android.bp = file:platform/build/soong:/OWNERS
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index c45a871..7cb7c0b 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -28,6 +28,7 @@
import android.content.ContentResolver;
import android.content.Intent;
import android.content.IntentSender;
+import android.content.pm.PackageManager.SignatureResult;
import android.content.pm.SigningDetails.CertCapabilities;
import android.content.pm.overlay.OverlayPaths;
import android.os.Bundle;
@@ -334,10 +335,14 @@
/**
* Retrieve all receivers that can handle a broadcast of the given intent.
+ * @param filterCallingUid The results will be filtered in the context of this UID instead
+ * of the calling UID.
+ * @param forSend true if the invocation is intended for sending broadcasts. The value
+ * of this parameter affects how packages are filtered.
*/
public abstract List<ResolveInfo> queryIntentReceivers(Intent intent,
String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags,
- int filterCallingUid, int userId);
+ int filterCallingUid, int userId, boolean forSend);
/**
* Retrieve all services that can be performed for the given intent.
@@ -371,10 +376,10 @@
int deviceOwnerUserId, String deviceOwner, SparseArray<String> profileOwners);
/**
- * Called by Owners to set the package names protected by the device owner.
+ * Marks packages as protected for a given user or all users in case of USER_ALL.
*/
- public abstract void setDeviceOwnerProtectedPackages(
- String deviceOwnerPackageName, List<String> packageNames);
+ public abstract void setOwnerProtectedPackages(
+ @UserIdInt int userId, @NonNull List<String> packageNames);
/**
* Returns {@code true} if a given package can't be wiped. Otherwise, returns {@code false}.
@@ -1279,4 +1284,15 @@
public abstract void shutdown();
public abstract DynamicCodeLogger getDynamicCodeLogger();
+
+ /**
+ * Compare the signatures of two packages that are installed in different users.
+ *
+ * @param uid1 First UID whose signature will be compared.
+ * @param uid2 Second UID whose signature will be compared.
+ * @return {@link PackageManager#SIGNATURE_MATCH} if signatures are matched.
+ * @throws SecurityException if the caller does not hold the
+ * {@link android.Manifest.permission#INTERACT_ACROSS_USERS}.
+ */
+ public abstract @SignatureResult int checkUidSignaturesForAllUsers(int uid1, int uid2);
}
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 3607b40..8edd75e 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -3876,9 +3876,12 @@
match = vol.isVisibleForWrite(userId)
|| (includeSharedProfile && vol.isVisibleForWrite(userIdSharingMedia));
} else {
+ // Return both read only and write only volumes. When includeSharedProfile is
+ // true, all the volumes of userIdSharingMedia should be returned when queried
+ // from the user it shares media with
match = vol.isVisibleForUser(userId)
|| (!vol.isVisible() && includeInvisible && vol.getPath() != null)
- || (includeSharedProfile && vol.isVisibleForRead(userIdSharingMedia));
+ || (includeSharedProfile && vol.isVisibleForUser(userIdSharingMedia));
}
if (!match) continue;
diff --git a/services/core/java/com/android/server/SystemServiceManager.java b/services/core/java/com/android/server/SystemServiceManager.java
index a562afb..9455a89 100644
--- a/services/core/java/com/android/server/SystemServiceManager.java
+++ b/services/core/java/com/android/server/SystemServiceManager.java
@@ -83,8 +83,6 @@
private static final String USER_STOPPED = "Cleanup"; // Logged as onCleanupUser
private static final String USER_COMPLETED_EVENT = "CompletedEvent"; // onCompletedEventUser
- // Whether to use multiple threads to run user lifecycle phases in parallel.
- private static boolean sUseLifecycleThreadPool = true;
// The default number of threads to use if lifecycle thread pool is enabled.
private static final int DEFAULT_MAX_USER_POOL_THREADS = 3;
// The number of threads to use if lifecycle thread pool is enabled, dependent on the number of
@@ -129,9 +127,6 @@
mContext = context;
mServices = new ArrayList<>();
mServiceClassnames = new ArraySet<>();
- // Disable using the thread pool for low ram devices
- sUseLifecycleThreadPool = sUseLifecycleThreadPool
- && !ActivityManager.isLowRamDeviceStatic();
mNumUserPoolThreads = Math.min(Runtime.getRuntime().availableProcessors(),
DEFAULT_MAX_USER_POOL_THREADS);
}
@@ -551,16 +546,10 @@
terminated = threadPool.awaitTermination(
USER_POOL_SHUTDOWN_TIMEOUT_SECONDS, TimeUnit.SECONDS);
} catch (InterruptedException e) {
- Slog.wtf(TAG, "User lifecycle thread pool was interrupted while awaiting completion"
- + " of " + onWhat + " of user " + curUser, e);
- if (!onWhat.equals(USER_COMPLETED_EVENT)) {
- Slog.e(TAG, "Couldn't terminate, disabling thread pool. "
- + "Please capture a bug report.");
- sUseLifecycleThreadPool = false;
- }
+ logFailure(onWhat, curUser, "(user lifecycle threadpool was interrupted)", e);
}
if (!terminated) {
- Slog.wtf(TAG, "User lifecycle thread pool was not terminated.");
+ logFailure(onWhat, curUser, "(user lifecycle threadpool was not terminated)", null);
}
}
t.traceEnd(); // main entry
@@ -575,9 +564,9 @@
private boolean useThreadPool(int userId, @NonNull String onWhat) {
switch (onWhat) {
case USER_STARTING:
- // Limit the lifecycle parallelization to all users other than the system user
- // and only for the user start lifecycle phase for now.
- return sUseLifecycleThreadPool && userId != UserHandle.USER_SYSTEM;
+ // Don't allow lifecycle parallelization for user start on low ram devices and
+ // the system user.
+ return !ActivityManager.isLowRamDeviceStatic() && userId != UserHandle.USER_SYSTEM;
case USER_COMPLETED_EVENT:
return true;
default:
@@ -611,8 +600,6 @@
"on" + USER_STARTING + "User-" + curUserId);
} catch (Exception e) {
logFailure(USER_STARTING, curUser, serviceName, e);
- Slog.e(TAG, "Disabling thread pool - please capture a bug report.");
- sUseLifecycleThreadPool = false;
} finally {
t.traceEnd();
}
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 93cdc9d..ee4bc24 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -3075,42 +3075,88 @@
Binder.restoreCallingIdentity(ident);
}
+ // Send the broadcast exactly once to all possible disjoint sets of apps.
+ // If the location master switch is on, broadcast the ServiceState 4 times:
+ // - Full ServiceState sent to apps with ACCESS_FINE_LOCATION and READ_PHONE_STATE
+ // - Full ServiceState sent to apps with ACCESS_FINE_LOCATION and
+ // READ_PRIVILEGED_PHONE_STATE but not READ_PHONE_STATE
+ // - Sanitized ServiceState sent to apps with READ_PHONE_STATE but not ACCESS_FINE_LOCATION
+ // - Sanitized ServiceState sent to apps with READ_PRIVILEGED_PHONE_STATE but neither
+ // READ_PHONE_STATE nor ACCESS_FINE_LOCATION
+ // If the location master switch is off, broadcast the ServiceState multiple times:
+ // - Full ServiceState sent to all apps permitted to bypass the location master switch if
+ // they have either READ_PHONE_STATE or READ_PRIVILEGED_PHONE_STATE
+ // - Sanitized ServiceState sent to all other apps with READ_PHONE_STATE
+ // - Sanitized ServiceState sent to all other apps with READ_PRIVILEGED_PHONE_STATE but not
+ // READ_PHONE_STATE
+ if (Binder.withCleanCallingIdentity(() ->
+ LocationAccessPolicy.isLocationModeEnabled(mContext, mContext.getUserId()))) {
+ Intent fullIntent = createServiceStateIntent(state, subId, phoneId, false);
+ mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions(
+ fullIntent,
+ new String[]{Manifest.permission.READ_PHONE_STATE,
+ Manifest.permission.ACCESS_FINE_LOCATION});
+ mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions(
+ fullIntent,
+ new String[]{Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
+ Manifest.permission.ACCESS_FINE_LOCATION},
+ new String[]{Manifest.permission.READ_PHONE_STATE});
+
+ Intent sanitizedIntent = createServiceStateIntent(state, subId, phoneId, true);
+ mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions(
+ sanitizedIntent,
+ new String[]{Manifest.permission.READ_PHONE_STATE},
+ new String[]{Manifest.permission.ACCESS_FINE_LOCATION});
+ mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions(
+ sanitizedIntent,
+ new String[]{Manifest.permission.READ_PRIVILEGED_PHONE_STATE},
+ new String[]{Manifest.permission.READ_PHONE_STATE,
+ Manifest.permission.ACCESS_FINE_LOCATION});
+ } else {
+ String[] locationBypassPackages = Binder.withCleanCallingIdentity(() ->
+ LocationAccessPolicy.getLocationBypassPackages(mContext));
+ for (String locationBypassPackage : locationBypassPackages) {
+ Intent fullIntent = createServiceStateIntent(state, subId, phoneId, false);
+ fullIntent.setPackage(locationBypassPackage);
+ mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions(
+ fullIntent,
+ new String[]{Manifest.permission.READ_PHONE_STATE});
+ mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions(
+ fullIntent,
+ new String[]{Manifest.permission.READ_PRIVILEGED_PHONE_STATE},
+ new String[]{Manifest.permission.READ_PHONE_STATE});
+ }
+
+ Intent sanitizedIntent = createServiceStateIntent(state, subId, phoneId, true);
+ mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions(
+ sanitizedIntent,
+ new String[]{Manifest.permission.READ_PHONE_STATE},
+ new String[]{/* no excluded permissions */},
+ locationBypassPackages);
+ mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions(
+ sanitizedIntent,
+ new String[]{Manifest.permission.READ_PRIVILEGED_PHONE_STATE},
+ new String[]{Manifest.permission.READ_PHONE_STATE},
+ locationBypassPackages);
+ }
+ }
+
+ private Intent createServiceStateIntent(ServiceState state, int subId, int phoneId,
+ boolean sanitizeLocation) {
Intent intent = new Intent(Intent.ACTION_SERVICE_STATE);
intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
Bundle data = new Bundle();
- state.fillInNotifierBundle(data);
+ if (sanitizeLocation) {
+ state.createLocationInfoSanitizedCopy(true).fillInNotifierBundle(data);
+ } else {
+ state.fillInNotifierBundle(data);
+ }
intent.putExtras(data);
- // Pass the subscription along with the intent.
intent.putExtra(PHONE_CONSTANTS_SUBSCRIPTION_KEY, subId);
intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, subId);
intent.putExtra(PHONE_CONSTANTS_SLOT_KEY, phoneId);
intent.putExtra(SubscriptionManager.EXTRA_SLOT_INDEX, phoneId);
-
- // Send the broadcast twice -- once for all apps with READ_PHONE_STATE, then again
- // for all apps with READ_PRIVILEGED_PHONE_STATE but not READ_PHONE_STATE.
- // Do this again twice, the first time for apps with ACCESS_FINE_LOCATION, then again with
- // the location-sanitized service state for all apps without ACCESS_FINE_LOCATION.
- // This ensures that any app holding either READ_PRIVILEGED_PHONE_STATE or READ_PHONE_STATE
- // get this broadcast exactly once, and we are not exposing location without permission.
- mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions(intent,
- new String[] {Manifest.permission.READ_PHONE_STATE,
- Manifest.permission.ACCESS_FINE_LOCATION});
- mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions(intent,
- new String[] {Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
- Manifest.permission.ACCESS_FINE_LOCATION},
- new String[] {Manifest.permission.READ_PHONE_STATE});
-
- // Replace bundle with location-sanitized ServiceState
- data = new Bundle();
- state.createLocationInfoSanitizedCopy(true).fillInNotifierBundle(data);
- intent.putExtras(data);
- mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions(intent,
- new String[] {Manifest.permission.READ_PHONE_STATE},
- new String[] {Manifest.permission.ACCESS_FINE_LOCATION});
- mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions(intent,
- new String[] {Manifest.permission.READ_PRIVILEGED_PHONE_STATE},
- new String[] {Manifest.permission.READ_PHONE_STATE,
- Manifest.permission.ACCESS_FINE_LOCATION});
+ return intent;
}
private void broadcastSignalStrengthChanged(SignalStrength signalStrength, int phoneId,
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index 6092f16..fe47369 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -19,6 +19,8 @@
import static com.android.server.Watchdog.HandlerCheckerAndTimeout.withCustomTimeout;
import static com.android.server.Watchdog.HandlerCheckerAndTimeout.withDefaultTimeout;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.IActivityController;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -43,6 +45,7 @@
import android.os.UserHandle;
import android.provider.Settings;
import android.sysprop.WatchdogProperties;
+import android.util.Dumpable;
import android.util.EventLog;
import android.util.Log;
import android.util.Slog;
@@ -63,6 +66,7 @@
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
+import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Arrays;
@@ -76,7 +80,7 @@
/**
* This class calls its monitor every minute. Killing this process if they don't return
**/
-public class Watchdog {
+public class Watchdog implements Dumpable {
static final String TAG = "Watchdog";
/** Debug flag. */
@@ -1034,4 +1038,10 @@
}
doSysRq('c');
}
+
+ @Override
+ public void dump(@NonNull PrintWriter pw, @Nullable String[] args) {
+ pw.print("WatchdogTimeoutMillis=");
+ pw.println(mWatchdogTimeoutMillis);
+ }
}
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 6fa3bc8..48b3d0e 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -6476,10 +6476,16 @@
}
if (ret == REASON_DENIED) {
- final boolean isAllowedPackage =
- mAllowListWhileInUsePermissionInFgs.contains(callingPackage);
- if (isAllowedPackage) {
- ret = REASON_ALLOWLISTED_PACKAGE;
+ if (verifyPackage(callingPackage, callingUid)) {
+ final boolean isAllowedPackage =
+ mAllowListWhileInUsePermissionInFgs.contains(callingPackage);
+ if (isAllowedPackage) {
+ ret = REASON_ALLOWLISTED_PACKAGE;
+ }
+ } else {
+ EventLog.writeEvent(0x534e4554, "215003903", callingUid,
+ "callingPackage:" + callingPackage + " does not belong to callingUid:"
+ + callingUid);
}
}
@@ -6593,12 +6599,11 @@
}
final int uidState = mAm.getUidStateLocked(callingUid);
- int callerTargetSdkVersion = INVALID_UID;
+ int callerTargetSdkVersion = -1;
try {
- ApplicationInfo ai = mAm.mContext.getPackageManager().getApplicationInfoAsUser(
- callingPackage, PackageManager.MATCH_KNOWN_PACKAGES, userId);
- callerTargetSdkVersion = ai.targetSdkVersion;
- } catch (PackageManager.NameNotFoundException e) {
+ callerTargetSdkVersion = mAm.mContext.getPackageManager()
+ .getTargetSdkVersion(callingPackage);
+ } catch (PackageManager.NameNotFoundException ignored) {
}
final String debugInfo =
"[callingPackage: " + callingPackage
@@ -6883,4 +6888,19 @@
/* allowBackgroundActivityStarts */ false)
!= REASON_DENIED;
}
+
+ /**
+ * Checks if a given packageName belongs to a given uid.
+ * @param packageName the package of the caller
+ * @param uid the uid of the caller
+ * @return true or false
+ */
+ private boolean verifyPackage(String packageName, int uid) {
+ if (uid == ROOT_UID || uid == SYSTEM_UID) {
+ //System and Root are always allowed
+ return true;
+ }
+ return mAm.getPackageManagerInternal().isSameApp(packageName, uid,
+ UserHandle.getUserId(uid));
+ }
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index d4480f8..cb22dae 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1531,6 +1531,8 @@
// Encapsulates the global setting "hidden_api_blacklist_exemptions"
final HiddenApiSettings mHiddenApiBlacklist;
+ final SdkSandboxSettings mSdkSandboxSettings;
+
private final PlatformCompat mPlatformCompat;
PackageManagerInternal mPackageManagerInt;
@@ -2236,6 +2238,53 @@
}
}
+ /**
+ * Handles settings related to the enforcement of SDK sandbox restrictions.
+ */
+ static class SdkSandboxSettings implements DeviceConfig.OnPropertiesChangedListener {
+
+ private final Context mContext;
+ private final Object mLock = new Object();
+
+ @GuardedBy("mLock")
+ private boolean mEnforceBroadcastReceiverRestrictions;
+
+ /**
+ * Property to enforce broadcast receiver restrictions for SDK sandbox processes. If the
+ * value of this property is {@code true}, the restrictions will be enforced.
+ */
+ public static final String ENFORCE_BROADCAST_RECEIVER_RESTRICTIONS =
+ "enforce_broadcast_receiver_restrictions";
+
+ SdkSandboxSettings(Context context) {
+ mContext = context;
+ }
+
+ void registerObserver() {
+ synchronized (mLock) {
+ mEnforceBroadcastReceiverRestrictions = DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_SDK_SANDBOX,
+ ENFORCE_BROADCAST_RECEIVER_RESTRICTIONS, false);
+ DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SDK_SANDBOX,
+ mContext.getMainExecutor(), this);
+ }
+ }
+
+ @Override
+ public void onPropertiesChanged(DeviceConfig.Properties properties) {
+ synchronized (mLock) {
+ mEnforceBroadcastReceiverRestrictions = properties.getBoolean(
+ ENFORCE_BROADCAST_RECEIVER_RESTRICTIONS, false);
+ }
+ }
+
+ boolean isBroadcastReceiverRestrictionsEnforced() {
+ synchronized (mLock) {
+ return mEnforceBroadcastReceiverRestrictions;
+ }
+ }
+ }
+
AppOpsManager getAppOpsManager() {
if (mAppOpsManager == null) {
mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
@@ -2278,6 +2327,7 @@
mProcStartHandlerThread = null;
mProcStartHandler = null;
mHiddenApiBlacklist = null;
+ mSdkSandboxSettings = null;
mFactoryTest = FACTORY_TEST_OFF;
mUgmInternal = LocalServices.getService(UriGrantsManagerInternal.class);
mInternal = new LocalService();
@@ -2397,6 +2447,7 @@
mAtmInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
mHiddenApiBlacklist = new HiddenApiSettings(mHandler, mContext);
+ mSdkSandboxSettings = new SdkSandboxSettings(mContext);
Watchdog.getInstance().addMonitor(this);
Watchdog.getInstance().addThread(mHandler);
@@ -2618,7 +2669,7 @@
public void batterySendBroadcast(Intent intent) {
synchronized (this) {
broadcastIntentLocked(null, null, null, intent, null, null, 0, null, null, null, null,
- OP_NONE, null, false, false, -1, SYSTEM_UID, Binder.getCallingUid(),
+ null, OP_NONE, null, false, false, -1, SYSTEM_UID, Binder.getCallingUid(),
Binder.getCallingPid(), UserHandle.USER_ALL);
}
}
@@ -4237,11 +4288,11 @@
broadcastIntentLocked(null /* callerApp */, null /* callerPackage */,
null /* callerFeatureId */, intent, null /* resolvedType */, null /* resultTo */,
0 /* resultCode */, null /* resultData */, null /* resultExtras */,
- null /* requiredPermissions */, null /* excludedPermissions */, OP_NONE,
- null /* bOptions */, false /* ordered */, false /* sticky */, MY_PID, SYSTEM_UID,
- Binder.getCallingUid(), Binder.getCallingPid(), userId,
- false /* allowBackgroundActivityStarts */, null /* backgroundActivityStartsToken */,
- broadcastAllowList);
+ null /* requiredPermissions */, null /* excludedPermissions */,
+ null /* excludedPackages */, OP_NONE, null /* bOptions */, false /* ordered */,
+ false /* sticky */, MY_PID, SYSTEM_UID, Binder.getCallingUid(),
+ Binder.getCallingPid(), userId, false /* allowBackgroundActivityStarts */,
+ null /* backgroundActivityStartsToken */, broadcastAllowList);
}
private void cleanupDisabledPackageComponentsLocked(
@@ -4798,7 +4849,8 @@
thread.runIsolatedEntryPoint(
app.getIsolatedEntryPoint(), app.getIsolatedEntryPointArgs());
} else if (instr2 != null) {
- thread.bindApplication(processName, appInfo, app.sdkSandboxClientAppPackage,
+ thread.bindApplication(processName, appInfo,
+ app.sdkSandboxClientAppVolumeUuid, app.sdkSandboxClientAppPackage,
providerList,
instr2.mClass,
profilerInfo, instr2.mArguments,
@@ -4813,7 +4865,8 @@
app.getDisabledCompatChanges(), serializedSystemFontMap,
app.getStartElapsedTime(), app.getStartUptime());
} else {
- thread.bindApplication(processName, appInfo, app.sdkSandboxClientAppPackage,
+ thread.bindApplication(processName, appInfo,
+ app.sdkSandboxClientAppVolumeUuid, app.sdkSandboxClientAppPackage,
providerList, null, profilerInfo, null, null, null, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
isRestrictedBackupMode || !normalMode, app.isPersistent(),
@@ -7904,6 +7957,7 @@
final boolean alwaysFinishActivities =
Settings.Global.getInt(resolver, ALWAYS_FINISH_ACTIVITIES, 0) != 0;
mHiddenApiBlacklist.registerObserver();
+ mSdkSandboxSettings.registerObserver();
mPlatformCompat.registerContentObserver();
mAppProfiler.retrieveSettings();
@@ -8078,8 +8132,8 @@
// do this when the system user is not setup since the setup wizard should be the one
// to handle home activity in this case.
if (UserManager.isSplitSystemUser() &&
- Settings.Secure.getInt(mContext.getContentResolver(),
- Settings.Secure.USER_SETUP_COMPLETE, 0) != 0
+ Settings.Secure.getIntForUser(mContext.getContentResolver(),
+ Settings.Secure.USER_SETUP_COMPLETE, 0, currentUserId) != 0
|| SystemProperties.getBoolean(SYSTEM_USER_HOME_NEEDED, false)) {
t.traceBegin("enableHomeActivity");
ComponentName cName = new ComponentName(mContext, SystemUserHomeActivity.class);
@@ -8115,7 +8169,7 @@
| Intent.FLAG_RECEIVER_FOREGROUND);
intent.putExtra(Intent.EXTRA_USER_HANDLE, currentUserId);
broadcastIntentLocked(null, null, null, intent,
- null, null, 0, null, null, null, null, OP_NONE,
+ null, null, 0, null, null, null, null, null, OP_NONE,
null, false, false, MY_PID, SYSTEM_UID, callingUid, callingPid,
currentUserId);
intent = new Intent(Intent.ACTION_USER_STARTING);
@@ -8127,8 +8181,8 @@
public void performReceive(Intent intent, int resultCode,
String data, Bundle extras, boolean ordered, boolean sticky,
int sendingUser) {}
- }, 0, null, null, new String[] {INTERACT_ACROSS_USERS}, null, OP_NONE,
- null, true, false, MY_PID, SYSTEM_UID, callingUid, callingPid,
+ }, 0, null, null, new String[] {INTERACT_ACROSS_USERS}, null, null,
+ OP_NONE, null, true, false, MY_PID, SYSTEM_UID, callingUid, callingPid,
UserHandle.USER_ALL);
} catch (Throwable e) {
Slog.wtf(TAG, "Failed sending first user broadcasts", e);
@@ -12975,7 +13029,7 @@
// Allow Sandbox process to register only unexported receivers.
if ((flags & Context.RECEIVER_NOT_EXPORTED) != 0) {
enforceNotIsolatedCaller("registerReceiver");
- } else {
+ } else if (mSdkSandboxSettings.isBroadcastReceiverRestrictionsEnforced()) {
enforceNotIsolatedOrSdkSandboxCaller("registerReceiver");
}
ArrayList<Intent> stickyIntents = null;
@@ -13200,8 +13254,8 @@
Intent intent = allSticky.get(i);
BroadcastQueue queue = broadcastQueueForIntent(intent);
BroadcastRecord r = new BroadcastRecord(queue, intent, null,
- null, null, -1, -1, false, null, null, null, OP_NONE, null, receivers,
- null, 0, null, null, false, true, true, -1, false, null,
+ null, null, -1, -1, false, null, null, null, null, OP_NONE, null,
+ receivers, null, 0, null, null, false, true, true, -1, false, null,
false /* only PRE_BOOT_COMPLETED should be exempt, no stickies */);
queue.enqueueParallelBroadcastLocked(r);
queue.scheduleBroadcastsLocked();
@@ -13283,8 +13337,8 @@
UserManager.DISALLOW_DEBUGGING_FEATURES, user)) {
continue;
}
- List<ResolveInfo> newReceivers = mPackageManagerInt
- .queryIntentReceivers(intent, resolvedType, pmFlags, callingUid, user);
+ List<ResolveInfo> newReceivers = mPackageManagerInt.queryIntentReceivers(
+ intent, resolvedType, pmFlags, callingUid, user, true /* forSend */);
if (user != UserHandle.USER_SYSTEM && newReceivers != null) {
// If this is not the system user, we need to check for
// any receivers that should be filtered out.
@@ -13300,8 +13354,9 @@
if (newReceivers != null) {
for (int i = newReceivers.size() - 1; i >= 0; i--) {
final ResolveInfo ri = newReceivers.get(i);
- final Resolution<ResolveInfo> resolution = mComponentAliasResolver
- .resolveReceiver(intent, ri, resolvedType, pmFlags, user, callingUid);
+ final Resolution<ResolveInfo> resolution =
+ mComponentAliasResolver.resolveReceiver(intent, ri, resolvedType,
+ pmFlags, user, callingUid, true /* forSend */);
if (resolution == null) {
// It was an alias, but the target was not found.
newReceivers.remove(i);
@@ -13456,12 +13511,14 @@
String callerPackage, String callerFeatureId, Intent intent, String resolvedType,
IIntentReceiver resultTo, int resultCode, String resultData,
Bundle resultExtras, String[] requiredPermissions, String[] excludedPermissions,
- int appOp, Bundle bOptions, boolean ordered, boolean sticky, int callingPid,
+ String[] excludedPackages, int appOp, Bundle bOptions, boolean ordered,
+ boolean sticky, int callingPid,
int callingUid, int realCallingUid, int realCallingPid, int userId) {
return broadcastIntentLocked(callerApp, callerPackage, callerFeatureId, intent,
resolvedType, resultTo, resultCode, resultData, resultExtras, requiredPermissions,
- excludedPermissions, appOp, bOptions, ordered, sticky, callingPid, callingUid,
- realCallingUid, realCallingPid, userId, false /* allowBackgroundActivityStarts */,
+ excludedPermissions, excludedPackages, appOp, bOptions, ordered, sticky, callingPid,
+ callingUid, realCallingUid, realCallingPid, userId,
+ false /* allowBackgroundActivityStarts */,
null /* tokenNeededForBackgroundActivityStarts */, null /* broadcastAllowList */);
}
@@ -13470,7 +13527,7 @@
@Nullable String callerFeatureId, Intent intent, String resolvedType,
IIntentReceiver resultTo, int resultCode, String resultData,
Bundle resultExtras, String[] requiredPermissions,
- String[] excludedPermissions, int appOp, Bundle bOptions,
+ String[] excludedPermissions, String[] excludedPackages, int appOp, Bundle bOptions,
boolean ordered, boolean sticky, int callingPid, int callingUid,
int realCallingUid, int realCallingPid, int userId,
boolean allowBackgroundActivityStarts,
@@ -14077,10 +14134,10 @@
final BroadcastQueue queue = broadcastQueueForIntent(intent);
BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage,
callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,
- requiredPermissions, excludedPermissions, appOp, brOptions, registeredReceivers,
- resultTo, resultCode, resultData, resultExtras, ordered, sticky, false, userId,
- allowBackgroundActivityStarts, backgroundActivityStartsToken,
- timeoutExempt);
+ requiredPermissions, excludedPermissions, excludedPackages, appOp, brOptions,
+ registeredReceivers, resultTo, resultCode, resultData, resultExtras, ordered,
+ sticky, false, userId, allowBackgroundActivityStarts,
+ backgroundActivityStartsToken, timeoutExempt);
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing parallel broadcast " + r);
final boolean replaced = replacePending
&& (queue.replaceParallelBroadcastLocked(r) != null);
@@ -14175,7 +14232,7 @@
BroadcastQueue queue = broadcastQueueForIntent(intent);
BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage,
callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,
- requiredPermissions, excludedPermissions, appOp, brOptions,
+ requiredPermissions, excludedPermissions, excludedPackages, appOp, brOptions,
receivers, resultTo, resultCode, resultData, resultExtras,
ordered, sticky, false, userId, allowBackgroundActivityStarts,
backgroundActivityStartsToken, timeoutExempt);
@@ -14304,14 +14361,16 @@
String[] requiredPermissions, int appOp, Bundle bOptions,
boolean serialized, boolean sticky, int userId) {
return broadcastIntentWithFeature(caller, null, intent, resolvedType, resultTo, resultCode,
- resultData, resultExtras, requiredPermissions, null, appOp, bOptions, serialized,
- sticky, userId);
+ resultData, resultExtras, requiredPermissions, null, null, appOp, bOptions,
+ serialized, sticky, userId);
}
+ @Override
public final int broadcastIntentWithFeature(IApplicationThread caller, String callingFeatureId,
Intent intent, String resolvedType, IIntentReceiver resultTo,
int resultCode, String resultData, Bundle resultExtras,
- String[] requiredPermissions, String[] excludedPermissions, int appOp, Bundle bOptions,
+ String[] requiredPermissions, String[] excludedPermissions,
+ String[] excludedPackages, int appOp, Bundle bOptions,
boolean serialized, boolean sticky, int userId) {
enforceNotIsolatedCaller("broadcastIntent");
synchronized(this) {
@@ -14326,8 +14385,8 @@
return broadcastIntentLocked(callerApp,
callerApp != null ? callerApp.info.packageName : null, callingFeatureId,
intent, resolvedType, resultTo, resultCode, resultData, resultExtras,
- requiredPermissions, excludedPermissions, appOp, bOptions, serialized,
- sticky, callingPid, callingUid, callingUid, callingPid, userId);
+ requiredPermissions, excludedPermissions, excludedPackages, appOp, bOptions,
+ serialized, sticky, callingPid, callingUid, callingUid, callingPid, userId);
} finally {
Binder.restoreCallingIdentity(origId);
}
@@ -14350,7 +14409,7 @@
try {
return broadcastIntentLocked(null, packageName, featureId, intent, resolvedType,
resultTo, resultCode, resultData, resultExtras, requiredPermissions, null,
- OP_NONE, bOptions, serialized, sticky, -1, uid, realCallingUid,
+ null, OP_NONE, bOptions, serialized, sticky, -1, uid, realCallingUid,
realCallingPid, userId, allowBackgroundActivityStarts,
backgroundActivityStartsToken, broadcastAllowList);
} finally {
@@ -16873,10 +16932,11 @@
return ActivityManagerService.this.broadcastIntentLocked(null /*callerApp*/,
null /*callerPackage*/, null /*callingFeatureId*/, intent,
null /*resolvedType*/, resultTo, 0 /*resultCode*/, null /*resultData*/,
- null /*resultExtras*/, requiredPermissions, null, AppOpsManager.OP_NONE,
- bOptions /*options*/, serialized, false /*sticky*/, callingPid,
- callingUid, callingUid, callingPid, userId,
- false /*allowBackgroundStarts*/,
+ null /*resultExtras*/, requiredPermissions,
+ null /*excludedPermissions*/, null /*excludedPackages*/,
+ AppOpsManager.OP_NONE, bOptions /*options*/, serialized,
+ false /*sticky*/, callingPid, callingUid, callingUid, callingPid,
+ userId, false /*allowBackgroundStarts*/,
null /*tokenNeededForBackgroundActivityStarts*/, appIdAllowList);
} finally {
Binder.restoreCallingIdentity(origId);
@@ -17012,7 +17072,7 @@
| Intent.FLAG_RECEIVER_FOREGROUND
| Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
broadcastIntentLocked(null, null, null, intent, null, null, 0, null, null, null,
- null, OP_NONE, null, false, false, MY_PID, SYSTEM_UID,
+ null, null, OP_NONE, null, false, false, MY_PID, SYSTEM_UID,
Binder.getCallingUid(), Binder.getCallingPid(), UserHandle.USER_ALL);
if ((changes & ActivityInfo.CONFIG_LOCALE) != 0) {
intent = new Intent(Intent.ACTION_LOCALE_CHANGED);
@@ -17027,8 +17087,8 @@
TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
PowerExemptionManager.REASON_LOCALE_CHANGED, "");
broadcastIntentLocked(null, null, null, intent, null, null, 0, null, null, null,
- null, OP_NONE, bOptions.toBundle(), false, false, MY_PID, SYSTEM_UID,
- Binder.getCallingUid(), Binder.getCallingPid(),
+ null, null, OP_NONE, bOptions.toBundle(), false, false, MY_PID,
+ SYSTEM_UID, Binder.getCallingUid(), Binder.getCallingPid(),
UserHandle.USER_ALL);
}
@@ -17043,8 +17103,9 @@
String[] permissions =
new String[] { android.Manifest.permission.INSTALL_PACKAGES };
broadcastIntentLocked(null, null, null, intent, null, null, 0, null, null,
- permissions, null, OP_NONE, null, false, false, MY_PID, SYSTEM_UID,
- Binder.getCallingUid(), Binder.getCallingPid(), UserHandle.USER_ALL);
+ permissions, null, null, OP_NONE, null, false, false, MY_PID,
+ SYSTEM_UID, Binder.getCallingUid(), Binder.getCallingPid(),
+ UserHandle.USER_ALL);
}
}
}
@@ -17068,8 +17129,8 @@
}
broadcastIntentLocked(null, null, null, intent, null, null, 0, null, null, null,
- null, OP_NONE, null, false, false, -1, SYSTEM_UID, Binder.getCallingUid(),
- Binder.getCallingPid(), UserHandle.USER_ALL);
+ null, null, OP_NONE, null, false, false, -1, SYSTEM_UID,
+ Binder.getCallingUid(), Binder.getCallingPid(), UserHandle.USER_ALL);
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 402491d..f83d444 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -183,7 +183,7 @@
private boolean mAsync;
private BroadcastOptions mBroadcastOptions;
private boolean mShowSplashScreen;
- private boolean mDismissKeyguardIfInsecure;
+ private boolean mDismissKeyguard;
final boolean mDumping;
@@ -442,8 +442,8 @@
mAsync = true;
} else if (opt.equals("--splashscreen-show-icon")) {
mShowSplashScreen = true;
- } else if (opt.equals("--dismiss-keyguard-if-insecure")) {
- mDismissKeyguardIfInsecure = true;
+ } else if (opt.equals("--dismiss-keyguard")) {
+ mDismissKeyguard = true;
} else {
return false;
}
@@ -588,11 +588,11 @@
}
options.setSplashScreenStyle(SplashScreen.SPLASH_SCREEN_STYLE_ICON);
}
- if (mDismissKeyguardIfInsecure) {
+ if (mDismissKeyguard) {
if (options == null) {
options = ActivityOptions.makeBasic();
}
- options.setDismissKeyguardIfInsecure();
+ options.setDismissKeyguard();
}
if (mWaitOption) {
result = mInternal.startActivityAndWait(null, SHELL_PACKAGE_NAME, null, intent,
@@ -804,8 +804,8 @@
pw.flush();
Bundle bundle = mBroadcastOptions == null ? null : mBroadcastOptions.toBundle();
mInterface.broadcastIntentWithFeature(null, null, intent, null, receiver, 0, null, null,
- requiredPermissions, null, android.app.AppOpsManager.OP_NONE, bundle, true, false,
- mUserId);
+ requiredPermissions, null, null, android.app.AppOpsManager.OP_NONE, bundle, true,
+ false, mUserId);
if (!mAsync) {
receiver.waitForFinish();
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerUtils.java b/services/core/java/com/android/server/am/ActivityManagerUtils.java
index 5506ad1..9be553c 100644
--- a/services/core/java/com/android/server/am/ActivityManagerUtils.java
+++ b/services/core/java/com/android/server/am/ActivityManagerUtils.java
@@ -16,6 +16,7 @@
package com.android.server.am;
import android.app.ActivityThread;
+import android.content.ContentResolver;
import android.provider.Settings;
import android.util.ArrayMap;
@@ -53,9 +54,12 @@
static int getAndroidIdHash() {
// No synchronization is required. Double-initialization is fine here.
if (sAndroidIdHash == null) {
- final String androidId = Settings.Secure.getString(
- ActivityThread.currentApplication().getContentResolver(),
- Settings.Secure.ANDROID_ID);
+ final ContentResolver resolver = ActivityThread.currentApplication()
+ .getContentResolver();
+ final String androidId = Settings.Secure.getStringForUser(
+ resolver,
+ Settings.Secure.ANDROID_ID,
+ resolver.getUserId());
sAndroidIdHash = getUnsignedHashUnCached(
sInjectedAndroidId != null ? sInjectedAndroidId : androidId);
}
diff --git a/services/core/java/com/android/server/am/AppBatteryTracker.java b/services/core/java/com/android/server/am/AppBatteryTracker.java
index c09bb2d..1a566a9 100644
--- a/services/core/java/com/android/server/am/AppBatteryTracker.java
+++ b/services/core/java/com/android/server/am/AppBatteryTracker.java
@@ -1258,6 +1258,16 @@
+ "current_drain_event_duration_based_threshold_enabled";
/**
+ * Whether or not we should move the app into the restricted bucket level if its background
+ * battery usage goes beyond the threshold. Note this different from the flag
+ * {@link AppRestrictionController.ConstantsObserver#KEY_BG_AUTO_RESTRICT_ABUSIVE_APPS}
+ * which is to control the overall auto bg restrictions.
+ */
+ static final String KEY_BG_CURRENT_DRAIN_AUTO_RESTRICT_ABUSIVE_APPS_ENABLED =
+ DEVICE_CONFIG_SUBNAMESPACE_PREFIX
+ + "current_drain_auto_restrict_abusive_apps_enabled";
+
+ /**
* The types of battery drain we're checking on each app; if the sum of the battery drain
* exceeds the threshold, it'll be moved to restricted standby bucket; the type here
* must be one of, or combination of {@link #BATTERY_USAGE_TYPE_BACKGROUND},
@@ -1353,6 +1363,11 @@
final boolean mDefaultBgCurrentDrainEventDurationBasedThresholdEnabled;
/**
+ * Default value to {@link #mBgCurrentDrainAutoRestrictAbusiveAppsEnabled}.
+ */
+ final boolean mDefaultBgCurrentDrainAutoRestrictAbusiveAppsEnabled;
+
+ /**
* Default value to {@link #mBgCurrentDrainRestrictedBucketTypes}.
*/
final int mDefaultCurrentDrainTypesToRestrictedBucket;
@@ -1430,6 +1445,11 @@
volatile boolean mBgCurrentDrainEventDurationBasedThresholdEnabled;
/**
+ * @see #KEY_BG_CURRENT_DRAIN_AUTO_RESTRICT_ABUSIVE_APPS_ENABLED.
+ */
+ volatile boolean mBgCurrentDrainAutoRestrictAbusiveAppsEnabled;
+
+ /**
* @see #KEY_BG_CURRENT_DRAIN_TYPES_TO_RESTRICTED_BUCKET.
*/
volatile int mBgCurrentDrainRestrictedBucketTypes;
@@ -1520,6 +1540,8 @@
R.integer.config_bg_current_drain_location_min_duration) * 1_000;
mDefaultBgCurrentDrainEventDurationBasedThresholdEnabled = resources.getBoolean(
R.bool.config_bg_current_drain_event_duration_based_threshold_enabled);
+ mDefaultBgCurrentDrainAutoRestrictAbusiveAppsEnabled = resources.getBoolean(
+ R.bool.config_bg_current_drain_auto_restrict_abusive_apps);
mDefaultCurrentDrainTypesToRestrictedBucket = resources.getInteger(
R.integer.config_bg_current_drain_types_to_restricted_bucket);
mDefaultBgCurrentDrainTypesToBgRestricted = resources.getInteger(
@@ -1569,6 +1591,9 @@
case KEY_BG_CURRENT_DRAIN_POWER_COMPONENTS:
updateCurrentDrainThreshold();
break;
+ case KEY_BG_CURRENT_DRAIN_AUTO_RESTRICT_ABUSIVE_APPS_ENABLED:
+ updateBgCurrentDrainAutoRestrictAbusiveAppsEnabled();
+ break;
case KEY_BG_CURRENT_DRAIN_WINDOW:
updateCurrentDrainWindow();
break;
@@ -1701,6 +1726,13 @@
DEFAULT_BG_CURRENT_DRAIN_DECOUPLE_THRESHOLD);
}
+ private void updateBgCurrentDrainAutoRestrictAbusiveAppsEnabled() {
+ mBgCurrentDrainAutoRestrictAbusiveAppsEnabled = DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ KEY_BG_CURRENT_DRAIN_AUTO_RESTRICT_ABUSIVE_APPS_ENABLED,
+ mDefaultBgCurrentDrainAutoRestrictAbusiveAppsEnabled);
+ }
+
@Override
public void onSystemReady() {
mBatteryFullChargeMah =
@@ -1714,6 +1746,7 @@
updateCurrentDrainEventDurationBasedThresholdEnabled();
updateCurrentDrainExemptedTypes();
updateCurrentDrainDecoupleThresholds();
+ updateBgCurrentDrainAutoRestrictAbusiveAppsEnabled();
}
@Override
@@ -1728,9 +1761,12 @@
if (pair != null) {
final long lastInteractionTime = mLastInteractionTime.get(uid, 0L);
final long[] ts = pair.first;
- final int restrictedLevel = ts[TIME_STAMP_INDEX_RESTRICTED_BUCKET]
- > (lastInteractionTime + mBgCurrentDrainInteractionGracePeriodMs)
- && mTracker.mAppRestrictionController.isAutoRestrictAbusiveAppEnabled()
+ final boolean noInteractionRecently = ts[TIME_STAMP_INDEX_RESTRICTED_BUCKET]
+ > (lastInteractionTime + mBgCurrentDrainInteractionGracePeriodMs);
+ final boolean canRestrict =
+ mTracker.mAppRestrictionController.isAutoRestrictAbusiveAppEnabled()
+ && mBgCurrentDrainAutoRestrictAbusiveAppsEnabled;
+ final int restrictedLevel = noInteractionRecently && canRestrict
? RESTRICTION_LEVEL_RESTRICTED_BUCKET
: RESTRICTION_LEVEL_ADAPTIVE_BUCKET;
if (maxLevel > RESTRICTION_LEVEL_BACKGROUND_RESTRICTED) {
@@ -2066,6 +2102,10 @@
pw.print('=');
pw.println(mBgCurrentDrainEventDurationBasedThresholdEnabled);
pw.print(prefix);
+ pw.print(KEY_BG_CURRENT_DRAIN_AUTO_RESTRICT_ABUSIVE_APPS_ENABLED);
+ pw.print('=');
+ pw.println(mBgCurrentDrainAutoRestrictAbusiveAppsEnabled);
+ pw.print(prefix);
pw.print(KEY_BG_CURRENT_DRAIN_TYPES_TO_RESTRICTED_BUCKET);
pw.print('=');
pw.println(batteryUsageTypesToString(mBgCurrentDrainRestrictedBucketTypes));
diff --git a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
index 84969aa..702526a 100644
--- a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
+++ b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
@@ -320,12 +320,11 @@
}
@Override
- public Future<?> scheduleSyncDueToProcessStateChange(long delayMillis) {
+ public void scheduleSyncDueToProcessStateChange(int flags, long delayMillis) {
synchronized (BatteryExternalStatsWorker.this) {
mProcessStateSync = scheduleDelayedSyncLocked(mProcessStateSync,
- () -> scheduleSync("procstate-change", UPDATE_ON_PROC_STATE_CHANGE),
+ () -> scheduleSync("procstate-change", flags),
delayMillis);
- return mProcessStateSync;
}
}
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index dd7fb84..d2e40c5 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -860,6 +860,21 @@
}
}
+ // Check that the receiver does *not* belong to any of the excluded packages
+ if (!skip && r.excludedPackages != null && r.excludedPackages.length > 0) {
+ if (ArrayUtils.contains(r.excludedPackages, filter.packageName)) {
+ Slog.w(TAG, "Skipping delivery of excluded package "
+ + r.intent.toString()
+ + " to " + filter.receiverList.app
+ + " (pid=" + filter.receiverList.pid
+ + ", uid=" + filter.receiverList.uid + ")"
+ + " excludes package " + filter.packageName
+ + " due to sender " + r.callerPackage
+ + " (uid " + r.callingUid + ")");
+ skip = true;
+ }
+ }
+
// If the broadcast also requires an app op check that as well.
if (!skip && r.appOp != AppOpsManager.OP_NONE
&& mService.getAppOpsManager().noteOpNoThrow(r.appOp,
@@ -1721,6 +1736,19 @@
}
}
+ // Check that the receiver does *not* belong to any of the excluded packages
+ if (!skip && r.excludedPackages != null && r.excludedPackages.length > 0) {
+ if (ArrayUtils.contains(r.excludedPackages, component.getPackageName())) {
+ Slog.w(TAG, "Skipping delivery of excluded package "
+ + r.intent + " to "
+ + component.flattenToShortString()
+ + " excludes package " + component.getPackageName()
+ + " due to sender " + r.callerPackage
+ + " (uid " + r.callingUid + ")");
+ skip = true;
+ }
+ }
+
if (!skip && info.activityInfo.applicationInfo.uid != Process.SYSTEM_UID &&
r.requiredPermissions != null && r.requiredPermissions.length > 0) {
for (int i = 0; i < r.requiredPermissions.length; i++) {
diff --git a/services/core/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java
index 5343af2..19ffc173 100644
--- a/services/core/java/com/android/server/am/BroadcastRecord.java
+++ b/services/core/java/com/android/server/am/BroadcastRecord.java
@@ -75,6 +75,7 @@
final String resolvedType; // the resolved data type
final String[] requiredPermissions; // permissions the caller has required
final String[] excludedPermissions; // permissions to exclude
+ final String[] excludedPackages; // packages to exclude
final int appOp; // an app op that is associated with this broadcast
final BroadcastOptions options; // BroadcastOptions supplied by caller
final List receivers; // contains BroadcastFilter and ResolveInfo
@@ -162,6 +163,10 @@
pw.print(prefix); pw.print("excludedPermissions=");
pw.print(Arrays.toString(excludedPermissions));
}
+ if (excludedPackages != null && excludedPackages.length > 0) {
+ pw.print(prefix); pw.print("excludedPackages=");
+ pw.print(Arrays.toString(excludedPackages));
+ }
if (options != null) {
pw.print(prefix); pw.print("options="); pw.println(options.toBundle());
}
@@ -260,7 +265,8 @@
Intent _intent, ProcessRecord _callerApp, String _callerPackage,
@Nullable String _callerFeatureId, int _callingPid, int _callingUid,
boolean _callerInstantApp, String _resolvedType,
- String[] _requiredPermissions, String[] _excludedPermissions, int _appOp,
+ String[] _requiredPermissions, String[] _excludedPermissions,
+ String[] _excludedPackages, int _appOp,
BroadcastOptions _options, List _receivers, IIntentReceiver _resultTo, int _resultCode,
String _resultData, Bundle _resultExtras, boolean _serialized, boolean _sticky,
boolean _initialSticky, int _userId, boolean allowBackgroundActivityStarts,
@@ -280,6 +286,7 @@
resolvedType = _resolvedType;
requiredPermissions = _requiredPermissions;
excludedPermissions = _excludedPermissions;
+ excludedPackages = _excludedPackages;
appOp = _appOp;
options = _options;
receivers = _receivers;
@@ -321,6 +328,7 @@
resolvedType = from.resolvedType;
requiredPermissions = from.requiredPermissions;
excludedPermissions = from.excludedPermissions;
+ excludedPackages = from.excludedPackages;
appOp = from.appOp;
options = from.options;
receivers = from.receivers;
@@ -381,9 +389,10 @@
// build a new BroadcastRecord around that single-target list
BroadcastRecord split = new BroadcastRecord(queue, intent, callerApp, callerPackage,
callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,
- requiredPermissions, excludedPermissions, appOp, options, splitReceivers, resultTo,
- resultCode, resultData, resultExtras, ordered, sticky, initialSticky, userId,
- allowBackgroundActivityStarts, mBackgroundActivityStartsToken, timeoutExempt);
+ requiredPermissions, excludedPermissions, excludedPackages, appOp, options,
+ splitReceivers, resultTo, resultCode, resultData, resultExtras, ordered, sticky,
+ initialSticky, userId, allowBackgroundActivityStarts,
+ mBackgroundActivityStartsToken, timeoutExempt);
split.enqueueTime = this.enqueueTime;
split.enqueueRealTime = this.enqueueRealTime;
split.enqueueClockTime = this.enqueueClockTime;
@@ -459,7 +468,7 @@
for (int i = 0; i < uidSize; i++) {
final BroadcastRecord br = new BroadcastRecord(queue, intent, callerApp, callerPackage,
callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,
- requiredPermissions, excludedPermissions, appOp, options,
+ requiredPermissions, excludedPermissions, excludedPackages, appOp, options,
uid2receiverList.valueAt(i), null /* _resultTo */,
resultCode, resultData, resultExtras, ordered, sticky, initialSticky, userId,
allowBackgroundActivityStarts, mBackgroundActivityStartsToken, timeoutExempt);
diff --git a/services/core/java/com/android/server/am/ComponentAliasResolver.java b/services/core/java/com/android/server/am/ComponentAliasResolver.java
index 2db3b15..01735a7 100644
--- a/services/core/java/com/android/server/am/ComponentAliasResolver.java
+++ b/services/core/java/com/android/server/am/ComponentAliasResolver.java
@@ -483,7 +483,7 @@
@Nullable
public Resolution<ResolveInfo> resolveReceiver(@NonNull Intent intent,
@NonNull ResolveInfo receiver, @Nullable String resolvedType,
- int packageFlags, int userId, int callingUid) {
+ int packageFlags, int userId, int callingUid, boolean forSend) {
// Resolve this alias.
final Resolution<ComponentName> resolution = resolveComponentAlias(() ->
receiver.activityInfo.getComponentName());
@@ -506,8 +506,8 @@
i.setPackage(null);
i.setComponent(resolution.getTarget());
- List<ResolveInfo> resolved = pmi.queryIntentReceivers(i,
- resolvedType, packageFlags, callingUid, userId);
+ List<ResolveInfo> resolved = pmi.queryIntentReceivers(
+ i, resolvedType, packageFlags, callingUid, userId, forSend);
if (resolved == null || resolved.size() == 0) {
// Target component not found.
Slog.w(TAG, "Alias target " + target.flattenToShortString() + " not found");
diff --git a/services/core/java/com/android/server/am/PreBootBroadcaster.java b/services/core/java/com/android/server/am/PreBootBroadcaster.java
index 7562098..35f91ba 100644
--- a/services/core/java/com/android/server/am/PreBootBroadcaster.java
+++ b/services/core/java/com/android/server/am/PreBootBroadcaster.java
@@ -124,7 +124,7 @@
REASON_PRE_BOOT_COMPLETED, "");
synchronized (mService) {
mService.broadcastIntentLocked(null, null, null, mIntent, null, this, 0, null, null,
- null, null, AppOpsManager.OP_NONE, bOptions.toBundle(), true,
+ null, null, null, AppOpsManager.OP_NONE, bOptions.toBundle(), true,
false, ActivityManagerService.MY_PID,
Process.SYSTEM_UID, Binder.getCallingUid(), Binder.getCallingPid(), mUserId);
}
diff --git a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
index 7fe2700..a953f04 100644
--- a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
+++ b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
@@ -28,6 +28,7 @@
import android.app.ApplicationErrorReport;
import android.app.ApplicationExitInfo;
import android.content.ComponentName;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.IncrementalStatesInfo;
@@ -605,8 +606,11 @@
}
private boolean getShowBackground() {
- return Settings.Secure.getInt(mService.mContext.getContentResolver(),
- Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0;
+ final ContentResolver resolver = mService.mContext.getContentResolver();
+ return Settings.Secure.getIntForUser(resolver,
+ Settings.Secure.ANR_SHOW_BACKGROUND,
+ 0,
+ resolver.getUserId()) != 0;
}
/**
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index d8f7714..0d946395 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -2028,8 +2028,10 @@
mService.mProcessList.handlePredecessorProcDied((ProcessRecord) msg.obj);
break;
case MSG_PROCESS_KILL_TIMEOUT:
- mService.handleProcessStartOrKillTimeoutLocked((ProcessRecord) msg.obj,
- /* isKillTimeout */ true);
+ synchronized (mService) {
+ mService.handleProcessStartOrKillTimeoutLocked((ProcessRecord) msg.obj,
+ /* isKillTimeout */ true);
+ }
break;
}
}
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index b4ff870..ac5cb2d 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -87,6 +87,7 @@
final String processName; // name of the process
final String sdkSandboxClientAppPackage; // if this is an sdk sandbox process, name of the
// app package for which it is running
+ final String sdkSandboxClientAppVolumeUuid; // uuid of the app for which the sandbox is running
/**
* Overall state of process's uid.
@@ -535,6 +536,11 @@
userId = UserHandle.getUserId(_uid);
processName = _processName;
sdkSandboxClientAppPackage = _sdkSandboxClientAppPackage;
+ if (isSdkSandbox) {
+ sdkSandboxClientAppVolumeUuid = getClientInfoForSdkSandbox().volumeUuid;
+ } else {
+ sdkSandboxClientAppVolumeUuid = null;
+ }
mPersistent = false;
mRemoved = false;
mProfile = new ProcessProfileRecord(this);
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index c043773..7ffea26 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -3203,8 +3203,8 @@
synchronized (mService) {
return mService.broadcastIntentLocked(null, null, null, intent, resolvedType,
resultTo, resultCode, resultData, resultExtras, requiredPermissions, null,
- appOp, bOptions, ordered, sticky, callingPid, callingUid, realCallingUid,
- realCallingPid, userId);
+ null, appOp, bOptions, ordered, sticky, callingPid, callingUid,
+ realCallingUid, realCallingPid, userId);
}
}
diff --git a/services/core/java/com/android/server/apphibernation/AppHibernationService.java b/services/core/java/com/android/server/apphibernation/AppHibernationService.java
index d239c02..27ce493 100644
--- a/services/core/java/com/android/server/apphibernation/AppHibernationService.java
+++ b/services/core/java/com/android/server/apphibernation/AppHibernationService.java
@@ -501,6 +501,7 @@
null /* resultExtras */,
requiredPermissions,
null /* excludedPermissions */,
+ null /* excludedPackages */,
OP_NONE,
null /* bOptions */,
false /* serialized */,
@@ -519,6 +520,7 @@
null /* resultExtras */,
requiredPermissions,
null /* excludedPermissions */,
+ null /* excludedPackages */,
OP_NONE,
null /* bOptions */,
false /* serialized */,
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index f96542f..5c7af47 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -43,6 +43,7 @@
import static android.app.AppOpsManager.OP_FLAG_TRUSTED_PROXIED;
import static android.app.AppOpsManager.OP_NONE;
import static android.app.AppOpsManager.OP_PLAY_AUDIO;
+import static android.app.AppOpsManager.OP_RECEIVE_AMBIENT_TRIGGER_AUDIO;
import static android.app.AppOpsManager.OP_RECORD_AUDIO;
import static android.app.AppOpsManager.OP_RECORD_AUDIO_HOTWORD;
import static android.app.AppOpsManager.OnOpStartedListener.START_TYPE_FAILED;
@@ -3261,7 +3262,7 @@
return AppOpsManager.MODE_IGNORED;
}
synchronized (this) {
- if (isOpRestrictedLocked(uid, code, packageName, attributionTag, pvr.bypass)) {
+ if (isOpRestrictedLocked(uid, code, packageName, attributionTag, pvr.bypass, true)) {
return AppOpsManager.MODE_IGNORED;
}
code = AppOpsManager.opToSwitch(code);
@@ -3491,7 +3492,7 @@
final int switchCode = AppOpsManager.opToSwitch(code);
final UidState uidState = ops.uidState;
- if (isOpRestrictedLocked(uid, code, packageName, attributionTag, pvr.bypass)) {
+ if (isOpRestrictedLocked(uid, code, packageName, attributionTag, pvr.bypass, false)) {
attributedOp.rejected(uidState.state, flags);
scheduleOpNotedIfNeededLocked(code, uid, packageName, attributionTag, flags,
AppOpsManager.MODE_IGNORED);
@@ -3861,7 +3862,7 @@
// the data gated by OP_RECORD_AUDIO.
//
// TODO: Revert this change before Android 12.
- if (code == OP_RECORD_AUDIO_HOTWORD) {
+ if (code == OP_RECORD_AUDIO_HOTWORD || code == OP_RECEIVE_AMBIENT_TRIGGER_AUDIO) {
int result = checkOperation(OP_RECORD_AUDIO, uid, packageName);
if (result != AppOpsManager.MODE_ALLOWED) {
return new SyncNotedAppOp(result, code, attributionTag, packageName);
@@ -4011,7 +4012,8 @@
final Op op = getOpLocked(ops, code, uid, true);
final AttributedOp attributedOp = op.getOrCreateAttribution(op, attributionTag);
final UidState uidState = ops.uidState;
- isRestricted = isOpRestrictedLocked(uid, code, packageName, attributionTag, pvr.bypass);
+ isRestricted = isOpRestrictedLocked(uid, code, packageName, attributionTag, pvr.bypass,
+ false);
final int switchCode = AppOpsManager.opToSwitch(code);
// If there is a non-default per UID policy (we set UID op mode only if
// non-default) it takes over, otherwise use the per package policy.
@@ -4872,7 +4874,7 @@
}
private boolean isOpRestrictedLocked(int uid, int code, String packageName,
- String attributionTag, @Nullable RestrictionBypass appBypass) {
+ String attributionTag, @Nullable RestrictionBypass appBypass, boolean isCheckOp) {
int restrictionSetCount = mOpGlobalRestrictions.size();
for (int i = 0; i < restrictionSetCount; i++) {
@@ -4889,7 +4891,8 @@
// For each client, check that the given op is not restricted, or that the given
// package is exempt from the restriction.
ClientUserRestrictionState restrictionState = mOpUserRestrictions.valueAt(i);
- if (restrictionState.hasRestriction(code, packageName, attributionTag, userHandle)) {
+ if (restrictionState.hasRestriction(code, packageName, attributionTag, userHandle,
+ isCheckOp)) {
RestrictionBypass opBypass = opAllowSystemBypassRestriction(code);
if (opBypass != null) {
// If we are the system, bypass user restrictions for certain codes
@@ -7264,7 +7267,7 @@
}
public boolean hasRestriction(int restriction, String packageName, String attributionTag,
- int userId) {
+ int userId, boolean isCheckOp) {
if (perUserRestrictions == null) {
return false;
}
@@ -7283,6 +7286,9 @@
return true;
}
+ if (isCheckOp) {
+ return !perUserExclusions.includes(packageName);
+ }
return !perUserExclusions.contains(packageName, attributionTag);
}
@@ -7449,7 +7455,8 @@
int numRestrictions = mOpUserRestrictions.size();
for (int i = 0; i < numRestrictions; i++) {
if (mOpUserRestrictions.valueAt(i)
- .hasRestriction(code, pkg, attributionTag, user.getIdentifier())) {
+ .hasRestriction(code, pkg, attributionTag, user.getIdentifier(),
+ false)) {
number++;
}
}
diff --git a/services/core/java/com/android/server/appop/DiscreteRegistry.java b/services/core/java/com/android/server/appop/DiscreteRegistry.java
index 8de515d..158092f 100644
--- a/services/core/java/com/android/server/appop/DiscreteRegistry.java
+++ b/services/core/java/com/android/server/appop/DiscreteRegistry.java
@@ -34,6 +34,7 @@
import static android.app.AppOpsManager.OP_NONE;
import static android.app.AppOpsManager.OP_PHONE_CALL_CAMERA;
import static android.app.AppOpsManager.OP_PHONE_CALL_MICROPHONE;
+import static android.app.AppOpsManager.OP_RECEIVE_AMBIENT_TRIGGER_AUDIO;
import static android.app.AppOpsManager.OP_RECORD_AUDIO;
import static android.app.AppOpsManager.flagsToString;
import static android.app.AppOpsManager.getUidStateName;
@@ -133,7 +134,7 @@
private static final String PROPERTY_DISCRETE_OPS_LIST = "discrete_history_ops_cslist";
private static final String DEFAULT_DISCRETE_OPS = OP_FINE_LOCATION + "," + OP_COARSE_LOCATION
+ "," + OP_CAMERA + "," + OP_RECORD_AUDIO + "," + OP_PHONE_CALL_MICROPHONE + ","
- + OP_PHONE_CALL_CAMERA;
+ + OP_PHONE_CALL_CAMERA + "," + OP_RECEIVE_AMBIENT_TRIGGER_AUDIO;
private static final long DEFAULT_DISCRETE_HISTORY_CUTOFF = Duration.ofDays(7).toMillis();
private static final long MAXIMUM_DISCRETE_HISTORY_CUTOFF = Duration.ofDays(30).toMillis();
private static final long DEFAULT_DISCRETE_HISTORY_QUANTIZATION =
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 3b715a2..03dcc8d 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -1289,8 +1289,11 @@
break;
case MSG_L_SET_BT_ACTIVE_DEVICE:
synchronized (mDeviceStateLock) {
- mDeviceInventory.onSetBtActiveDevice((BtDeviceInfo) msg.obj,
- mAudioService.getBluetoothContextualVolumeStream());
+ BtDeviceInfo btInfo = (BtDeviceInfo) msg.obj;
+ mDeviceInventory.onSetBtActiveDevice(btInfo,
+ (btInfo.mProfile != BluetoothProfile.LE_AUDIO || btInfo.mIsLeOutput)
+ ? mAudioService.getBluetoothContextualVolumeStream()
+ : AudioSystem.STREAM_DEFAULT);
}
break;
case MSG_BT_HEADSET_CNCT_FAILED:
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 8a1f4c9..2e30e24 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -4146,19 +4146,8 @@
{
streamType = mStreamVolumeAlias[streamType];
- if (streamType == AudioSystem.STREAM_MUSIC) {
- flags = updateFlagsForTvPlatform(flags);
- synchronized (mHdmiClientLock) {
- // Don't display volume UI on a TV Playback device when using absolute volume
- if (mHdmiCecVolumeControlEnabled && mHdmiPlaybackClient != null
- && (isAbsoluteVolumeDevice(device)
- || isA2dpAbsoluteVolumeDevice(device))) {
- flags &= ~AudioManager.FLAG_SHOW_UI;
- }
- }
- if (isFullVolumeDevice(device)) {
- flags &= ~AudioManager.FLAG_SHOW_UI;
- }
+ if (streamType == AudioSystem.STREAM_MUSIC && isFullVolumeDevice(device)) {
+ flags &= ~AudioManager.FLAG_SHOW_UI;
}
mVolumeController.postVolumeChanged(streamType, flags);
}
@@ -6648,6 +6637,11 @@
// verify arguments
Objects.requireNonNull(device);
AudioManager.enforceValidVolumeBehavior(deviceVolumeBehavior);
+ sVolumeLogger.log(new AudioEventLogger.StringEvent("setDeviceVolumeBehavior: dev:"
+ + AudioSystem.getOutputDeviceName(device.getInternalType()) + " addr:"
+ + device.getAddress() + " behavior:"
+ + AudioDeviceVolumeManager.volumeBehaviorName(deviceVolumeBehavior)
+ + " pack:" + pkgName).printLog(TAG));
if (pkgName == null) {
pkgName = "";
}
@@ -8363,7 +8357,7 @@
private void avrcpSupportsAbsoluteVolume(String address, boolean support) {
// address is not used for now, but may be used when multiple a2dp devices are supported
sVolumeLogger.log(new AudioEventLogger.StringEvent("avrcpSupportsAbsoluteVolume addr="
- + address + " support=" + support));
+ + address + " support=" + support).printLog(TAG));
mDeviceBroker.setAvrcpAbsoluteVolumeSupported(support);
setAvrcpAbsoluteVolumeSupported(support);
}
diff --git a/services/core/java/com/android/server/audio/SpatializerHelper.java b/services/core/java/com/android/server/audio/SpatializerHelper.java
index d8aa9aa..0b9cb19 100644
--- a/services/core/java/com/android/server/audio/SpatializerHelper.java
+++ b/services/core/java/com/android/server/audio/SpatializerHelper.java
@@ -70,12 +70,6 @@
private @Nullable SensorManager mSensorManager;
//------------------------------------------------------------
- /** head tracker sensor name */
- // TODO: replace with generic head tracker sensor name.
- // the current implementation refers to the "google" namespace but will be replaced
- // by an android name at the next API level revision, it is not Google-specific.
- private static final String HEADTRACKER_SENSOR =
- "com.google.hardware.sensor.hid_dynamic.headtracker";
private static final SparseIntArray SPAT_MODE_FOR_DEVICE_TYPE = new SparseIntArray(15) {
{
@@ -125,6 +119,8 @@
private int mCapableSpatLevel = Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_NONE;
private boolean mTransauralSupported = false;
private boolean mBinauralSupported = false;
+ private boolean mIsHeadTrackingSupported = false;
+ private int[] mSupportedHeadTrackingModes = new int[0];
private int mActualHeadTrackingMode = Spatializer.HEAD_TRACKING_MODE_UNSUPPORTED;
private int mDesiredHeadTrackingMode = Spatializer.HEAD_TRACKING_MODE_RELATIVE_WORLD;
private boolean mHeadTrackerAvailable = false;
@@ -137,9 +133,9 @@
private int mSpatOutput = 0;
private @Nullable ISpatializer mSpat;
private @Nullable SpatializerCallback mSpatCallback;
- private @Nullable SpatializerHeadTrackingCallback mSpatHeadTrackingCallback;
+ private @Nullable SpatializerHeadTrackingCallback mSpatHeadTrackingCallback =
+ new SpatializerHeadTrackingCallback();
private @Nullable HelperDynamicSensorCallback mDynSensorCallback;
- private boolean mIsHeadTrackingSupported = false;
// default attributes and format that determine basic availability of spatialization
private static final AudioAttributes DEFAULT_ATTRIBUTES = new AudioAttributes.Builder()
@@ -195,6 +191,8 @@
return;
}
// capabilities of spatializer?
+ resetCapabilities();
+
try {
byte[] levels = spat.getSupportedLevels();
if (levels == null
@@ -213,6 +211,38 @@
break;
}
}
+
+ // Note: head tracking support must be initialized before spatialization modes as
+ // addCompatibleAudioDevice() calls onRoutingUpdated() which will initialize the
+ // sensors according to mIsHeadTrackingSupported.
+ mIsHeadTrackingSupported = spat.isHeadTrackingSupported();
+ if (mIsHeadTrackingSupported) {
+ final byte[] values = spat.getSupportedHeadTrackingModes();
+ ArrayList<Integer> list = new ArrayList<>(0);
+ for (byte value : values) {
+ switch (value) {
+ case SpatializerHeadTrackingMode.OTHER:
+ case SpatializerHeadTrackingMode.DISABLED:
+ // not expected here, skip
+ break;
+ case SpatializerHeadTrackingMode.RELATIVE_WORLD:
+ case SpatializerHeadTrackingMode.RELATIVE_SCREEN:
+ list.add(headTrackingModeTypeToSpatializerInt(value));
+ break;
+ default:
+ Log.e(TAG, "Unexpected head tracking mode:" + value,
+ new IllegalArgumentException("invalid mode"));
+ break;
+ }
+ }
+ mSupportedHeadTrackingModes = new int[list.size()];
+ for (int i = 0; i < list.size(); i++) {
+ mSupportedHeadTrackingModes[i] = list.get(i);
+ }
+ mActualHeadTrackingMode =
+ headTrackingModeTypeToSpatializerInt(spat.getActualHeadTrackingMode());
+ }
+
byte[] spatModes = spat.getSupportedModes();
for (byte mode : spatModes) {
switch (mode) {
@@ -258,7 +288,7 @@
}
// TODO read persisted states
} catch (RemoteException e) {
- /* capable level remains at NONE*/
+ resetCapabilities();
} finally {
if (spat != null) {
try {
@@ -285,12 +315,19 @@
releaseSpat();
mState = STATE_UNINITIALIZED;
mSpatLevel = Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_NONE;
- mCapableSpatLevel = Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_NONE;
mActualHeadTrackingMode = Spatializer.HEAD_TRACKING_MODE_UNSUPPORTED;
init(true);
setSpatializerEnabledInt(featureEnabled);
}
+ private void resetCapabilities() {
+ mCapableSpatLevel = Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_NONE;
+ mBinauralSupported = false;
+ mTransauralSupported = false;
+ mIsHeadTrackingSupported = false;
+ mSupportedHeadTrackingModes = new int[0];
+ }
+
//------------------------------------------------------
// routing monitoring
synchronized void onRoutingUpdated() {
@@ -852,18 +889,19 @@
private void createSpat() {
if (mSpat == null) {
mSpatCallback = new SpatializerCallback();
- mSpatHeadTrackingCallback = new SpatializerHeadTrackingCallback();
mSpat = AudioSystem.getSpatializer(mSpatCallback);
try {
- mIsHeadTrackingSupported = mSpat.isHeadTrackingSupported();
//TODO: register heatracking callback only when sensors are registered
if (mIsHeadTrackingSupported) {
+ mActualHeadTrackingMode =
+ headTrackingModeTypeToSpatializerInt(mSpat.getActualHeadTrackingMode());
mSpat.registerHeadTrackingCallback(mSpatHeadTrackingCallback);
}
} catch (RemoteException e) {
Log.e(TAG, "Can't configure head tracking", e);
mState = STATE_NOT_SUPPORTED;
mCapableSpatLevel = Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_NONE;
+ mActualHeadTrackingMode = Spatializer.HEAD_TRACKING_MODE_UNSUPPORTED;
}
}
}
@@ -883,7 +921,6 @@
} catch (RemoteException e) {
Log.e(TAG, "Can't set release spatializer cleanly", e);
}
- mIsHeadTrackingSupported = false;
mSpat = null;
}
}
@@ -951,76 +988,11 @@
}
synchronized int[] getSupportedHeadTrackingModes() {
- switch (mState) {
- case STATE_UNINITIALIZED:
- return new int[0];
- case STATE_NOT_SUPPORTED:
- // return an empty list when Spatializer functionality is not supported
- // because the list of head tracking modes you can set is actually empty
- // as defined in {@link Spatializer#getSupportedHeadTrackingModes()}
- return new int[0];
- case STATE_ENABLED_UNAVAILABLE:
- case STATE_DISABLED_UNAVAILABLE:
- case STATE_DISABLED_AVAILABLE:
- case STATE_ENABLED_AVAILABLE:
- if (mSpat == null) {
- return new int[0];
- }
- break;
- }
- // mSpat != null
- try {
- final byte[] values = mSpat.getSupportedHeadTrackingModes();
- ArrayList<Integer> list = new ArrayList<>(0);
- for (byte value : values) {
- switch (value) {
- case SpatializerHeadTrackingMode.OTHER:
- case SpatializerHeadTrackingMode.DISABLED:
- // not expected here, skip
- break;
- case SpatializerHeadTrackingMode.RELATIVE_WORLD:
- case SpatializerHeadTrackingMode.RELATIVE_SCREEN:
- list.add(headTrackingModeTypeToSpatializerInt(value));
- break;
- default:
- Log.e(TAG, "Unexpected head tracking mode:" + value,
- new IllegalArgumentException("invalid mode"));
- break;
- }
- }
- int[] modes = new int[list.size()];
- for (int i = 0; i < list.size(); i++) {
- modes[i] = list.get(i);
- }
- return modes;
- } catch (RemoteException e) {
- Log.e(TAG, "Error calling getSupportedHeadTrackingModes", e);
- return new int[] { Spatializer.HEAD_TRACKING_MODE_UNSUPPORTED };
- }
+ return mSupportedHeadTrackingModes;
}
synchronized int getActualHeadTrackingMode() {
- switch (mState) {
- case STATE_UNINITIALIZED:
- return Spatializer.HEAD_TRACKING_MODE_DISABLED;
- case STATE_NOT_SUPPORTED:
- return Spatializer.HEAD_TRACKING_MODE_UNSUPPORTED;
- case STATE_ENABLED_UNAVAILABLE:
- case STATE_DISABLED_UNAVAILABLE:
- case STATE_DISABLED_AVAILABLE:
- case STATE_ENABLED_AVAILABLE:
- if (mSpat == null) {
- return Spatializer.HEAD_TRACKING_MODE_DISABLED;
- }
- break;
- }
- // mSpat != null
- try {
- return headTrackingModeTypeToSpatializerInt(mSpat.getActualHeadTrackingMode());
- } catch (RemoteException e) {
- Log.e(TAG, "Error calling getActualHeadTrackingMode", e);
- return Spatializer.HEAD_TRACKING_MODE_UNSUPPORTED;
- }
+ return mActualHeadTrackingMode;
}
synchronized int getDesiredHeadTrackingMode() {
@@ -1465,19 +1437,19 @@
pw.println("\tmState:" + mState);
pw.println("\tmSpatLevel:" + mSpatLevel);
pw.println("\tmCapableSpatLevel:" + mCapableSpatLevel);
- pw.println("\tmActualHeadTrackingMode:"
- + Spatializer.headtrackingModeToString(mActualHeadTrackingMode));
- pw.println("\tmDesiredHeadTrackingMode:"
- + Spatializer.headtrackingModeToString(mDesiredHeadTrackingMode));
- pw.println("\tsupports binaural:" + mBinauralSupported + " / transaural:"
- + mTransauralSupported);
+ pw.println("\tmIsHeadTrackingSupported:" + mIsHeadTrackingSupported);
StringBuilder modesString = new StringBuilder();
- int[] modes = getSupportedHeadTrackingModes();
- for (int mode : modes) {
+ for (int mode : mSupportedHeadTrackingModes) {
modesString.append(Spatializer.headtrackingModeToString(mode)).append(" ");
}
pw.println("\tsupported head tracking modes:" + modesString);
+ pw.println("\tmDesiredHeadTrackingMode:"
+ + Spatializer.headtrackingModeToString(mDesiredHeadTrackingMode));
+ pw.println("\tmActualHeadTrackingMode:"
+ + Spatializer.headtrackingModeToString(mActualHeadTrackingMode));
pw.println("\theadtracker available:" + mHeadTrackerAvailable);
+ pw.println("\tsupports binaural:" + mBinauralSupported + " / transaural:"
+ + mTransauralSupported);
pw.println("\tmSpatOutput:" + mSpatOutput);
pw.println("\tdevices:");
for (SADeviceState device : mSADevices) {
@@ -1544,24 +1516,24 @@
private int getHeadSensorHandleUpdateTracker() {
int headHandle = -1;
UUID routingDeviceUuid = mAudioService.getDeviceSensorUuid(ROUTING_DEVICES[0]);
- List<Sensor> sensors = new ArrayList<Sensor>(0);
- sensors.addAll(mSensorManager.getDynamicSensorList(Sensor.TYPE_HEAD_TRACKER));
- sensors.addAll(mSensorManager.getDynamicSensorList(Sensor.TYPE_DEVICE_PRIVATE_BASE));
+ // We limit only to Sensor.TYPE_HEAD_TRACKER here to avoid confusion
+ // with gaming sensors. (Note that Sensor.TYPE_ROTATION_VECTOR
+ // and Sensor.TYPE_GAME_ROTATION_VECTOR are supported internally by
+ // SensorPoseProvider).
+ // Note: this is a dynamic sensor list right now.
+ List<Sensor> sensors = mSensorManager.getDynamicSensorList(Sensor.TYPE_HEAD_TRACKER);
for (Sensor sensor : sensors) {
- if (sensor.getType() == Sensor.TYPE_HEAD_TRACKER
- || sensor.getStringType().equals(HEADTRACKER_SENSOR)) {
- UUID uuid = sensor.getUuid();
- if (uuid.equals(routingDeviceUuid)) {
- headHandle = sensor.getHandle();
- if (!setHasHeadTracker(ROUTING_DEVICES[0])) {
- headHandle = -1;
- }
- break;
+ final UUID uuid = sensor.getUuid();
+ if (uuid.equals(routingDeviceUuid)) {
+ headHandle = sensor.getHandle();
+ if (!setHasHeadTracker(ROUTING_DEVICES[0])) {
+ headHandle = -1;
}
- if (uuid.equals(UuidUtils.STANDALONE_UUID)) {
- headHandle = sensor.getHandle();
- break;
- }
+ break;
+ }
+ if (uuid.equals(UuidUtils.STANDALONE_UUID)) {
+ headHandle = sensor.getHandle();
+ // we do not break, perhaps we find a head tracker on device.
}
}
return headHandle;
diff --git a/services/core/java/com/android/server/biometrics/Utils.java b/services/core/java/com/android/server/biometrics/Utils.java
index e0bd6189..06417d7 100644
--- a/services/core/java/com/android/server/biometrics/Utils.java
+++ b/services/core/java/com/android/server/biometrics/Utils.java
@@ -39,6 +39,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
+import android.app.ActivityTaskManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -589,4 +590,37 @@
throw new IllegalArgumentException("Unknown strength: " + strength);
}
}
+
+ /**
+ * Checks if a client package is running in the background.
+ *
+ * @param clientPackage The name of the package to be checked.
+ * @return Whether the client package is running in background
+ */
+ public static boolean isBackground(String clientPackage) {
+ Slog.v(TAG, "Checking if the authenticating is in background,"
+ + " clientPackage:" + clientPackage);
+ final List<ActivityManager.RunningTaskInfo> tasks =
+ ActivityTaskManager.getInstance().getTasks(Integer.MAX_VALUE);
+
+ if (tasks == null || tasks.isEmpty()) {
+ Slog.d(TAG, "No running tasks reported");
+ return true;
+ }
+
+ for (ActivityManager.RunningTaskInfo taskInfo : tasks) {
+ final ComponentName topActivity = taskInfo.topActivity;
+ if (topActivity != null) {
+ final String topPackage = topActivity.getPackageName();
+ if (topPackage.contentEquals(clientPackage) && taskInfo.isVisible()) {
+ return false;
+ } else {
+ Slog.i(TAG, "Running task, top: " + topPackage
+ + ", isVisible: " + taskInfo.isVisible());
+ }
+ }
+ }
+
+ return true;
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
index 1002229..4eb6d38 100644
--- a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
@@ -19,10 +19,8 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.app.ActivityManager;
import android.app.ActivityTaskManager;
import android.app.TaskStackListener;
-import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.hardware.biometrics.BiometricAuthenticator;
@@ -42,7 +40,6 @@
import com.android.server.biometrics.log.BiometricLogger;
import java.util.ArrayList;
-import java.util.List;
import java.util.function.Supplier;
/**
@@ -202,25 +199,7 @@
if (!mAllowBackgroundAuthentication && authenticated
&& !Utils.isKeyguard(getContext(), getOwnerString())
&& !Utils.isSystem(getContext(), getOwnerString())) {
- final List<ActivityManager.RunningTaskInfo> tasks =
- mActivityTaskManager.getTasks(1);
- if (tasks == null || tasks.isEmpty()) {
- Slog.e(TAG, "No running tasks reported");
- isBackgroundAuth = true;
- } else {
- final ComponentName topActivity = tasks.get(0).topActivity;
- if (topActivity == null) {
- Slog.e(TAG, "Unable to get top activity");
- isBackgroundAuth = true;
- } else {
- final String topPackage = topActivity.getPackageName();
- if (!topPackage.contentEquals(getOwnerString())) {
- Slog.e(TAG, "Background authentication detected, top: " + topPackage
- + ", client: " + getOwnerString());
- isBackgroundAuth = true;
- }
- }
- }
+ isBackgroundAuth = Utils.isBackground(getOwnerString());
}
// Fail authentication if we can't confirm the client activity is on top.
@@ -465,7 +444,6 @@
@Override
public void cancel() {
super.cancel();
-
if (mTaskStackListener != null) {
mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
index 4e03ee9..e0900b9 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
@@ -104,22 +104,17 @@
Slog.e(getTag(), "Task stack changed for client: " + client);
continue;
}
- if (Utils.isKeyguard(mContext, client.getOwnerString())) {
+ if (Utils.isKeyguard(mContext, client.getOwnerString())
+ || Utils.isSystem(mContext, client.getOwnerString())) {
continue; // Keyguard is always allowed
}
- final List<ActivityManager.RunningTaskInfo> runningTasks =
- mActivityTaskManager.getTasks(1);
- if (!runningTasks.isEmpty()) {
- final String topPackage =
- runningTasks.get(0).topActivity.getPackageName();
- if (!topPackage.contentEquals(client.getOwnerString())
- && !client.isAlreadyDone()) {
- Slog.e(getTag(), "Stopping background authentication, top: "
- + topPackage + " currentClient: " + client);
- mSensors.valueAt(i).getScheduler().cancelAuthenticationOrDetection(
- client.getToken(), client.getRequestId());
- }
+ if (Utils.isBackground(client.getOwnerString())
+ && !client.isAlreadyDone()) {
+ Slog.e(getTag(), "Stopping background authentication,"
+ + " currentClient: " + client);
+ mSensors.valueAt(i).getScheduler().cancelAuthenticationOrDetection(
+ client.getToken(), client.getRequestId());
}
}
});
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceResetLockoutClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceResetLockoutClient.java
index de0a36a..bf7a62a 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceResetLockoutClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceResetLockoutClient.java
@@ -88,6 +88,10 @@
mCallback.onClientFinished(this, true /* success */);
}
+ public boolean interruptsPrecedingClients() {
+ return true;
+ }
+
/**
* Reset the local lockout state and notify any listeners.
*
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceResetLockoutClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceResetLockoutClient.java
index 6e74d36..f29b9e8 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceResetLockoutClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceResetLockoutClient.java
@@ -65,6 +65,10 @@
startHalOperation();
}
+ public boolean interruptsPrecedingClients() {
+ return true;
+ }
+
@Override
protected void startHalOperation() {
try {
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
index b06fe38..668f4c4 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
@@ -122,18 +122,12 @@
continue; // Keyguard is always allowed
}
- final List<ActivityManager.RunningTaskInfo> runningTasks =
- mActivityTaskManager.getTasks(1);
- if (!runningTasks.isEmpty()) {
- final String topPackage =
- runningTasks.get(0).topActivity.getPackageName();
- if (!topPackage.contentEquals(client.getOwnerString())
- && !client.isAlreadyDone()) {
- Slog.e(getTag(), "Stopping background authentication, top: "
- + topPackage + " currentClient: " + client);
- mSensors.valueAt(i).getScheduler().cancelAuthenticationOrDetection(
- client.getToken(), client.getRequestId());
- }
+ if (Utils.isBackground(client.getOwnerString())
+ && !client.isAlreadyDone()) {
+ Slog.e(getTag(), "Stopping background authentication,"
+ + " currentClient: " + client);
+ mSensors.valueAt(i).getScheduler().cancelAuthenticationOrDetection(
+ client.getToken(), client.getRequestId());
}
}
});
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintResetLockoutClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintResetLockoutClient.java
index f90cba7..c8148df 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintResetLockoutClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintResetLockoutClient.java
@@ -82,6 +82,10 @@
}
}
+ public boolean interruptsPrecedingClients() {
+ return true;
+ }
+
void onLockoutCleared() {
resetLocalLockoutStateToNone(getSensorId(), getTargetUserId(), mLockoutCache,
mLockoutResetDispatcher);
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
index a650d3e..0c7bcc7 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
@@ -142,17 +142,12 @@
return; // Keyguard is always allowed
}
- final List<ActivityManager.RunningTaskInfo> runningTasks =
- mActivityTaskManager.getTasks(1);
- if (!runningTasks.isEmpty()) {
- final String topPackage = runningTasks.get(0).topActivity.getPackageName();
- if (!topPackage.contentEquals(client.getOwnerString())
- && !client.isAlreadyDone()) {
- Slog.e(TAG, "Stopping background authentication, top: "
- + topPackage + " currentClient: " + client);
- mScheduler.cancelAuthenticationOrDetection(
- client.getToken(), client.getRequestId());
- }
+ if (Utils.isBackground(client.getOwnerString())
+ && !client.isAlreadyDone()) {
+ Slog.e(TAG, "Stopping background authentication,"
+ + " currentClient: " + client);
+ mScheduler.cancelAuthenticationOrDetection(
+ client.getToken(), client.getRequestId());
}
});
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintResetLockoutClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintResetLockoutClient.java
index 559ca06..843fcc8 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintResetLockoutClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintResetLockoutClient.java
@@ -50,6 +50,10 @@
callback.onClientFinished(this, true /* success */);
}
+ public boolean interruptsPrecedingClients() {
+ return true;
+ }
+
@Override
public int getProtoEnum() {
return BiometricsProto.CM_RESET_LOCKOUT;
diff --git a/services/core/java/com/android/server/clipboard/EmulatorClipboardMonitor.java b/services/core/java/com/android/server/clipboard/EmulatorClipboardMonitor.java
index 28c7cad..ab3b250 100644
--- a/services/core/java/com/android/server/clipboard/EmulatorClipboardMonitor.java
+++ b/services/core/java/com/android/server/clipboard/EmulatorClipboardMonitor.java
@@ -18,6 +18,7 @@
import android.annotation.Nullable;
import android.content.ClipData;
+import android.os.PersistableBundle;
import android.os.SystemProperties;
import android.system.ErrnoException;
import android.system.Os;
@@ -25,6 +26,7 @@
import android.system.VmSocketAddress;
import android.util.Slog;
+import java.io.EOFException;
import java.io.FileDescriptor;
import java.io.InterruptedIOException;
import java.net.SocketException;
@@ -58,11 +60,11 @@
return mPipe;
}
- private synchronized boolean openPipe() {
- if (mPipe != null) {
- return true;
- }
+ private synchronized void setPipeFD(final FileDescriptor fd) {
+ mPipe = fd;
+ }
+ private static FileDescriptor openPipeImpl() {
try {
final FileDescriptor fd = Os.socket(OsConstants.AF_VSOCK, OsConstants.SOCK_STREAM, 0);
@@ -70,39 +72,42 @@
Os.connect(fd, new VmSocketAddress(HOST_PORT, OsConstants.VMADDR_CID_HOST));
final byte[] handshake = createOpenHandshake();
- Os.write(fd, handshake, 0, handshake.length);
- mPipe = fd;
- return true;
+ writeFully(fd, handshake, 0, handshake.length);
+ return fd;
} catch (ErrnoException | SocketException | InterruptedIOException e) {
Os.close(fd);
}
} catch (ErrnoException e) {
}
- return false;
+ return null;
}
- private synchronized void closePipe() {
- try {
- final FileDescriptor fd = mPipe;
- mPipe = null;
- if (fd != null) {
- Os.close(fd);
- }
- } catch (ErrnoException ignore) {
+ private static FileDescriptor openPipe() throws InterruptedException {
+ FileDescriptor fd = openPipeImpl();
+
+ // There's no guarantee that QEMU pipes will be ready at the moment
+ // this method is invoked. We simply try to get the pipe open and
+ // retry on failure indefinitely.
+ while (fd == null) {
+ Thread.sleep(100);
+ fd = openPipeImpl();
}
+
+ return fd;
}
- private byte[] receiveMessage() throws ErrnoException, InterruptedIOException {
+ private static byte[] receiveMessage(final FileDescriptor fd) throws ErrnoException,
+ InterruptedIOException, EOFException {
final byte[] lengthBits = new byte[4];
- Os.read(mPipe, lengthBits, 0, lengthBits.length);
+ readFully(fd, lengthBits, 0, lengthBits.length);
final ByteBuffer bb = ByteBuffer.wrap(lengthBits);
bb.order(ByteOrder.LITTLE_ENDIAN);
final int msgLen = bb.getInt();
final byte[] msg = new byte[msgLen];
- Os.read(mPipe, msg, 0, msg.length);
+ readFully(fd, msg, 0, msg.length);
return msg;
}
@@ -115,35 +120,46 @@
bb.order(ByteOrder.LITTLE_ENDIAN);
bb.putInt(msg.length);
- Os.write(fd, lengthBits, 0, lengthBits.length);
- Os.write(fd, msg, 0, msg.length);
+ writeFully(fd, lengthBits, 0, lengthBits.length);
+ writeFully(fd, msg, 0, msg.length);
}
EmulatorClipboardMonitor(final Consumer<ClipData> setAndroidClipboard) {
this.mHostMonitorThread = new Thread(() -> {
+ FileDescriptor fd = null;
+
while (!Thread.interrupted()) {
try {
- // There's no guarantee that QEMU pipes will be ready at the moment
- // this method is invoked. We simply try to get the pipe open and
- // retry on failure indefinitely.
- while (!openPipe()) {
- Thread.sleep(100);
+ if (fd == null) {
+ fd = openPipe();
+ setPipeFD(fd);
}
- final byte[] receivedData = receiveMessage();
+ final byte[] receivedData = receiveMessage(fd);
final String str = new String(receivedData);
final ClipData clip = new ClipData("host clipboard",
new String[]{"text/plain"},
new ClipData.Item(str));
+ final PersistableBundle bundle = new PersistableBundle();
+ bundle.putBoolean("com.android.systemui.SUPPRESS_CLIPBOARD_OVERLAY", true);
+ clip.getDescription().setExtras(bundle);
if (LOG_CLIBOARD_ACCESS) {
Slog.i(TAG, "Setting the guest clipboard to '" + str + "'");
}
setAndroidClipboard.accept(clip);
- } catch (ErrnoException | InterruptedIOException e) {
- closePipe();
- } catch (InterruptedException | IllegalArgumentException e) {
+ } catch (ErrnoException | EOFException | InterruptedIOException
+ | InterruptedException e) {
+ setPipeFD(null);
+
+ try {
+ Os.close(fd);
+ } catch (ErrnoException e2) {
+ // ignore
+ }
+
+ fd = null;
}
}
});
@@ -153,33 +169,70 @@
@Override
public void accept(final @Nullable ClipData clip) {
+ final FileDescriptor fd = getPipeFD();
+ if (fd != null) {
+ setHostClipboard(fd, getClipString(clip));
+ }
+ }
+
+ private String getClipString(final @Nullable ClipData clip) {
if (clip == null) {
- setHostClipboardImpl("");
- } else if (clip.getItemCount() > 0) {
- final CharSequence text = clip.getItemAt(0).getText();
- if (text != null) {
- setHostClipboardImpl(text.toString());
+ return "";
+ }
+
+ if (clip.getItemCount() == 0) {
+ return "";
+ }
+
+ final CharSequence text = clip.getItemAt(0).getText();
+ if (text == null) {
+ return "";
+ }
+
+ return text.toString();
+ }
+
+ private static void setHostClipboard(final FileDescriptor fd, final String value) {
+ Thread t = new Thread(() -> {
+ if (LOG_CLIBOARD_ACCESS) {
+ Slog.i(TAG, "Setting the host clipboard to '" + value + "'");
+ }
+
+ try {
+ sendMessage(fd, value.getBytes());
+ } catch (ErrnoException | InterruptedIOException e) {
+ Slog.e(TAG, "Failed to set host clipboard " + e.getMessage());
+ } catch (IllegalArgumentException e) {
+ }
+ });
+ t.start();
+ }
+
+ private static void readFully(final FileDescriptor fd,
+ final byte[] buf, int offset, int size)
+ throws ErrnoException, InterruptedIOException, EOFException {
+ while (size > 0) {
+ final int r = Os.read(fd, buf, offset, size);
+ if (r > 0) {
+ offset += r;
+ size -= r;
+ } else {
+ throw new EOFException();
}
}
}
- private void setHostClipboardImpl(final String value) {
- final FileDescriptor pipeFD = getPipeFD();
-
- if (pipeFD != null) {
- Thread t = new Thread(() -> {
- if (LOG_CLIBOARD_ACCESS) {
- Slog.i(TAG, "Setting the host clipboard to '" + value + "'");
- }
-
- try {
- sendMessage(pipeFD, value.getBytes());
- } catch (ErrnoException | InterruptedIOException e) {
- Slog.e(TAG, "Failed to set host clipboard " + e.getMessage());
- } catch (IllegalArgumentException e) {
- }
- });
- t.start();
+ private static void writeFully(final FileDescriptor fd,
+ final byte[] buf, int offset, int size)
+ throws ErrnoException, InterruptedIOException {
+ while (size > 0) {
+ final int r = Os.write(fd, buf, offset, size);
+ if (r > 0) {
+ offset += r;
+ size -= r;
+ } else {
+ throw new ErrnoException("write", OsConstants.EIO);
+ }
}
}
}
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 29386a0..fa1f5fc 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -763,31 +763,36 @@
// Also notify the new package if there was a provider change.
final boolean shouldNotifyNewPkg = isVpnApp(packageName) && isPackageChanged;
- if (setAlwaysOnPackageInternal(packageName, lockdown, lockdownAllowlist)) {
- saveAlwaysOnPackage();
- // TODO(b/230548427): Remove SDK check once VPN related stuff are decoupled from
- // ConnectivityServiceTest.
- if (shouldNotifyOldPkg && SdkLevel.isAtLeastT()) {
- // If both of shouldNotifyOldPkg & isPackageChanged are true, which means the
- // always-on of old package is disabled or the old package is replaced with the new
- // package. In this case, VpnProfileState should be disconnected.
- sendEventToVpnManagerApp(VpnManager.CATEGORY_EVENT_ALWAYS_ON_STATE_CHANGED,
- -1 /* errorClass */, -1 /* errorCode*/, oldPackage,
- null /* sessionKey */, isPackageChanged ? makeDisconnectedVpnProfileState()
- : makeVpnProfileStateLocked(),
- null /* underlyingNetwork */, null /* nc */, null /* lp */);
- }
- // TODO(b/230548427): Remove SDK check once VPN related stuff are decoupled from
- // ConnectivityServiceTest.
- if (shouldNotifyNewPkg && SdkLevel.isAtLeastT()) {
- sendEventToVpnManagerApp(VpnManager.CATEGORY_EVENT_ALWAYS_ON_STATE_CHANGED,
- -1 /* errorClass */, -1 /* errorCode*/, packageName,
- getSessionKeyLocked(), makeVpnProfileStateLocked(),
- null /* underlyingNetwork */, null /* nc */, null /* lp */);
- }
+ if (!setAlwaysOnPackageInternal(packageName, lockdown, lockdownAllowlist)) {
+ return false;
+ }
+
+ saveAlwaysOnPackage();
+
+ // TODO(b/230548427): Remove SDK check once VPN related stuff are decoupled from
+ // ConnectivityServiceTest.
+ if (!SdkLevel.isAtLeastT()) {
return true;
}
- return false;
+
+ if (shouldNotifyOldPkg) {
+ // If both of shouldNotifyOldPkg & isPackageChanged are true, that means the
+ // always-on of old package is disabled or the old package is replaced with the new
+ // package. In this case, VpnProfileState should be disconnected.
+ sendEventToVpnManagerApp(VpnManager.CATEGORY_EVENT_ALWAYS_ON_STATE_CHANGED,
+ -1 /* errorClass */, -1 /* errorCode*/, oldPackage,
+ null /* sessionKey */, isPackageChanged ? makeDisconnectedVpnProfileState()
+ : makeVpnProfileStateLocked(),
+ null /* underlyingNetwork */, null /* nc */, null /* lp */);
+ }
+
+ if (shouldNotifyNewPkg) {
+ sendEventToVpnManagerApp(VpnManager.CATEGORY_EVENT_ALWAYS_ON_STATE_CHANGED,
+ -1 /* errorClass */, -1 /* errorCode*/, packageName,
+ getSessionKeyLocked(), makeVpnProfileStateLocked(),
+ null /* underlyingNetwork */, null /* nc */, null /* lp */);
+ }
+ return true;
}
/**
@@ -1621,11 +1626,19 @@
}
// Note: Return type guarantees results are deduped and sorted, which callers require.
+ // This method also adds the SDK sandbox UIDs corresponding to the applications by default,
+ // since apps are generally not aware of them, yet they should follow the VPN configuration
+ // of the app they belong to.
private SortedSet<Integer> getAppsUids(List<String> packageNames, int userId) {
SortedSet<Integer> uids = new TreeSet<>();
for (String app : packageNames) {
int uid = getAppUid(app, userId);
if (uid != -1) uids.add(uid);
+ // TODO(b/230548427): Remove SDK check once VPN related stuff are decoupled from
+ // ConnectivityServiceTest.
+ if (Process.isApplicationUid(uid) && SdkLevel.isAtLeastT()) {
+ uids.add(Process.toSdkSandboxUid(uid));
+ }
}
return uids;
}
@@ -2580,13 +2593,13 @@
void onDefaultNetworkLinkPropertiesChanged(@NonNull LinkProperties lp);
- void onChildOpened(
- @NonNull Network network, @NonNull ChildSessionConfiguration childConfig);
+ void onDefaultNetworkLost(@NonNull Network network);
- void onChildTransformCreated(
- @NonNull Network network, @NonNull IpSecTransform transform, int direction);
+ void onChildOpened(int token, @NonNull ChildSessionConfiguration childConfig);
- void onSessionLost(@NonNull Network network, @Nullable Exception exception);
+ void onChildTransformCreated(int token, @NonNull IpSecTransform transform, int direction);
+
+ void onSessionLost(int token, @Nullable Exception exception);
}
/**
@@ -2633,11 +2646,18 @@
/** Signal to ensure shutdown is honored even if a new Network is connected. */
private boolean mIsRunning = true;
+ /**
+ * The token used by the primary/current/active IKE session.
+ *
+ * <p>This token MUST be updated when the VPN switches to use a new IKE session.
+ */
+ private int mCurrentToken = -1;
+
@Nullable private IpSecTunnelInterface mTunnelIface;
@Nullable private IkeSession mSession;
@Nullable private Network mActiveNetwork;
- @Nullable private NetworkCapabilities mNetworkCapabilities;
- @Nullable private LinkProperties mLinkProperties;
+ @Nullable private NetworkCapabilities mUnderlyingNetworkCapabilities;
+ @Nullable private LinkProperties mUnderlyingLinkProperties;
private final String mSessionKey;
IkeV2VpnRunner(@NonNull Ikev2VpnProfile profile) {
@@ -2686,22 +2706,25 @@
return Objects.equals(mActiveNetwork, network) && mIsRunning;
}
+ private boolean isActiveToken(int token) {
+ return (mCurrentToken == token) && mIsRunning;
+ }
+
/**
* Called when an IKE Child session has been opened, signalling completion of the startup.
*
* <p>This method is only ever called once per IkeSession, and MUST run on the mExecutor
* thread in order to ensure consistency of the Ikev2VpnRunner fields.
*/
- public void onChildOpened(
- @NonNull Network network, @NonNull ChildSessionConfiguration childConfig) {
- if (!isActiveNetwork(network)) {
- Log.d(TAG, "onOpened called for obsolete network " + network);
+ public void onChildOpened(int token, @NonNull ChildSessionConfiguration childConfig) {
+ if (!isActiveToken(token)) {
+ Log.d(TAG, "onChildOpened called for obsolete token " + token);
// Do nothing; this signals that either: (1) a new/better Network was found,
- // and the Ikev2VpnRunner has switched to it in onDefaultNetworkChanged, or (2) this
- // IKE session was already shut down (exited, or an error was encountered somewhere
- // else). In both cases, all resources and sessions are torn down via
- // resetIkeState().
+ // and the Ikev2VpnRunner has switched to it by restarting a new IKE session in
+ // onDefaultNetworkChanged, or (2) this IKE session was already shut down (exited,
+ // or an error was encountered somewhere else). In both cases, all resources and
+ // sessions are torn down via resetIkeState().
return;
}
@@ -2738,7 +2761,7 @@
mConfig.dnsServers.clear();
mConfig.dnsServers.addAll(dnsAddrStrings);
- mConfig.underlyingNetworks = new Network[] {network};
+ mConfig.underlyingNetworks = new Network[] {mActiveNetwork};
mConfig.disallowedApplications = getAppExclusionList(mPackage);
@@ -2754,7 +2777,8 @@
return; // Link properties are already sent.
} else {
// Underlying networks also set in agentConnect()
- networkAgent.setUnderlyingNetworks(Collections.singletonList(network));
+ networkAgent.setUnderlyingNetworks(
+ Collections.singletonList(mActiveNetwork));
}
lp = makeLinkProperties(); // Accesses VPN instance fields; must be locked
@@ -2762,8 +2786,8 @@
networkAgent.sendLinkProperties(lp);
} catch (Exception e) {
- Log.d(TAG, "Error in ChildOpened for network " + network, e);
- onSessionLost(network, e);
+ Log.d(TAG, "Error in ChildOpened for token " + token, e);
+ onSessionLost(token, e);
}
}
@@ -2775,15 +2799,15 @@
* consistency of the Ikev2VpnRunner fields.
*/
public void onChildTransformCreated(
- @NonNull Network network, @NonNull IpSecTransform transform, int direction) {
- if (!isActiveNetwork(network)) {
- Log.d(TAG, "ChildTransformCreated for obsolete network " + network);
+ int token, @NonNull IpSecTransform transform, int direction) {
+ if (!isActiveToken(token)) {
+ Log.d(TAG, "ChildTransformCreated for obsolete token " + token);
// Do nothing; this signals that either: (1) a new/better Network was found,
- // and the Ikev2VpnRunner has switched to it in onDefaultNetworkChanged, or (2) this
- // IKE session was already shut down (exited, or an error was encountered somewhere
- // else). In both cases, all resources and sessions are torn down via
- // resetIkeState().
+ // and the Ikev2VpnRunner has switched to it by restarting a new IKE session in
+ // onDefaultNetworkChanged, or (2) this IKE session was already shut down (exited,
+ // or an error was encountered somewhere else). In both cases, all resources and
+ // sessions are torn down via resetIkeState().
return;
}
@@ -2792,8 +2816,8 @@
// them alive for us
mIpSecManager.applyTunnelModeTransform(mTunnelIface, direction, transform);
} catch (IOException e) {
- Log.d(TAG, "Transform application failed for network " + network, e);
- onSessionLost(network, e);
+ Log.d(TAG, "Transform application failed for token " + token, e);
+ onSessionLost(token, e);
}
}
@@ -2851,30 +2875,55 @@
network);
NetdUtils.setInterfaceUp(mNetd, mTunnelIface.getInterfaceName());
- mSession = mIkev2SessionCreator.createIkeSession(
- mContext,
- ikeSessionParams,
- childSessionParams,
- mExecutor,
- new VpnIkev2Utils.IkeSessionCallbackImpl(
- TAG, IkeV2VpnRunner.this, network),
- new VpnIkev2Utils.ChildSessionCallbackImpl(
- TAG, IkeV2VpnRunner.this, network));
- Log.d(TAG, "Ike Session started for network " + network);
+ final int token = ++mCurrentToken;
+ mSession =
+ mIkev2SessionCreator.createIkeSession(
+ mContext,
+ ikeSessionParams,
+ childSessionParams,
+ mExecutor,
+ new VpnIkev2Utils.IkeSessionCallbackImpl(
+ TAG, IkeV2VpnRunner.this, token),
+ new VpnIkev2Utils.ChildSessionCallbackImpl(
+ TAG, IkeV2VpnRunner.this, token));
+ Log.d(TAG, "IKE session started for token " + token);
} catch (Exception e) {
- Log.i(TAG, "Setup failed for network " + network + ". Aborting", e);
- onSessionLost(network, e);
+ Log.i(TAG, "Setup failed for token " + mCurrentToken + ". Aborting", e);
+ onSessionLost(mCurrentToken, e);
}
}
/** Called when the NetworkCapabilities of underlying network is changed */
public void onDefaultNetworkCapabilitiesChanged(@NonNull NetworkCapabilities nc) {
- mNetworkCapabilities = nc;
+ mUnderlyingNetworkCapabilities = nc;
}
/** Called when the LinkProperties of underlying network is changed */
public void onDefaultNetworkLinkPropertiesChanged(@NonNull LinkProperties lp) {
- mLinkProperties = lp;
+ mUnderlyingLinkProperties = lp;
+ }
+
+ /**
+ * Handles loss of the default underlying network
+ *
+ * <p>The Ikev2VpnRunner will kill the IKE session and reset the VPN.
+ *
+ * <p>This method MUST always be called on the mExecutor thread in order to ensure
+ * consistency of the Ikev2VpnRunner fields.
+ */
+ public void onDefaultNetworkLost(@NonNull Network network) {
+ if (!isActiveNetwork(network)) {
+ Log.d(TAG, "onDefaultNetworkLost called for obsolete network " + network);
+
+ // Do nothing; this signals that either: (1) a new/better Network was found,
+ // and the Ikev2VpnRunner has switched to it by restarting a new IKE session in
+ // onDefaultNetworkChanged, or (2) this IKE session was already shut down (exited,
+ // or an error was encountered somewhere else). In both cases, all resources and
+ // sessions are torn down via resetIkeState().
+ return;
+ }
+
+ handleSessionLost(null);
}
/** Marks the state as FAILED, and disconnects. */
@@ -2895,18 +2944,22 @@
* <p>This method MUST always be called on the mExecutor thread in order to ensure
* consistency of the Ikev2VpnRunner fields.
*/
- public void onSessionLost(@NonNull Network network, @Nullable Exception exception) {
- if (!isActiveNetwork(network)) {
- Log.d(TAG, "onSessionLost() called for obsolete network " + network);
+ public void onSessionLost(int token, @Nullable Exception exception) {
+ if (!isActiveToken(token)) {
+ Log.d(TAG, "onSessionLost() called for obsolete token " + token);
// Do nothing; this signals that either: (1) a new/better Network was found,
- // and the Ikev2VpnRunner has switched to it in onDefaultNetworkChanged, or (2) this
- // IKE session was already shut down (exited, or an error was encountered somewhere
- // else). In both cases, all resources and sessions are torn down via
- // onSessionLost() and resetIkeState().
+ // and the Ikev2VpnRunner has switched to it by restarting a new IKE session in
+ // onDefaultNetworkChanged, or (2) this IKE session was already shut down (exited,
+ // or an error was encountered somewhere else). In both cases, all resources and
+ // sessions are torn down via resetIkeState().
return;
}
+ handleSessionLost(exception);
+ }
+
+ private void handleSessionLost(@Nullable Exception exception) {
synchronized (Vpn.this) {
if (exception instanceof IkeProtocolException) {
final IkeProtocolException ikeException = (IkeProtocolException) exception;
@@ -2928,9 +2981,9 @@
getPackage(), mSessionKey, makeVpnProfileStateLocked(),
mActiveNetwork,
getRedactedNetworkCapabilitiesOfUnderlyingNetwork(
- this.mNetworkCapabilities),
+ mUnderlyingNetworkCapabilities),
getRedactedLinkPropertiesOfUnderlyingNetwork(
- this.mLinkProperties));
+ mUnderlyingLinkProperties));
}
markFailedAndDisconnect(exception);
return;
@@ -2946,9 +2999,9 @@
getPackage(), mSessionKey, makeVpnProfileStateLocked(),
mActiveNetwork,
getRedactedNetworkCapabilitiesOfUnderlyingNetwork(
- this.mNetworkCapabilities),
+ mUnderlyingNetworkCapabilities),
getRedactedLinkPropertiesOfUnderlyingNetwork(
- this.mLinkProperties));
+ mUnderlyingLinkProperties));
}
}
} else if (exception instanceof IllegalArgumentException) {
@@ -2965,9 +3018,9 @@
getPackage(), mSessionKey, makeVpnProfileStateLocked(),
mActiveNetwork,
getRedactedNetworkCapabilitiesOfUnderlyingNetwork(
- this.mNetworkCapabilities),
+ mUnderlyingNetworkCapabilities),
getRedactedLinkPropertiesOfUnderlyingNetwork(
- this.mLinkProperties));
+ mUnderlyingLinkProperties));
}
} else if (exception instanceof IkeNonProtocolException) {
if (exception.getCause() instanceof UnknownHostException) {
@@ -2980,9 +3033,9 @@
getPackage(), mSessionKey, makeVpnProfileStateLocked(),
mActiveNetwork,
getRedactedNetworkCapabilitiesOfUnderlyingNetwork(
- this.mNetworkCapabilities),
+ mUnderlyingNetworkCapabilities),
getRedactedLinkPropertiesOfUnderlyingNetwork(
- this.mLinkProperties));
+ mUnderlyingLinkProperties));
}
} else if (exception.getCause() instanceof IkeTimeoutException) {
// TODO(b/230548427): Remove SDK check once VPN related stuff are
@@ -2994,9 +3047,9 @@
getPackage(), mSessionKey, makeVpnProfileStateLocked(),
mActiveNetwork,
getRedactedNetworkCapabilitiesOfUnderlyingNetwork(
- this.mNetworkCapabilities),
+ mUnderlyingNetworkCapabilities),
getRedactedLinkPropertiesOfUnderlyingNetwork(
- this.mLinkProperties));
+ mUnderlyingLinkProperties));
}
} else if (exception.getCause() instanceof IOException) {
// TODO(b/230548427): Remove SDK check once VPN related stuff are
@@ -3008,9 +3061,9 @@
getPackage(), mSessionKey, makeVpnProfileStateLocked(),
mActiveNetwork,
getRedactedNetworkCapabilitiesOfUnderlyingNetwork(
- this.mNetworkCapabilities),
+ mUnderlyingNetworkCapabilities),
getRedactedLinkPropertiesOfUnderlyingNetwork(
- this.mLinkProperties));
+ mUnderlyingLinkProperties));
}
}
} else if (exception != null) {
@@ -3019,12 +3072,12 @@
}
mActiveNetwork = null;
- mNetworkCapabilities = null;
- mLinkProperties = null;
+ mUnderlyingNetworkCapabilities = null;
+ mUnderlyingLinkProperties = null;
// Close all obsolete state, but keep VPN alive incase a usable network comes up.
// (Mirrors VpnService behavior)
- Log.d(TAG, "Resetting state for network: " + network);
+ Log.d(TAG, "Resetting state for token: " + mCurrentToken);
synchronized (Vpn.this) {
// Since this method handles non-fatal errors only, set mInterface to null to
@@ -3085,8 +3138,8 @@
*/
private void disconnectVpnRunner() {
mActiveNetwork = null;
- mNetworkCapabilities = null;
- mLinkProperties = null;
+ mUnderlyingNetworkCapabilities = null;
+ mUnderlyingLinkProperties = null;
mIsRunning = false;
resetIkeState();
diff --git a/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java b/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java
index e1e488d..3e49afa 100644
--- a/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java
+++ b/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java
@@ -298,35 +298,35 @@
static class IkeSessionCallbackImpl implements IkeSessionCallback {
private final String mTag;
private final Vpn.IkeV2VpnRunnerCallback mCallback;
- private final Network mNetwork;
+ private final int mToken;
- IkeSessionCallbackImpl(String tag, Vpn.IkeV2VpnRunnerCallback callback, Network network) {
+ IkeSessionCallbackImpl(String tag, Vpn.IkeV2VpnRunnerCallback callback, int token) {
mTag = tag;
mCallback = callback;
- mNetwork = network;
+ mToken = token;
}
@Override
public void onOpened(@NonNull IkeSessionConfiguration ikeSessionConfig) {
- Log.d(mTag, "IkeOpened for network " + mNetwork);
+ Log.d(mTag, "IkeOpened for token " + mToken);
// Nothing to do here.
}
@Override
public void onClosed() {
- Log.d(mTag, "IkeClosed for network " + mNetwork);
- mCallback.onSessionLost(mNetwork, null); // Server requested session closure. Retry?
+ Log.d(mTag, "IkeClosed for token " + mToken);
+ mCallback.onSessionLost(mToken, null); // Server requested session closure. Retry?
}
@Override
public void onClosedExceptionally(@NonNull IkeException exception) {
- Log.d(mTag, "IkeClosedExceptionally for network " + mNetwork, exception);
- mCallback.onSessionLost(mNetwork, exception);
+ Log.d(mTag, "IkeClosedExceptionally for token " + mToken, exception);
+ mCallback.onSessionLost(mToken, exception);
}
@Override
public void onError(@NonNull IkeProtocolException exception) {
- Log.d(mTag, "IkeError for network " + mNetwork, exception);
+ Log.d(mTag, "IkeError for token " + mToken, exception);
// Non-fatal, log and continue.
}
}
@@ -334,36 +334,36 @@
static class ChildSessionCallbackImpl implements ChildSessionCallback {
private final String mTag;
private final Vpn.IkeV2VpnRunnerCallback mCallback;
- private final Network mNetwork;
+ private final int mToken;
- ChildSessionCallbackImpl(String tag, Vpn.IkeV2VpnRunnerCallback callback, Network network) {
+ ChildSessionCallbackImpl(String tag, Vpn.IkeV2VpnRunnerCallback callback, int token) {
mTag = tag;
mCallback = callback;
- mNetwork = network;
+ mToken = token;
}
@Override
public void onOpened(@NonNull ChildSessionConfiguration childConfig) {
- Log.d(mTag, "ChildOpened for network " + mNetwork);
- mCallback.onChildOpened(mNetwork, childConfig);
+ Log.d(mTag, "ChildOpened for token " + mToken);
+ mCallback.onChildOpened(mToken, childConfig);
}
@Override
public void onClosed() {
- Log.d(mTag, "ChildClosed for network " + mNetwork);
- mCallback.onSessionLost(mNetwork, null);
+ Log.d(mTag, "ChildClosed for token " + mToken);
+ mCallback.onSessionLost(mToken, null);
}
@Override
public void onClosedExceptionally(@NonNull IkeException exception) {
- Log.d(mTag, "ChildClosedExceptionally for network " + mNetwork, exception);
- mCallback.onSessionLost(mNetwork, exception);
+ Log.d(mTag, "ChildClosedExceptionally for token " + mToken, exception);
+ mCallback.onSessionLost(mToken, exception);
}
@Override
public void onIpSecTransformCreated(@NonNull IpSecTransform transform, int direction) {
- Log.d(mTag, "ChildTransformCreated; Direction: " + direction + "; network " + mNetwork);
- mCallback.onChildTransformCreated(mNetwork, transform, direction);
+ Log.d(mTag, "ChildTransformCreated; Direction: " + direction + "; token " + mToken);
+ mCallback.onChildTransformCreated(mToken, transform, direction);
}
@Override
@@ -371,8 +371,7 @@
// Nothing to be done; no references to the IpSecTransform are held by the
// Ikev2VpnRunner (or this callback class), and this transform will be closed by the
// IKE library.
- Log.d(mTag,
- "ChildTransformDeleted; Direction: " + direction + "; for network " + mNetwork);
+ Log.d(mTag, "ChildTransformDeleted; Direction: " + direction + "; for token " + mToken);
}
}
@@ -412,8 +411,8 @@
@Override
public void onLost(@NonNull Network network) {
- Log.d(mTag, "Tearing down; lost network: " + network);
- mExecutor.execute(() -> mCallback.onSessionLost(network, null));
+ Log.d(mTag, "onLost called for network: " + network);
+ mExecutor.execute(() -> mCallback.onDefaultNetworkLost(network));
}
}
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index b669d98..75b4eb4 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -26,6 +26,7 @@
import android.annotation.RequiresPermission;
import android.annotation.UserIdInt;
import android.app.ActivityManager;
+import android.app.ActivityManager.RestrictionLevel;
import android.app.ActivityManagerInternal;
import android.app.AppGlobals;
import android.app.AppOpsManager;
@@ -51,6 +52,7 @@
import android.content.pm.ProviderInfo;
import android.database.IContentObserver;
import android.net.Uri;
+import android.os.AppBackgroundRestrictionsInfo;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
@@ -77,6 +79,7 @@
import com.android.internal.os.BinderDeathDispatcher;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DumpUtils;
+import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.LocalServices;
import com.android.server.SystemService;
@@ -1493,11 +1496,84 @@
return ContentResolver.SYNC_EXEMPTION_PROMOTE_BUCKET_WITH_TEMP;
}
if (procState <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND || isUidActive) {
+ FrameworkStatsLog.write(FrameworkStatsLog.SYNC_EXEMPTION_OCCURRED,
+ callingUid, getProcStateForStatsd(procState), isUidActive,
+ getRestrictionLevelForStatsd(ami.getRestrictionLevel(callingUid)));
return ContentResolver.SYNC_EXEMPTION_PROMOTE_BUCKET;
}
return ContentResolver.SYNC_EXEMPTION_NONE;
}
+ private int getProcStateForStatsd(int procState) {
+ switch (procState) {
+ case ActivityManager.PROCESS_STATE_UNKNOWN:
+ return FrameworkStatsLog.SYNC_EXEMPTION_OCCURRED__PROC_STATE__UNKNOWN;
+ case ActivityManager.PROCESS_STATE_PERSISTENT:
+ return FrameworkStatsLog.SYNC_EXEMPTION_OCCURRED__PROC_STATE__PERSISTENT;
+ case ActivityManager.PROCESS_STATE_PERSISTENT_UI:
+ return FrameworkStatsLog.SYNC_EXEMPTION_OCCURRED__PROC_STATE__PERSISTENT_UI;
+ case ActivityManager.PROCESS_STATE_TOP:
+ return FrameworkStatsLog.SYNC_EXEMPTION_OCCURRED__PROC_STATE__TOP;
+ case ActivityManager.PROCESS_STATE_BOUND_TOP:
+ return FrameworkStatsLog.SYNC_EXEMPTION_OCCURRED__PROC_STATE__BOUND_TOP;
+ case ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE:
+ return FrameworkStatsLog.SYNC_EXEMPTION_OCCURRED__PROC_STATE__FOREGROUND_SERVICE;
+ case ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE:
+ return FrameworkStatsLog
+ .SYNC_EXEMPTION_OCCURRED__PROC_STATE__BOUND_FOREGROUND_SERVICE;
+ case ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND:
+ return FrameworkStatsLog.SYNC_EXEMPTION_OCCURRED__PROC_STATE__IMPORTANT_FOREGROUND;
+ case ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND:
+ return FrameworkStatsLog.SYNC_EXEMPTION_OCCURRED__PROC_STATE__IMPORTANT_BACKGROUND;
+ case ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND:
+ return FrameworkStatsLog.SYNC_EXEMPTION_OCCURRED__PROC_STATE__TRANSIENT_BACKGROUND;
+ case ActivityManager.PROCESS_STATE_BACKUP:
+ return FrameworkStatsLog.SYNC_EXEMPTION_OCCURRED__PROC_STATE__BACKUP;
+ case ActivityManager.PROCESS_STATE_SERVICE:
+ return FrameworkStatsLog.SYNC_EXEMPTION_OCCURRED__PROC_STATE__SERVICE;
+ case ActivityManager.PROCESS_STATE_RECEIVER:
+ return FrameworkStatsLog.SYNC_EXEMPTION_OCCURRED__PROC_STATE__RECEIVER;
+ case ActivityManager.PROCESS_STATE_TOP_SLEEPING:
+ return FrameworkStatsLog.SYNC_EXEMPTION_OCCURRED__PROC_STATE__TOP_SLEEPING;
+ case ActivityManager.PROCESS_STATE_HEAVY_WEIGHT:
+ return FrameworkStatsLog.SYNC_EXEMPTION_OCCURRED__PROC_STATE__HEAVY_WEIGHT;
+ case ActivityManager.PROCESS_STATE_LAST_ACTIVITY:
+ return FrameworkStatsLog.SYNC_EXEMPTION_OCCURRED__PROC_STATE__LAST_ACTIVITY;
+ case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY:
+ return FrameworkStatsLog.SYNC_EXEMPTION_OCCURRED__PROC_STATE__CACHED_ACTIVITY;
+ case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:
+ return FrameworkStatsLog
+ .SYNC_EXEMPTION_OCCURRED__PROC_STATE__CACHED_ACTIVITY_CLIENT;
+ case ActivityManager.PROCESS_STATE_CACHED_RECENT:
+ return FrameworkStatsLog.SYNC_EXEMPTION_OCCURRED__PROC_STATE__CACHED_RECENT;
+ case ActivityManager.PROCESS_STATE_CACHED_EMPTY:
+ return FrameworkStatsLog.SYNC_EXEMPTION_OCCURRED__PROC_STATE__CACHED_EMPTY;
+ default:
+ return FrameworkStatsLog.SYNC_EXEMPTION_OCCURRED__PROC_STATE__UNKNOWN;
+ }
+ }
+
+ private int getRestrictionLevelForStatsd(@RestrictionLevel int level) {
+ switch (level) {
+ case ActivityManager.RESTRICTION_LEVEL_UNKNOWN:
+ return AppBackgroundRestrictionsInfo.LEVEL_UNKNOWN;
+ case ActivityManager.RESTRICTION_LEVEL_UNRESTRICTED:
+ return AppBackgroundRestrictionsInfo.LEVEL_UNRESTRICTED;
+ case ActivityManager.RESTRICTION_LEVEL_EXEMPTED:
+ return AppBackgroundRestrictionsInfo.LEVEL_EXEMPTED;
+ case ActivityManager.RESTRICTION_LEVEL_ADAPTIVE_BUCKET:
+ return AppBackgroundRestrictionsInfo.LEVEL_ADAPTIVE_BUCKET;
+ case ActivityManager.RESTRICTION_LEVEL_RESTRICTED_BUCKET:
+ return AppBackgroundRestrictionsInfo.LEVEL_RESTRICTED_BUCKET;
+ case ActivityManager.RESTRICTION_LEVEL_BACKGROUND_RESTRICTED:
+ return AppBackgroundRestrictionsInfo.LEVEL_BACKGROUND_RESTRICTED;
+ case ActivityManager.RESTRICTION_LEVEL_HIBERNATION:
+ return AppBackgroundRestrictionsInfo.LEVEL_HIBERNATION;
+ default:
+ return AppBackgroundRestrictionsInfo.LEVEL_UNKNOWN;
+ }
+ }
+
/** {@hide} */
@VisibleForTesting
public static final class ObserverNode {
diff --git a/services/core/java/com/android/server/display/PersistentDataStore.java b/services/core/java/com/android/server/display/PersistentDataStore.java
index 2eba080..4b93d8f 100644
--- a/services/core/java/com/android/server/display/PersistentDataStore.java
+++ b/services/core/java/com/android/server/display/PersistentDataStore.java
@@ -20,6 +20,7 @@
import android.graphics.Point;
import android.hardware.display.BrightnessConfiguration;
import android.hardware.display.WifiDisplay;
+import android.os.Handler;
import android.util.AtomicFile;
import android.util.Slog;
import android.util.SparseArray;
@@ -31,12 +32,14 @@
import android.view.Display;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.os.BackgroundThread;
import com.android.internal.util.XmlUtils;
import libcore.io.IoUtils;
import org.xmlpull.v1.XmlPullParserException;
+import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
@@ -141,13 +144,22 @@
// The interface for methods which should be replaced by the test harness.
private Injector mInjector;
+ private final Handler mHandler;
+ private final Object mFileAccessLock = new Object();
+
public PersistentDataStore() {
this(new Injector());
}
@VisibleForTesting
PersistentDataStore(Injector injector) {
+ this(injector, BackgroundThread.getHandler());
+ }
+
+ @VisibleForTesting
+ PersistentDataStore(Injector injector, Handler handler) {
mInjector = injector;
+ mHandler = handler;
}
public void saveIfNeeded() {
@@ -418,45 +430,61 @@
}
private void load() {
- clearState();
-
- final InputStream is;
- try {
- is = mInjector.openRead();
- } catch (FileNotFoundException ex) {
- return;
- }
-
- TypedXmlPullParser parser;
- try {
- parser = Xml.resolvePullParser(is);
- loadFromXml(parser);
- } catch (IOException ex) {
- Slog.w(TAG, "Failed to load display manager persistent store data.", ex);
+ synchronized (mFileAccessLock) {
clearState();
- } catch (XmlPullParserException ex) {
- Slog.w(TAG, "Failed to load display manager persistent store data.", ex);
- clearState();
- } finally {
- IoUtils.closeQuietly(is);
+
+ final InputStream is;
+ try {
+ is = mInjector.openRead();
+ } catch (FileNotFoundException ex) {
+ return;
+ }
+
+ TypedXmlPullParser parser;
+ try {
+ parser = Xml.resolvePullParser(is);
+ loadFromXml(parser);
+ } catch (IOException ex) {
+ Slog.w(TAG, "Failed to load display manager persistent store data.", ex);
+ clearState();
+ } catch (XmlPullParserException ex) {
+ Slog.w(TAG, "Failed to load display manager persistent store data.", ex);
+ clearState();
+ } finally {
+ IoUtils.closeQuietly(is);
+ }
}
}
private void save() {
- final OutputStream os;
+ final ByteArrayOutputStream os;
try {
- os = mInjector.startWrite();
- boolean success = false;
- try {
- TypedXmlSerializer serializer = Xml.resolveSerializer(os);
- saveToXml(serializer);
- serializer.flush();
- success = true;
- } finally {
- mInjector.finishWrite(os, success);
- }
+ os = new ByteArrayOutputStream();
+
+ TypedXmlSerializer serializer = Xml.resolveSerializer(os);
+ saveToXml(serializer);
+
+ mHandler.removeCallbacksAndMessages(/* token */ null);
+ mHandler.post(() -> {
+ synchronized (mFileAccessLock) {
+ OutputStream fileOutput = null;
+ try {
+ fileOutput = mInjector.startWrite();
+ os.writeTo(fileOutput);
+ fileOutput.flush();
+ } catch (IOException ex) {
+ Slog.w(TAG, "Failed to save display manager persistent store data.", ex);
+ } finally {
+ if (fileOutput != null) {
+ mInjector.finishWrite(fileOutput, true);
+ }
+ }
+ }
+ });
+
+ serializer.flush();
} catch (IOException ex) {
- Slog.w(TAG, "Failed to save display manager persistent store data.", ex);
+ Slog.w(TAG, "Failed to process the XML serializer.", ex);
}
}
diff --git a/services/core/java/com/android/server/display/color/ColorDisplayService.java b/services/core/java/com/android/server/display/color/ColorDisplayService.java
index 8035526..8de150a 100644
--- a/services/core/java/com/android/server/display/color/ColorDisplayService.java
+++ b/services/core/java/com/android/server/display/color/ColorDisplayService.java
@@ -948,19 +948,15 @@
if (!isColorModeAvailable(colorMode)) {
final int[] mappedColorModes = getContext().getResources().getIntArray(
R.array.config_mappedColorModes);
- if (colorMode == COLOR_MODE_BOOSTED && mappedColorModes.length > COLOR_MODE_NATURAL
- && isColorModeAvailable(mappedColorModes[COLOR_MODE_NATURAL])) {
- colorMode = COLOR_MODE_NATURAL;
- } else if (colorMode == COLOR_MODE_SATURATED
- && mappedColorModes.length > COLOR_MODE_AUTOMATIC
- && isColorModeAvailable(mappedColorModes[COLOR_MODE_AUTOMATIC])) {
- colorMode = COLOR_MODE_AUTOMATIC;
- } else if (colorMode == COLOR_MODE_AUTOMATIC
- && mappedColorModes.length > COLOR_MODE_SATURATED
- && isColorModeAvailable(mappedColorModes[COLOR_MODE_SATURATED])) {
- colorMode = COLOR_MODE_SATURATED;
+ if (colorMode != -1 && mappedColorModes.length > colorMode
+ && isColorModeAvailable(mappedColorModes[colorMode])) {
+ colorMode = mappedColorModes[colorMode];
} else {
- colorMode = -1;
+ final int[] availableColorModes = getContext().getResources().getIntArray(
+ R.array.config_availableColorModes);
+ if (availableColorModes.length > 0) {
+ colorMode = availableColorModes[0];
+ }
}
}
diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java
index 4e1d899..63c5456 100644
--- a/services/core/java/com/android/server/dreams/DreamManagerService.java
+++ b/services/core/java/com/android/server/dreams/DreamManagerService.java
@@ -124,8 +124,10 @@
final boolean activityAllowed = activityType == ACTIVITY_TYPE_HOME
|| activityType == ACTIVITY_TYPE_DREAM
|| activityType == ACTIVITY_TYPE_ASSISTANT;
- if (mCurrentDreamToken != null && !mCurrentDreamIsWaking && !activityAllowed) {
- stopDreamInternal(false, "activity starting: " + activityInfo.name);
+ if (mCurrentDreamToken != null && !mCurrentDreamIsWaking
+ && !mCurrentDreamIsDozing && !activityAllowed) {
+ requestAwakenInternal(
+ "stopping dream due to activity start: " + activityInfo.name);
}
}
};
@@ -229,13 +231,13 @@
mPowerManager.nap(time);
}
- private void requestAwakenInternal() {
+ private void requestAwakenInternal(String reason) {
// Treat an explicit request to awaken as user activity so that the
// device doesn't immediately go to sleep if the timeout expired,
// for example when being undocked.
long time = SystemClock.uptimeMillis();
mPowerManager.userActivity(time, false /*noChangeLights*/);
- stopDreamInternal(false /*immediate*/, "request awaken");
+ stopDreamInternal(false /*immediate*/, reason);
}
private void finishSelfInternal(IBinder token, boolean immediate) {
@@ -715,7 +717,7 @@
final long ident = Binder.clearCallingIdentity();
try {
- requestAwakenInternal();
+ requestAwakenInternal("request awaken");
} finally {
Binder.restoreCallingIdentity(ident);
}
diff --git a/services/core/java/com/android/server/firewall/IntentFirewall.java b/services/core/java/com/android/server/firewall/IntentFirewall.java
index bb8a744..2b95b11 100644
--- a/services/core/java/com/android/server/firewall/IntentFirewall.java
+++ b/services/core/java/com/android/server/firewall/IntentFirewall.java
@@ -25,6 +25,7 @@
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
+import android.os.Binder;
import android.os.Environment;
import android.os.FileObserver;
import android.os.Handler;
@@ -129,7 +130,7 @@
mObserver.startWatching();
}
- private PackageManagerInternal getPackageManager() {
+ PackageManagerInternal getPackageManager() {
if (mPackageManager == null) {
mPackageManager = LocalServices.getService(PackageManagerInternal.class);
}
@@ -623,12 +624,13 @@
}
boolean signaturesMatch(int uid1, int uid2) {
+ final long token = Binder.clearCallingIdentity();
try {
- IPackageManager pm = AppGlobals.getPackageManager();
- return pm.checkUidSignatures(uid1, uid2) == PackageManager.SIGNATURE_MATCH;
- } catch (RemoteException ex) {
- Slog.e(TAG, "Remote exception while checking signatures", ex);
- return false;
+ // Compare signatures of two packages for different users.
+ return getPackageManager()
+ .checkUidSignaturesForAllUsers(uid1, uid2) == PackageManager.SIGNATURE_MATCH;
+ } finally {
+ Binder.restoreCallingIdentity(token);
}
}
diff --git a/services/core/java/com/android/server/firewall/SenderFilter.java b/services/core/java/com/android/server/firewall/SenderFilter.java
index 0074119..40684fa 100644
--- a/services/core/java/com/android/server/firewall/SenderFilter.java
+++ b/services/core/java/com/android/server/firewall/SenderFilter.java
@@ -16,14 +16,11 @@
package com.android.server.firewall;
-import android.app.AppGlobals;
import android.content.ComponentName;
import android.content.Intent;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.IPackageManager;
+import android.content.pm.PackageManagerInternal;
import android.os.Process;
-import android.os.RemoteException;
-import android.util.Slog;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -37,22 +34,12 @@
private static final String VAL_SYSTEM_OR_SIGNATURE = "system|signature";
private static final String VAL_USER_ID = "userId";
- static boolean isPrivilegedApp(int callerUid, int callerPid) {
+ static boolean isPrivilegedApp(PackageManagerInternal pmi, int callerUid, int callerPid) {
if (callerUid == Process.SYSTEM_UID || callerUid == 0 ||
callerPid == Process.myPid() || callerPid == 0) {
return true;
}
-
- IPackageManager pm = AppGlobals.getPackageManager();
- try {
- return (pm.getPrivateFlagsForUid(callerUid) & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED)
- != 0;
- } catch (RemoteException ex) {
- Slog.e(IntentFirewall.TAG, "Remote exception while retrieving uid flags",
- ex);
- }
-
- return false;
+ return pmi.isUidPrivileged(callerUid);
}
public static final FilterFactory FACTORY = new FilterFactory("sender") {
@@ -89,7 +76,7 @@
@Override
public boolean matches(IntentFirewall ifw, ComponentName resolvedComponent, Intent intent,
int callerUid, int callerPid, String resolvedType, int receivingUid) {
- return isPrivilegedApp(callerUid, callerPid);
+ return isPrivilegedApp(ifw.getPackageManager(), callerUid, callerPid);
}
};
@@ -97,8 +84,8 @@
@Override
public boolean matches(IntentFirewall ifw, ComponentName resolvedComponent, Intent intent,
int callerUid, int callerPid, String resolvedType, int receivingUid) {
- return isPrivilegedApp(callerUid, callerPid) ||
- ifw.signaturesMatch(callerUid, receivingUid);
+ return isPrivilegedApp(ifw.getPackageManager(), callerUid, callerPid)
+ || ifw.signaturesMatch(callerUid, receivingUid);
}
};
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 1ea1457..9bce471f 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -810,35 +810,24 @@
}
}
- /**
- * Change ARC status into the given {@code enabled} status.
- *
- * @return {@code true} if ARC was in "Enabled" status
- */
@ServiceThreadOnly
- boolean setArcStatus(boolean enabled) {
+ void enableArc(List<byte[]> supportedSads) {
assertRunOnServiceThread();
+ HdmiLogger.debug("Set Arc Status[old:%b new:true]", mArcEstablished);
- HdmiLogger.debug("Set Arc Status[old:%b new:%b]", mArcEstablished, enabled);
- boolean oldStatus = mArcEstablished;
- if (enabled) {
- RequestSadAction action = new RequestSadAction(
- this, Constants.ADDR_AUDIO_SYSTEM,
- new RequestSadAction.RequestSadCallback() {
- @Override
- public void onRequestSadDone(List<byte[]> supportedSads) {
- enableAudioReturnChannel(enabled);
- notifyArcStatusToAudioService(enabled, supportedSads);
- mArcEstablished = enabled;
- }
- });
- addAndStartAction(action);
- } else {
- enableAudioReturnChannel(enabled);
- notifyArcStatusToAudioService(enabled, new ArrayList<>());
- mArcEstablished = enabled;
- }
- return oldStatus;
+ enableAudioReturnChannel(true);
+ notifyArcStatusToAudioService(true, supportedSads);
+ mArcEstablished = true;
+ }
+
+ @ServiceThreadOnly
+ void disableArc() {
+ assertRunOnServiceThread();
+ HdmiLogger.debug("Set Arc Status[old:%b new:false]", mArcEstablished);
+
+ enableAudioReturnChannel(false);
+ notifyArcStatusToAudioService(false, new ArrayList<>());
+ mArcEstablished = false;
}
/**
@@ -1066,7 +1055,7 @@
protected int handleTerminateArc(HdmiCecMessage message) {
assertRunOnServiceThread();
if (mService .isPowerStandbyOrTransient()) {
- setArcStatus(false);
+ disableArc();
return Constants.HANDLED;
}
// Do not check ARC configuration since the AVR might have been already removed.
@@ -1353,7 +1342,7 @@
if (avr == null) {
return;
}
- setArcStatus(false);
+ disableArc();
// Seq #44.
removeAllRunningArcAction();
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 9824b4e..f8a74f4 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -4176,7 +4176,11 @@
List<AudioDeviceAttributes> streamMusicDevices =
getAudioManager().getDevicesForAttributes(STREAM_MUSIC_ATTRIBUTES);
if (streamMusicDevices.contains(getAvcAudioOutputDevice())) {
- setStreamMusicVolume(volume, AudioManager.FLAG_ABSOLUTE_VOLUME);
+ int flags = AudioManager.FLAG_ABSOLUTE_VOLUME;
+ if (isTvDevice()) {
+ flags |= AudioManager.FLAG_SHOW_UI;
+ }
+ setStreamMusicVolume(volume, flags);
}
}
@@ -4190,8 +4194,11 @@
getAudioManager().getDevicesForAttributes(STREAM_MUSIC_ATTRIBUTES);
if (streamMusicDevices.contains(getAvcAudioOutputDevice())) {
int direction = mute ? AudioManager.ADJUST_MUTE : AudioManager.ADJUST_UNMUTE;
- getAudioManager().adjustStreamVolume(AudioManager.STREAM_MUSIC, direction,
- AudioManager.FLAG_ABSOLUTE_VOLUME);
+ int flags = AudioManager.FLAG_ABSOLUTE_VOLUME;
+ if (isTvDevice()) {
+ flags |= AudioManager.FLAG_SHOW_UI;
+ }
+ getAudioManager().adjustStreamVolume(AudioManager.STREAM_MUSIC, direction, flags);
}
}
diff --git a/services/core/java/com/android/server/hdmi/RequestArcAction.java b/services/core/java/com/android/server/hdmi/RequestArcAction.java
index c70101c..3d9a290 100644
--- a/services/core/java/com/android/server/hdmi/RequestArcAction.java
+++ b/services/core/java/com/android/server/hdmi/RequestArcAction.java
@@ -63,7 +63,7 @@
finish();
return true;
} else if (originalOpcode == Constants.MESSAGE_REQUEST_ARC_INITIATION) {
- tv().setArcStatus(false);
+ tv().disableArc();
finish();
return true;
}
diff --git a/services/core/java/com/android/server/hdmi/RequestArcInitiationAction.java b/services/core/java/com/android/server/hdmi/RequestArcInitiationAction.java
index 4eb220f..3b7f1dd 100644
--- a/services/core/java/com/android/server/hdmi/RequestArcInitiationAction.java
+++ b/services/core/java/com/android/server/hdmi/RequestArcInitiationAction.java
@@ -48,7 +48,7 @@
public void onSendCompleted(int error) {
if (error != SendMessageResult.SUCCESS) {
// Turn off ARC status if <Request ARC Initiation> fails.
- tv().setArcStatus(false);
+ tv().disableArc();
finish();
}
}
diff --git a/services/core/java/com/android/server/hdmi/RequestSadAction.java b/services/core/java/com/android/server/hdmi/RequestSadAction.java
index 702c000..23aaf32 100644
--- a/services/core/java/com/android/server/hdmi/RequestSadAction.java
+++ b/services/core/java/com/android/server/hdmi/RequestSadAction.java
@@ -181,13 +181,20 @@
return true;
}
if (cmd.getOpcode() == Constants.MESSAGE_FEATURE_ABORT
- && (cmd.getParams()[0] & 0xFF) == Constants.MESSAGE_REQUEST_SHORT_AUDIO_DESCRIPTOR
- && (cmd.getParams()[1] & 0xFF) == Constants.ABORT_INVALID_OPERAND) {
- // Queried SADs are not supported
- mQueriedSadCount += MAX_SAD_PER_REQUEST;
- mTimeoutRetry = 0;
- querySad();
- return true;
+ && (cmd.getParams()[0] & 0xFF)
+ == Constants.MESSAGE_REQUEST_SHORT_AUDIO_DESCRIPTOR) {
+ if ((cmd.getParams()[1] & 0xFF) == Constants.ABORT_UNRECOGNIZED_OPCODE) {
+ // SAD feature is not supported
+ wrapUpAndFinish();
+ return true;
+ }
+ if ((cmd.getParams()[1] & 0xFF) == Constants.ABORT_INVALID_OPERAND) {
+ // Queried SADs are not supported
+ mQueriedSadCount += MAX_SAD_PER_REQUEST;
+ mTimeoutRetry = 0;
+ querySad();
+ return true;
+ }
}
return false;
}
@@ -211,9 +218,9 @@
querySad();
return;
}
- mQueriedSadCount += MAX_SAD_PER_REQUEST;
- mTimeoutRetry = 0;
- querySad();
+ // Don't query any other SADs if one of the SAD queries ran into the maximum amount of
+ // retries.
+ wrapUpAndFinish();
}
}
diff --git a/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java b/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java
index db93ad0..32e274e 100644
--- a/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java
+++ b/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java
@@ -20,6 +20,8 @@
import android.hardware.tv.cec.V1_0.SendMessageResult;
import android.util.Slog;
+import java.util.List;
+
/**
* Feature action that handles enabling/disabling of ARC transmission channel.
* Once TV gets <Initiate ARC>, TV sends <Report ARC Initiated> to AV Receiver.
@@ -55,21 +57,31 @@
boolean start() {
// Seq #37.
if (mEnabled) {
- // Enable ARC status immediately before sending <Report Arc Initiated>.
- // If AVR responds with <Feature Abort>, disable ARC status again.
- // This is different from spec that says that turns ARC status to
- // "Enabled" if <Report ARC Initiated> is acknowledged and no
- // <Feature Abort> is received.
- // But implemented this way to save the time having to wait for
- // <Feature Abort>.
- setArcStatus(true);
- // If succeeds to send <Report ARC Initiated>, wait general timeout
- // to check whether there is no <Feature Abort> for <Report ARC Initiated>.
- mState = STATE_WAITING_TIMEOUT;
- addTimer(mState, HdmiConfig.TIMEOUT_MS);
- sendReportArcInitiated();
+ // Request SADs before enabling ARC
+ RequestSadAction action = new RequestSadAction(
+ localDevice(), Constants.ADDR_AUDIO_SYSTEM,
+ new RequestSadAction.RequestSadCallback() {
+ @Override
+ public void onRequestSadDone(List<byte[]> supportedSads) {
+ // Enable ARC status immediately before sending <Report Arc Initiated>.
+ // If AVR responds with <Feature Abort>, disable ARC status again.
+ // This is different from spec that says that turns ARC status to
+ // "Enabled" if <Report ARC Initiated> is acknowledged and no
+ // <Feature Abort> is received.
+ // But implemented this way to save the time having to wait for
+ // <Feature Abort>.
+ Slog.i(TAG, "Enabling ARC");
+ tv().enableArc(supportedSads);
+ // If succeeds to send <Report ARC Initiated>, wait general timeout to
+ // check whether there is no <Feature Abort> for <Report ARC Initiated>.
+ mState = STATE_WAITING_TIMEOUT;
+ addTimer(mState, HdmiConfig.TIMEOUT_MS);
+ sendReportArcInitiated();
+ }
+ });
+ addAndStartAction(action);
} else {
- setArcStatus(false);
+ disableArc();
finish();
}
return true;
@@ -92,7 +104,7 @@
case SendMessageResult.NACK:
// If <Report ARC Initiated> is negatively ack'ed, disable ARC and
// send <Report ARC Terminated> directly.
- setArcStatus(false);
+ disableArc();
HdmiLogger.debug("Failed to send <Report Arc Initiated>.");
finish();
break;
@@ -101,16 +113,12 @@
});
}
- private void setArcStatus(boolean enabled) {
- tv().setArcStatus(enabled);
- Slog.i(TAG, "Change arc status to " + enabled);
+ private void disableArc() {
+ Slog.i(TAG, "Disabling ARC");
- // If enabled before and set to "disabled" and send <Report Arc Terminated> to
- // av reciever.
- if (!enabled) {
- sendCommand(HdmiCecMessageBuilder.buildReportArcTerminated(getSourceAddress(),
- mAvrAddress));
- }
+ tv().disableArc();
+ sendCommand(HdmiCecMessageBuilder.buildReportArcTerminated(getSourceAddress(),
+ mAvrAddress));
}
@Override
@@ -124,7 +132,7 @@
int originalOpcode = cmd.getParams()[0] & 0xFF;
if (originalOpcode == Constants.MESSAGE_REPORT_ARC_INITIATED) {
HdmiLogger.debug("Feature aborted for <Report Arc Initiated>");
- setArcStatus(false);
+ disableArc();
finish();
return true;
}
diff --git a/services/core/java/com/android/server/input/TEST_MAPPING b/services/core/java/com/android/server/input/TEST_MAPPING
new file mode 100644
index 0000000..9626d8d
--- /dev/null
+++ b/services/core/java/com/android/server/input/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "imports": [
+ {
+ "path": "frameworks/native/services/inputflinger"
+ }
+ ]
+}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
index c4ff4ac..9a0809d 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
@@ -275,6 +275,7 @@
private final ServiceConnection mVisibleConnection = new ServiceConnection() {
@Override public void onBindingDied(ComponentName name) {
synchronized (ImfLock.class) {
+ mService.invalidateAutofillSessionLocked();
if (mVisibleBound) {
unbindVisibleConnection();
}
@@ -285,6 +286,9 @@
}
@Override public void onServiceDisconnected(ComponentName name) {
+ synchronized (ImfLock.class) {
+ mService.invalidateAutofillSessionLocked();
+ }
}
};
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 7615f78..ba8f551 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -313,6 +313,15 @@
@Nullable
private CreateInlineSuggestionsRequest mPendingInlineSuggestionsRequest;
+ /**
+ * A callback into the autofill service obtained from the latest call to
+ * {@link #onCreateInlineSuggestionsRequestLocked}, which can be used to invalidate an
+ * autofill session in case the IME process dies.
+ */
+ @GuardedBy("ImfLock.class")
+ @Nullable
+ private IInlineSuggestionsRequestCallback mInlineSuggestionsRequestCallback;
+
@UserIdInt
private int mLastSwitchUserId;
@@ -2183,6 +2192,7 @@
InlineSuggestionsRequestInfo requestInfo, IInlineSuggestionsRequestCallback callback,
boolean touchExplorationEnabled) {
clearPendingInlineSuggestionsRequestLocked();
+ mInlineSuggestionsRequestCallback = callback;
final InputMethodInfo imi = mMethodMap.get(getSelectedMethodIdLocked());
try {
if (userId == mSettings.getCurrentUserId()
@@ -2804,6 +2814,7 @@
if (DEBUG) {
Slog.d(TAG, "Avoiding IME startup and unbinding current input method.");
}
+ invalidateAutofillSessionLocked();
mBindingController.unbindCurrentMethod();
return InputBindResult.NO_EDITOR;
}
@@ -2842,6 +2853,17 @@
}
@GuardedBy("ImfLock.class")
+ void invalidateAutofillSessionLocked() {
+ if (mInlineSuggestionsRequestCallback != null) {
+ try {
+ mInlineSuggestionsRequestCallback.onInlineSuggestionsSessionInvalidated();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Cannot invalidate autofill session.", e);
+ }
+ }
+ }
+
+ @GuardedBy("ImfLock.class")
private boolean shouldPreventImeStartupLocked(
@NonNull String selectedMethodId,
@StartInputFlags int startInputFlags,
diff --git a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
index ea99e79..f5c2bbc 100644
--- a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
@@ -1587,6 +1587,7 @@
if (isGpsEnabled()) {
setGpsEnabled(false);
updateEnabled();
+ restartLocationRequest();
}
}
diff --git a/services/core/java/com/android/server/location/gnss/GnssNetworkConnectivityHandler.java b/services/core/java/com/android/server/location/gnss/GnssNetworkConnectivityHandler.java
index 718f98a..70b8689 100644
--- a/services/core/java/com/android/server/location/gnss/GnssNetworkConnectivityHandler.java
+++ b/services/core/java/com/android/server/location/gnss/GnssNetworkConnectivityHandler.java
@@ -200,7 +200,7 @@
mHandler = new Handler(looper);
mNiHandler = niHandler;
mConnMgr = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
- mSuplConnectivityCallback = createSuplConnectivityCallback();
+ mSuplConnectivityCallback = null;
}
/**
@@ -584,11 +584,21 @@
networkRequestBuilder.setNetworkSpecifier(Integer.toString(mActiveSubId));
}
NetworkRequest networkRequest = networkRequestBuilder.build();
- mConnMgr.requestNetwork(
- networkRequest,
- mSuplConnectivityCallback,
- mHandler,
- SUPL_NETWORK_REQUEST_TIMEOUT_MILLIS);
+ // Make sure we only have a single request.
+ if (mSuplConnectivityCallback != null) {
+ mConnMgr.unregisterNetworkCallback(mSuplConnectivityCallback);
+ }
+ mSuplConnectivityCallback = createSuplConnectivityCallback();
+ try {
+ mConnMgr.requestNetwork(
+ networkRequest,
+ mSuplConnectivityCallback,
+ mHandler,
+ SUPL_NETWORK_REQUEST_TIMEOUT_MILLIS);
+ } catch (RuntimeException e) {
+ Log.e(TAG, "Failed to request network.", e);
+ handleReleaseSuplConnection(GPS_AGPS_DATA_CONN_FAILED);
+ }
}
private int getNetworkCapability(int agpsType) {
@@ -619,7 +629,10 @@
}
mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED;
- mConnMgr.unregisterNetworkCallback(mSuplConnectivityCallback);
+ if (mSuplConnectivityCallback != null) {
+ mConnMgr.unregisterNetworkCallback(mSuplConnectivityCallback);
+ mSuplConnectivityCallback = null;
+ }
switch (agpsDataConnStatus) {
case GPS_AGPS_DATA_CONN_FAILED:
native_agps_data_conn_failed();
diff --git a/services/core/java/com/android/server/media/TEST_MAPPING b/services/core/java/com/android/server/media/TEST_MAPPING
new file mode 100644
index 0000000..1b49093
--- /dev/null
+++ b/services/core/java/com/android/server/media/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "CtsMediaBetterTogetherTestCases"
+ }
+ ]
+}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index fbcdd00..8ff9c2a 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -657,7 +657,6 @@
private int mWarnRemoteViewsSizeBytes;
private int mStripRemoteViewsSizeBytes;
- private boolean mForceUserSetOnUpgrade;
private MetricsLogger mMetricsLogger;
private NotificationChannelLogger mNotificationChannelLogger;
@@ -2285,6 +2284,7 @@
mNotificationChannelLogger,
mAppOps,
new SysUiStatsEvent.BuilderFactory());
+ mPreferencesHelper.updateFixedImportance(mUm.getUsers());
mRankingHelper = new RankingHelper(getContext(),
mRankingHandler,
mPreferencesHelper,
@@ -2472,9 +2472,6 @@
WorkerHandler handler = new WorkerHandler(Looper.myLooper());
- mForceUserSetOnUpgrade = getContext().getResources().getBoolean(
- R.bool.config_notificationForceUserSetOnUpgrade);
-
init(handler, new RankingHandlerWorker(mRankingThread.getLooper()),
AppGlobals.getPackageManager(), getContext().getPackageManager(),
getLocalService(LightsManager.class),
@@ -2503,8 +2500,7 @@
LocalServices.getService(ActivityManagerInternal.class),
createToastRateLimiter(), new PermissionHelper(LocalServices.getService(
PermissionManagerServiceInternal.class), AppGlobals.getPackageManager(),
- AppGlobals.getPermissionManager(),
- mForceUserSetOnUpgrade),
+ AppGlobals.getPermissionManager()),
LocalServices.getService(UsageStatsManagerInternal.class),
getContext().getSystemService(TelecomManager.class),
new NotificationChannelLoggerImpl());
@@ -3633,6 +3629,12 @@
}
@Override
+ public boolean isImportanceLocked(String pkg, int uid) {
+ checkCallerIsSystem();
+ return mPreferencesHelper.isImportanceLocked(pkg, uid);
+ }
+
+ @Override
public boolean canShowBadge(String pkg, int uid) {
checkCallerIsSystem();
return mPreferencesHelper.canShowBadge(pkg, uid);
@@ -6147,7 +6149,6 @@
pw.println(" mMaxPackageEnqueueRate=" + mMaxPackageEnqueueRate);
pw.println(" hideSilentStatusBar="
+ mPreferencesHelper.shouldHideSilentStatusIcons());
- pw.println(" mForceUserSetOnUpgrade=" + mForceUserSetOnUpgrade);
}
pw.println(" mArchive=" + mArchive.toString());
mArchive.dumpImpl(pw, filter);
diff --git a/services/core/java/com/android/server/notification/PermissionHelper.java b/services/core/java/com/android/server/notification/PermissionHelper.java
index b2fee1e..09ed567 100644
--- a/services/core/java/com/android/server/notification/PermissionHelper.java
+++ b/services/core/java/com/android/server/notification/PermissionHelper.java
@@ -16,7 +16,6 @@
package com.android.server.notification;
-import static android.content.pm.PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET;
import static android.content.pm.PackageManager.GET_PERMISSIONS;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
@@ -55,14 +54,12 @@
private final PermissionManagerServiceInternal mPmi;
private final IPackageManager mPackageManager;
private final IPermissionManager mPermManager;
- private final boolean mForceUserSetOnUpgrade;
public PermissionHelper(PermissionManagerServiceInternal pmi, IPackageManager packageManager,
- IPermissionManager permManager, boolean forceUserSetOnUpgrade) {
+ IPermissionManager permManager) {
mPmi = pmi;
mPackageManager = packageManager;
mPermManager = permManager;
- mForceUserSetOnUpgrade = forceUserSetOnUpgrade;
}
/**
@@ -72,8 +69,7 @@
public boolean hasPermission(int uid) {
final long callingId = Binder.clearCallingIdentity();
try {
- return mPmi.checkPostNotificationsPermissionGrantedOrLegacyAccess(uid)
- == PERMISSION_GRANTED;
+ return mPmi.checkUidPermission(uid, NOTIFICATION_PERMISSION) == PERMISSION_GRANTED;
} finally {
Binder.restoreCallingIdentity(callingId);
}
@@ -153,21 +149,13 @@
}
/**
- * @see setNotificationPermission(String, int, boolean, boolean, boolean)
- */
- public void setNotificationPermission(String packageName, @UserIdInt int userId, boolean grant,
- boolean userSet) {
- setNotificationPermission(packageName, userId, grant, userSet, false);
- }
-
- /**
* Grants or revokes the notification permission for a given package/user. UserSet should
* only be true if this method is being called to migrate existing user choice, because it
* can prevent the user from seeing the in app permission dialog. Must not be called
* with a lock held.
*/
public void setNotificationPermission(String packageName, @UserIdInt int userId, boolean grant,
- boolean userSet, boolean reviewRequired) {
+ boolean userSet) {
final long callingId = Binder.clearCallingIdentity();
try {
// Do not change the permission if the package doesn't request it, do not change fixed
@@ -181,7 +169,7 @@
boolean currentlyGranted = mPmi.checkPermission(packageName, NOTIFICATION_PERMISSION,
userId) != PackageManager.PERMISSION_DENIED;
- if (grant && !reviewRequired && !currentlyGranted) {
+ if (grant && !currentlyGranted) {
mPermManager.grantRuntimePermission(packageName, NOTIFICATION_PERMISSION, userId);
} else if (!grant && currentlyGranted) {
mPermManager.revokeRuntimePermission(packageName, NOTIFICATION_PERMISSION,
@@ -189,12 +177,10 @@
}
if (userSet) {
mPermManager.updatePermissionFlags(packageName, NOTIFICATION_PERMISSION,
- FLAG_PERMISSION_USER_SET | FLAG_PERMISSION_REVIEW_REQUIRED,
- FLAG_PERMISSION_USER_SET, true, userId);
- } else if (reviewRequired) {
+ FLAG_PERMISSION_USER_SET, FLAG_PERMISSION_USER_SET, true, userId);
+ } else {
mPermManager.updatePermissionFlags(packageName, NOTIFICATION_PERMISSION,
- FLAG_PERMISSION_REVIEW_REQUIRED, FLAG_PERMISSION_REVIEW_REQUIRED, true,
- userId);
+ 0, FLAG_PERMISSION_USER_SET, true, userId);
}
} catch (RemoteException e) {
Slog.e(TAG, "Could not reach system server", e);
@@ -212,9 +198,8 @@
return;
}
if (!isPermissionFixed(pkgPerm.packageName, pkgPerm.userId)) {
- boolean userSet = mForceUserSetOnUpgrade ? true : pkgPerm.userModifiedSettings;
setNotificationPermission(pkgPerm.packageName, pkgPerm.userId, pkgPerm.granted,
- userSet, !userSet);
+ true /* userSet always true on upgrade */);
}
}
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 4e3fbaa..97133a5 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -42,8 +42,10 @@
import android.app.NotificationManager;
import android.content.Context;
import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ParceledListSlice;
+import android.content.pm.UserInfo;
import android.metrics.LogMaker;
import android.os.Binder;
import android.os.Build;
@@ -146,7 +148,6 @@
static final boolean DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS = false;
private static final boolean DEFAULT_SHOW_BADGE = true;
- private static final boolean DEFAULT_OEM_LOCKED_IMPORTANCE = false;
private static final boolean DEFAULT_APP_LOCKED_IMPORTANCE = false;
static final boolean DEFAULT_BUBBLES_ENABLED = true;
@@ -193,8 +194,6 @@
private boolean mAllowInvalidShortcuts = false;
- private Map<String, List<String>> mOemLockedApps = new HashMap();
-
public PreferencesHelper(Context context, PackageManager pm, RankingHandler rankingHandler,
ZenModeHelper zenHelper, PermissionHelper permHelper,
NotificationChannelLogger notificationChannelLogger,
@@ -411,7 +410,7 @@
channel.populateFromXml(parser);
}
channel.setImportanceLockedByCriticalDeviceFunction(
- r.defaultAppLockedImportance);
+ r.defaultAppLockedImportance || r.fixedImportance);
if (isShortcutOk(channel) && isDeletionOk(channel)) {
r.channels.put(id, channel);
@@ -484,14 +483,6 @@
r.visibility = visibility;
r.showBadge = showBadge;
r.bubblePreference = bubblePreference;
- if (mOemLockedApps.containsKey(r.pkg)) {
- List<String> channels = mOemLockedApps.get(r.pkg);
- if (channels == null || channels.isEmpty()) {
- r.oemLockedImportance = true;
- } else {
- r.oemLockedChannels = channels;
- }
- }
try {
createDefaultChannelIfNeededLocked(r);
@@ -818,6 +809,13 @@
}
}
+ boolean isImportanceLocked(String pkg, int uid) {
+ synchronized (mPackagePreferences) {
+ PackagePreferences r = getOrCreatePackagePreferencesLocked(pkg, uid);
+ return r.fixedImportance || r.defaultAppLockedImportance;
+ }
+ }
+
@Override
public boolean isGroupBlocked(String packageName, int uid, String groupId) {
if (groupId == null) {
@@ -1008,7 +1006,7 @@
clearLockedFieldsLocked(channel);
channel.setImportanceLockedByCriticalDeviceFunction(
- r.defaultAppLockedImportance);
+ r.defaultAppLockedImportance || r.fixedImportance);
if (channel.getLockscreenVisibility() == Notification.VISIBILITY_PUBLIC) {
channel.setLockscreenVisibility(
@@ -1090,8 +1088,7 @@
updatedChannel.unlockFields(updatedChannel.getUserLockedFields());
}
- if ((mPermissionHelper.isPermissionFixed(r.pkg, UserHandle.getUserId(r.uid))
- || channel.isImportanceLockedByCriticalDeviceFunction())
+ if (channel.isImportanceLockedByCriticalDeviceFunction()
&& !(channel.isBlockable() || channel.getImportance() == IMPORTANCE_NONE)) {
updatedChannel.setImportance(channel.getImportance());
}
@@ -1267,6 +1264,28 @@
mHideSilentStatusBarIcons = hide;
}
+ public void updateFixedImportance(List<UserInfo> users) {
+ for (UserInfo user : users) {
+ List<PackageInfo> packages = mPm.getInstalledPackagesAsUser(
+ PackageManager.PackageInfoFlags.of(PackageManager.MATCH_SYSTEM_ONLY),
+ user.getUserHandle().getIdentifier());
+ for (PackageInfo pi : packages) {
+ boolean fixed = mPermissionHelper.isPermissionFixed(
+ pi.packageName, user.getUserHandle().getIdentifier());
+ if (fixed) {
+ synchronized (mPackagePreferences) {
+ PackagePreferences p = getOrCreatePackagePreferencesLocked(
+ pi.packageName, pi.applicationInfo.uid);
+ p.fixedImportance = true;
+ for (NotificationChannel channel : p.channels.values()) {
+ channel.setImportanceLockedByCriticalDeviceFunction(true);
+ }
+ }
+ }
+ }
+ }
+ }
+
public void updateDefaultApps(int userId, ArraySet<String> toRemove,
ArraySet<Pair<String, Integer>> toAdd) {
synchronized (mPackagePreferences) {
@@ -1274,8 +1293,10 @@
if (userId == UserHandle.getUserId(p.uid)) {
if (toRemove != null && toRemove.contains(p.pkg)) {
p.defaultAppLockedImportance = false;
- for (NotificationChannel channel : p.channels.values()) {
- channel.setImportanceLockedByCriticalDeviceFunction(false);
+ if (!p.fixedImportance) {
+ for (NotificationChannel channel : p.channels.values()) {
+ channel.setImportanceLockedByCriticalDeviceFunction(false);
+ }
}
}
}
@@ -1934,13 +1955,9 @@
pw.print(" defaultAppLocked=");
pw.print(r.defaultAppLockedImportance);
}
- if (r.oemLockedImportance != DEFAULT_OEM_LOCKED_IMPORTANCE) {
- pw.print(" oemLocked=");
- pw.print(r.oemLockedImportance);
- }
- if (!r.oemLockedChannels.isEmpty()) {
- pw.print(" futureLockedChannels=");
- pw.print(r.oemLockedChannels);
+ if (r.fixedImportance != DEFAULT_APP_LOCKED_IMPORTANCE) {
+ pw.print(" fixedImportance=");
+ pw.print(r.fixedImportance);
}
pw.println();
for (NotificationChannel channel : r.channels.values()) {
@@ -2682,9 +2699,8 @@
int lockedAppFields = DEFAULT_LOCKED_APP_FIELDS;
// these fields are loaded on boot from a different source of truth and so are not
// written to notification policy xml
- boolean oemLockedImportance = DEFAULT_OEM_LOCKED_IMPORTANCE;
- List<String> oemLockedChannels = new ArrayList<>();
boolean defaultAppLockedImportance = DEFAULT_APP_LOCKED_IMPORTANCE;
+ boolean fixedImportance = DEFAULT_APP_LOCKED_IMPORTANCE;
boolean hasSentInvalidMessage = false;
boolean hasSentValidMessage = false;
diff --git a/services/core/java/com/android/server/om/OverlayManagerShellCommand.java b/services/core/java/com/android/server/om/OverlayManagerShellCommand.java
index 89939a3..bdde4f6 100644
--- a/services/core/java/com/android/server/om/OverlayManagerShellCommand.java
+++ b/services/core/java/com/android/server/om/OverlayManagerShellCommand.java
@@ -33,10 +33,20 @@
import android.os.RemoteException;
import android.os.ShellCommand;
import android.os.UserHandle;
+import android.text.TextUtils;
import android.util.TypedValue;
+import android.util.TypedXmlPullParser;
+import android.util.Xml;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
+import java.util.Locale;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -51,6 +61,8 @@
final class OverlayManagerShellCommand extends ShellCommand {
private final Context mContext;
private final IOverlayManager mInterface;
+ private static final Map<String, Integer> TYPE_MAP = Map.of(
+ "color", TypedValue.TYPE_FIRST_COLOR_INT);
OverlayManagerShellCommand(@NonNull final Context ctx, @NonNull final IOverlayManager iom) {
mContext = ctx;
@@ -126,7 +138,8 @@
out.println(" applying the current configuration and enabled overlays.");
out.println(" For a more fine-grained alternative, use 'idmap2 lookup'.");
out.println(" fabricate [--user USER_ID] [--target-name OVERLAYABLE] --target PACKAGE");
- out.println(" --name NAME PACKAGE:TYPE/NAME ENCODED-TYPE-ID ENCODED-VALUE");
+ out.println(" --name NAME [--file FILE] ");
+ out.println(" PACKAGE:TYPE/NAME ENCODED-TYPE-ID/TYPE-NAME ENCODED-VALUE");
out.println(" Create an overlay from a single resource. Caller must be root. Example:");
out.println(" fabricate --target android --name LighterGray \\");
out.println(" android:color/lighter_gray 0x1c 0xffeeeeee");
@@ -241,6 +254,7 @@
String targetPackage = "";
String targetOverlayable = "";
String name = "";
+ String filename = null;
String opt;
while ((opt = getNextOption()) != null) {
switch (opt) {
@@ -256,6 +270,9 @@
case "--name":
name = getNextArgRequired();
break;
+ case "--file":
+ filename = getNextArgRequired();
+ break;
default:
err.println("Error: Unknown option: " + opt);
return 1;
@@ -271,42 +288,117 @@
err.println("Error: Missing required arg '--target'");
return 1;
}
-
- final String resourceName = getNextArgRequired();
- final String typeStr = getNextArgRequired();
- final int type;
- if (typeStr.startsWith("0x")) {
- type = Integer.parseUnsignedInt(typeStr.substring(2), 16);
- } else {
- type = Integer.parseUnsignedInt(typeStr);
- }
- final String dataStr = getNextArgRequired();
- final int data;
- if (dataStr.startsWith("0x")) {
- data = Integer.parseUnsignedInt(dataStr.substring(2), 16);
- } else {
- data = Integer.parseUnsignedInt(dataStr);
- }
-
- final PackageManager pm = mContext.getPackageManager();
- if (pm == null) {
- err.println("Error: failed to get package manager");
+ if (filename != null && getRemainingArgsCount() > 0) {
+ err.println(
+ "Error: When passing --file don't pass resource name, type, and value as well");
return 1;
}
-
final String overlayPackageName = "com.android.shell";
- final FabricatedOverlay overlay = new FabricatedOverlay.Builder(
+ FabricatedOverlay.Builder overlayBuilder = new FabricatedOverlay.Builder(
overlayPackageName, name, targetPackage)
- .setTargetOverlayable(targetOverlayable)
- .setResourceValue(resourceName, type, data)
- .build();
+ .setTargetOverlayable(targetOverlayable);
+ if (filename != null) {
+ int result = addOverlayValuesFromXml(overlayBuilder, targetPackage, filename);
+ if (result != 0) {
+ return result;
+ }
+ } else {
+ final String resourceName = getNextArgRequired();
+ final String typeStr = getNextArgRequired();
+ final String strData = getNextArgRequired();
+ addOverlayValue(overlayBuilder, resourceName, typeStr, strData);
+ }
mInterface.commit(new OverlayManagerTransaction.Builder()
- .registerFabricatedOverlay(overlay)
- .build());
+ .registerFabricatedOverlay(overlayBuilder.build()).build());
return 0;
}
+ private int addOverlayValuesFromXml(
+ FabricatedOverlay.Builder overlayBuilder, String targetPackage, String filename) {
+ final PrintWriter err = getErrPrintWriter();
+ File file = new File(filename);
+ if (!file.exists()) {
+ err.println("Error: File does not exist");
+ return 1;
+ }
+ if (!file.canRead()) {
+ err.println("Error: File is unreadable");
+ return 1;
+ }
+ try (FileInputStream fis = new FileInputStream(file)) {
+ TypedXmlPullParser parser = Xml.resolvePullParser(fis);
+ int type;
+ while ((type = parser.next()) != XmlPullParser.START_TAG
+ && type != XmlPullParser.END_DOCUMENT) {
+ continue;
+ }
+ parser.require(XmlPullParser.START_TAG, null, "overlay");
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
+ if (type == XmlPullParser.START_TAG) {
+ String tagName = parser.getName();
+ if (!tagName.equals("item")) {
+ err.println(TextUtils.formatSimple("Error: Unexpected tag: %s at line %d",
+ tagName, parser.getLineNumber()));
+ } else if (!parser.isEmptyElementTag()) {
+ err.println("Error: item tag must be empty");
+ return 1;
+ } else {
+ String target = parser.getAttributeValue(null, "target");
+ if (TextUtils.isEmpty(target)) {
+ err.println(
+ "Error: target name missing at line " + parser.getLineNumber());
+ return 1;
+ }
+ int index = target.indexOf('/');
+ if (index < 0) {
+ err.println("Error: target malformed, missing '/' at line "
+ + parser.getLineNumber());
+ return 1;
+ }
+ String overlayType = target.substring(0, index);
+ String value = parser.getAttributeValue(null, "value");
+ if (TextUtils.isEmpty(value)) {
+ err.println("Error: value missing at line " + parser.getLineNumber());
+ return 1;
+ }
+ addOverlayValue(overlayBuilder, targetPackage + ':' + target,
+ overlayType, value);
+ }
+ }
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ return 1;
+ } catch (XmlPullParserException e) {
+ e.printStackTrace();
+ return 1;
+ }
+ return 0;
+ }
+
+ private void addOverlayValue(FabricatedOverlay.Builder overlayBuilder,
+ String resourceName, String typeString, String valueString) {
+ final int type;
+ typeString = typeString.toLowerCase(Locale.getDefault());
+ if (TYPE_MAP.containsKey(typeString)) {
+ type = TYPE_MAP.get(typeString);
+ } else {
+ if (typeString.startsWith("0x")) {
+ type = Integer.parseUnsignedInt(typeString.substring(2), 16);
+ } else {
+ type = Integer.parseUnsignedInt(typeString);
+ }
+ }
+ final int intData;
+ if (valueString.startsWith("0x")) {
+ intData = Integer.parseUnsignedInt(valueString.substring(2), 16);
+ } else {
+ intData = Integer.parseUnsignedInt(valueString);
+ }
+ overlayBuilder.setResourceValue(resourceName, type, intData);
+ }
+
private int runEnableExclusive() throws RemoteException {
final PrintWriter err = getErrPrintWriter();
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index e00f66e..01ddc48 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -121,18 +121,21 @@
public final File preInstalledApexPath;
public final boolean isFactory;
public final File apexFile;
+ public final boolean activeApexChanged;
private ActiveApexInfo(File apexDirectory, File preInstalledApexPath, File apexFile) {
- this(null, apexDirectory, preInstalledApexPath, true, apexFile);
+ this(null, apexDirectory, preInstalledApexPath, true, apexFile, false);
}
private ActiveApexInfo(@Nullable String apexModuleName, File apexDirectory,
- File preInstalledApexPath, boolean isFactory, File apexFile) {
+ File preInstalledApexPath, boolean isFactory, File apexFile,
+ boolean activeApexChanged) {
this.apexModuleName = apexModuleName;
this.apexDirectory = apexDirectory;
this.preInstalledApexPath = preInstalledApexPath;
this.isFactory = isFactory;
this.apexFile = apexFile;
+ this.activeApexChanged = activeApexChanged;
}
private ActiveApexInfo(ApexInfo apexInfo) {
@@ -142,7 +145,8 @@
+ apexInfo.moduleName),
new File(apexInfo.preinstalledModulePath),
apexInfo.isFactory,
- new File(apexInfo.modulePath));
+ new File(apexInfo.modulePath),
+ apexInfo.activeApexChanged);
}
}
diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
index d26a1ac..5a01ccb 100644
--- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java
+++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
@@ -17,6 +17,7 @@
package com.android.server.pm;
import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
+import static com.android.server.pm.dex.ArtStatsLogUtils.BackgroundDexoptJobStatsLogger;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -77,43 +78,46 @@
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
- @VisibleForTesting
- static final int JOB_IDLE_OPTIMIZE = 800;
- @VisibleForTesting
- static final int JOB_POST_BOOT_UPDATE = 801;
+ @VisibleForTesting static final int JOB_IDLE_OPTIMIZE = 800;
+ @VisibleForTesting static final int JOB_POST_BOOT_UPDATE = 801;
private static final long IDLE_OPTIMIZATION_PERIOD = TimeUnit.DAYS.toMillis(1);
private static final long CANCELLATION_WAIT_CHECK_INTERVAL_MS = 200;
- private static ComponentName sDexoptServiceName = new ComponentName("android",
- BackgroundDexOptJobService.class.getName());
+ private static ComponentName sDexoptServiceName =
+ new ComponentName("android", BackgroundDexOptJobService.class.getName());
// Possible return codes of individual optimization steps.
/** Ok status: Optimizations finished, All packages were processed, can continue */
- private static final int STATUS_OK = 0;
+ public static final int STATUS_OK = 0;
/** Optimizations should be aborted. Job scheduler requested it. */
- private static final int STATUS_ABORT_BY_CANCELLATION = 1;
+ public static final int STATUS_ABORT_BY_CANCELLATION = 1;
/** Optimizations should be aborted. No space left on device. */
- private static final int STATUS_ABORT_NO_SPACE_LEFT = 2;
+ public static final int STATUS_ABORT_NO_SPACE_LEFT = 2;
/** Optimizations should be aborted. Thermal throttling level too high. */
- private static final int STATUS_ABORT_THERMAL = 3;
+ public static final int STATUS_ABORT_THERMAL = 3;
/** Battery level too low */
- private static final int STATUS_ABORT_BATTERY = 4;
- /** {@link PackageDexOptimizer#DEX_OPT_FAILED} case */
- private static final int STATUS_DEX_OPT_FAILED = 5;
+ public static final int STATUS_ABORT_BATTERY = 4;
+ /**
+ * {@link PackageDexOptimizer#DEX_OPT_FAILED} case. This state means some packages have failed
+ * compilation during the job. Note that the failure will not be permanent as the next dexopt
+ * job will exclude those failed packages.
+ */
+ public static final int STATUS_DEX_OPT_FAILED = 5;
- @IntDef(prefix = {"STATUS_"}, value = {
- STATUS_OK,
- STATUS_ABORT_BY_CANCELLATION,
- STATUS_ABORT_NO_SPACE_LEFT,
- STATUS_ABORT_THERMAL,
- STATUS_ABORT_BATTERY,
- STATUS_DEX_OPT_FAILED,
- })
+ @IntDef(prefix = {"STATUS_"},
+ value =
+ {
+ STATUS_OK,
+ STATUS_ABORT_BY_CANCELLATION,
+ STATUS_ABORT_NO_SPACE_LEFT,
+ STATUS_ABORT_THERMAL,
+ STATUS_ABORT_BATTERY,
+ STATUS_DEX_OPT_FAILED,
+ })
@Retention(RetentionPolicy.SOURCE)
- private @interface Status {
- }
+ public @interface Status {}
// Used for calculating space threshold for downgrading unused apps.
private static final int LOW_THRESHOLD_MULTIPLIER_FOR_DOWNGRADE = 2;
@@ -125,33 +129,30 @@
private final DexOptHelper mDexOptHelper;
+ private final BackgroundDexoptJobStatsLogger mStatsLogger =
+ new BackgroundDexoptJobStatsLogger();
+
private final Object mLock = new Object();
// Thread currently running dexopt. This will be null if dexopt is not running.
// The thread running dexopt make sure to set this into null when the pending dexopt is
// completed.
- @GuardedBy("mLock")
- @Nullable
- private Thread mDexOptThread;
+ @GuardedBy("mLock") @Nullable private Thread mDexOptThread;
// Thread currently cancelling dexopt. This thread is in blocked wait state until
// cancellation is done. Only this thread can change states for control. The other threads, if
// need to wait for cancellation, should just wait without doing any control.
- @GuardedBy("mLock")
- @Nullable
- private Thread mDexOptCancellingThread;
+ @GuardedBy("mLock") @Nullable private Thread mDexOptCancellingThread;
// Tells whether post boot update is completed or not.
- @GuardedBy("mLock")
- private boolean mFinishedPostBootUpdate;
+ @GuardedBy("mLock") private boolean mFinishedPostBootUpdate;
- @GuardedBy("mLock")
- @Status private int mLastExecutionStatus = STATUS_OK;
+ @GuardedBy("mLock") @Status private int mLastExecutionStatus = STATUS_OK;
- @GuardedBy("mLock")
- private long mLastExecutionStartTimeMs;
- @GuardedBy("mLock")
- private long mLastExecutionDurationMs;
+ @GuardedBy("mLock") private long mLastExecutionStartTimeMs;
+ @GuardedBy("mLock") private long mLastExecutionDurationIncludingSleepMs;
+ @GuardedBy("mLock") private long mLastExecutionStartUptimeMs;
+ @GuardedBy("mLock") private long mLastExecutionDurationMs;
// Keeps packages cancelled from PDO for last session. This is for debugging.
@GuardedBy("mLock")
@@ -177,8 +178,8 @@
void onPackagesUpdated(ArraySet<String> updatedPackages);
}
- public BackgroundDexOptService(Context context, DexManager dexManager,
- PackageManagerService pm) {
+ public BackgroundDexOptService(
+ Context context, DexManager dexManager, PackageManagerService pm) {
this(new Injector(context, dexManager, pm));
}
@@ -230,6 +231,10 @@
writer.println(mLastExecutionStatus);
writer.print("mLastExecutionStartTimeMs:");
writer.println(mLastExecutionStartTimeMs);
+ writer.print("mLastExecutionDurationIncludingSleepMs:");
+ writer.println(mLastExecutionDurationIncludingSleepMs);
+ writer.print("mLastExecutionStartUptimeMs:");
+ writer.println(mLastExecutionStartUptimeMs);
writer.print("mLastExecutionDurationMs:");
writer.println(mLastExecutionDurationMs);
writer.print("now:");
@@ -357,17 +362,20 @@
resetStatesForNewDexOptRunLocked(mInjector.createAndStartThread(
"BackgroundDexOptService_" + (isPostBootUpdateJob ? "PostBoot" : "Idle"),
() -> {
- TimingsTraceAndSlog tr = new TimingsTraceAndSlog(TAG,
- Trace.TRACE_TAG_PACKAGE_MANAGER);
+ TimingsTraceAndSlog tr =
+ new TimingsTraceAndSlog(TAG, Trace.TRACE_TAG_PACKAGE_MANAGER);
tr.traceBegin("jobExecution");
boolean completed = false;
try {
- completed = runIdleOptimization(pm, pkgs,
- params.getJobId() == JOB_POST_BOOT_UPDATE);
+ completed = runIdleOptimization(
+ pm, pkgs, params.getJobId() == JOB_POST_BOOT_UPDATE);
} finally { // Those cleanup should be done always.
tr.traceEnd();
- Slog.i(TAG, "dexopt finishing. jobid:" + params.getJobId()
- + " completed:" + completed);
+ Slog.i(TAG,
+ "dexopt finishing. jobid:" + params.getJobId()
+ + " completed:" + completed);
+
+ writeStatsLog(params);
if (params.getJobId() == JOB_POST_BOOT_UPDATE) {
if (completed) {
@@ -451,7 +459,7 @@
if (mDexOptThread != Thread.currentThread()) {
throw new IllegalStateException(
"Only mDexOptThread can mark completion, mDexOptThread:" + mDexOptThread
- + " current:" + Thread.currentThread());
+ + " current:" + Thread.currentThread());
}
mDexOptThread = null;
// Other threads may be waiting for completion.
@@ -481,11 +489,10 @@
private void scheduleAJob(int jobId) {
JobScheduler js = mInjector.getJobScheduler();
- JobInfo.Builder builder = new JobInfo.Builder(jobId, sDexoptServiceName)
- .setRequiresDeviceIdle(true);
+ JobInfo.Builder builder =
+ new JobInfo.Builder(jobId, sDexoptServiceName).setRequiresDeviceIdle(true);
if (jobId == JOB_IDLE_OPTIMIZE) {
- builder.setRequiresCharging(true)
- .setPeriodic(IDLE_OPTIMIZATION_PERIOD);
+ builder.setRequiresCharging(true).setPeriodic(IDLE_OPTIMIZATION_PERIOD);
}
js.schedule(builder.build());
}
@@ -525,30 +532,36 @@
}
}
- /** Returns true if completed */
- private boolean runIdleOptimization(PackageManagerService pm, List<String> pkgs,
- boolean isPostBootUpdate) {
+ /**
+ * Returns whether we've successfully run the job. Note that it will return true even if some
+ * packages may have failed compiling.
+ */
+ private boolean runIdleOptimization(
+ PackageManagerService pm, List<String> pkgs, boolean isPostBootUpdate) {
synchronized (mLock) {
mLastExecutionStartTimeMs = SystemClock.elapsedRealtime();
+ mLastExecutionDurationIncludingSleepMs = -1;
+ mLastExecutionStartUptimeMs = SystemClock.uptimeMillis();
mLastExecutionDurationMs = -1;
}
long lowStorageThreshold = getLowStorageThreshold();
- int status = idleOptimizePackages(pm, pkgs, lowStorageThreshold,
- isPostBootUpdate);
+ int status = idleOptimizePackages(pm, pkgs, lowStorageThreshold, isPostBootUpdate);
logStatus(status);
synchronized (mLock) {
mLastExecutionStatus = status;
- mLastExecutionDurationMs = SystemClock.elapsedRealtime() - mLastExecutionStartTimeMs;
+ mLastExecutionDurationIncludingSleepMs =
+ SystemClock.elapsedRealtime() - mLastExecutionStartTimeMs;
+ mLastExecutionDurationMs = SystemClock.uptimeMillis() - mLastExecutionStartUptimeMs;
}
- return status == STATUS_OK;
+ return status == STATUS_OK || status == STATUS_DEX_OPT_FAILED;
}
/** Gets the size of the directory. It uses recursion to go over all files. */
private long getDirectorySize(File f) {
long size = 0;
if (f.isDirectory()) {
- for (File file: f.listFiles()) {
+ for (File file : f.listFiles()) {
size += getDirectorySize(file);
}
} else {
@@ -599,8 +612,8 @@
// Only downgrade apps when space is low on device.
// Threshold is selected above the lowStorageThreshold so that we can pro-actively clean
// up disk before user hits the actual lowStorageThreshold.
- long lowStorageThresholdForDowngrade = LOW_THRESHOLD_MULTIPLIER_FOR_DOWNGRADE
- * lowStorageThreshold;
+ long lowStorageThresholdForDowngrade =
+ LOW_THRESHOLD_MULTIPLIER_FOR_DOWNGRADE * lowStorageThreshold;
boolean shouldDowngrade = shouldDowngrade(lowStorageThresholdForDowngrade);
if (DEBUG) {
Slog.d(TAG, "Should Downgrade " + shouldDowngrade);
@@ -620,19 +633,20 @@
// Should be aborted by the scheduler.
return abortCode;
}
- @DexOptResult int downgradeResult = downgradePackage(snapshot, pm, pkg,
+ @DexOptResult
+ int downgradeResult = downgradePackage(snapshot, pm, pkg,
/* isForPrimaryDex= */ true, isPostBootUpdate);
if (downgradeResult == PackageDexOptimizer.DEX_OPT_PERFORMED) {
updatedPackages.add(pkg);
}
- @Status int status = convertPackageDexOptimizerStatusToInternal(
- downgradeResult);
+ @Status
+ int status = convertPackageDexOptimizerStatusToInternal(downgradeResult);
if (status != STATUS_OK) {
return status;
}
if (supportSecondaryDex) {
downgradeResult = downgradePackage(snapshot, pm, pkg,
- /* isForPrimaryDex= */false, isPostBootUpdate);
+ /* isForPrimaryDex= */ false, isPostBootUpdate);
status = convertPackageDexOptimizerStatusToInternal(downgradeResult);
if (status != STATUS_OK) {
return status;
@@ -661,6 +675,11 @@
ArraySet<String> updatedPackages, boolean isPostBootUpdate) {
boolean supportSecondaryDex = mInjector.supportSecondaryDex();
+ // Keep the error if there is any error from any package.
+ @Status int status = STATUS_OK;
+
+ // Other than cancellation, all packages will be processed even if an error happens
+ // in a package.
for (String pkg : pkgs) {
int abortCode = abortIdleOptimizations(lowStorageThreshold);
if (abortCode != STATUS_OK) {
@@ -668,26 +687,32 @@
return abortCode;
}
- @DexOptResult int primaryResult =
- optimizePackage(pkg, true /* isForPrimaryDex */, isPostBootUpdate);
+ @DexOptResult
+ int primaryResult = optimizePackage(pkg, true /* isForPrimaryDex */, isPostBootUpdate);
+ if (primaryResult == PackageDexOptimizer.DEX_OPT_CANCELLED) {
+ return STATUS_ABORT_BY_CANCELLATION;
+ }
if (primaryResult == PackageDexOptimizer.DEX_OPT_PERFORMED) {
updatedPackages.add(pkg);
- } else if (primaryResult != PackageDexOptimizer.DEX_OPT_SKIPPED) {
- return convertPackageDexOptimizerStatusToInternal(primaryResult);
+ } else if (primaryResult == PackageDexOptimizer.DEX_OPT_FAILED) {
+ status = convertPackageDexOptimizerStatusToInternal(primaryResult);
}
if (!supportSecondaryDex) {
continue;
}
- @DexOptResult int secondaryResult =
+ @DexOptResult
+ int secondaryResult =
optimizePackage(pkg, false /* isForPrimaryDex */, isPostBootUpdate);
- if (secondaryResult != PackageDexOptimizer.DEX_OPT_PERFORMED
- && secondaryResult != PackageDexOptimizer.DEX_OPT_SKIPPED) {
- return convertPackageDexOptimizerStatusToInternal(secondaryResult);
+ if (secondaryResult == PackageDexOptimizer.DEX_OPT_CANCELLED) {
+ return STATUS_ABORT_BY_CANCELLATION;
+ }
+ if (secondaryResult == PackageDexOptimizer.DEX_OPT_FAILED) {
+ status = convertPackageDexOptimizerStatusToInternal(secondaryResult);
}
}
- return STATUS_OK;
+ return status;
}
/**
@@ -731,7 +756,7 @@
if (result == PackageDexOptimizer.DEX_OPT_PERFORMED) {
final Computer newSnapshot = pm.snapshotComputer();
FrameworkStatsLog.write(FrameworkStatsLog.APP_DOWNGRADED, pkg, package_size_before,
- getPackageSize(newSnapshot, pkg), /*aggressive=*/ false);
+ getPackageSize(newSnapshot, pkg), /*aggressive=*/false);
}
return result;
}
@@ -760,7 +785,7 @@
@DexOptResult
private int optimizePackage(String pkg, boolean isForPrimaryDex, boolean isPostBootUpdate) {
int reason = isPostBootUpdate ? PackageManagerService.REASON_POST_BOOT
- : PackageManagerService.REASON_BACKGROUND_DEXOPT;
+ : PackageManagerService.REASON_BACKGROUND_DEXOPT;
int dexoptFlags = DexoptOptions.DEXOPT_BOOT_COMPLETE;
if (!isPostBootUpdate) {
dexoptFlags |= DexoptOptions.DEXOPT_CHECK_FOR_PROFILES_UPDATES
@@ -777,22 +802,21 @@
}
@DexOptResult
- private int performDexOptPrimary(String pkg, int reason,
- int dexoptFlags) {
- return trackPerformDexOpt(pkg, /*isForPrimaryDex=*/ true,
- () -> mDexOptHelper.performDexOptWithStatus(
- new DexoptOptions(pkg, reason, dexoptFlags)));
+ private int performDexOptPrimary(String pkg, int reason, int dexoptFlags) {
+ DexoptOptions dexoptOptions = new DexoptOptions(pkg, reason, dexoptFlags);
+ return trackPerformDexOpt(pkg, /*isForPrimaryDex=*/true,
+ () -> mDexOptHelper.performDexOptWithStatus(dexoptOptions));
}
@DexOptResult
- private int performDexOptSecondary(String pkg, int reason,
- int dexoptFlags) {
- DexoptOptions dexoptOptions = new DexoptOptions(pkg, reason,
- dexoptFlags | DexoptOptions.DEXOPT_ONLY_SECONDARY_DEX);
- return trackPerformDexOpt(pkg, /*isForPrimaryDex=*/ false,
- () -> mDexOptHelper.performDexOpt(dexoptOptions)
- ? PackageDexOptimizer.DEX_OPT_PERFORMED : PackageDexOptimizer.DEX_OPT_FAILED
- );
+ private int performDexOptSecondary(String pkg, int reason, int dexoptFlags) {
+ DexoptOptions dexoptOptions = new DexoptOptions(
+ pkg, reason, dexoptFlags | DexoptOptions.DEXOPT_ONLY_SECONDARY_DEX);
+ return trackPerformDexOpt(pkg, /*isForPrimaryDex=*/false,
+ ()
+ -> mDexOptHelper.performDexOpt(dexoptOptions)
+ ? PackageDexOptimizer.DEX_OPT_PERFORMED
+ : PackageDexOptimizer.DEX_OPT_FAILED);
}
/**
@@ -805,8 +829,8 @@
* {@link PackageDexOptimizer#DEX_OPT_FAILED}
*/
@DexOptResult
- private int trackPerformDexOpt(String pkg, boolean isForPrimaryDex,
- Supplier<Integer> performDexOptWrapper) {
+ private int trackPerformDexOpt(
+ String pkg, boolean isForPrimaryDex, Supplier<Integer> performDexOptWrapper) {
ArraySet<String> failedPackageNames;
synchronized (mLock) {
failedPackageNames =
@@ -923,6 +947,19 @@
}
}
+ private void writeStatsLog(JobParameters params) {
+ @Status int status;
+ long durationMs;
+ long durationIncludingSleepMs;
+ synchronized (mLock) {
+ status = mLastExecutionStatus;
+ durationMs = mLastExecutionDurationMs;
+ durationIncludingSleepMs = mLastExecutionDurationIncludingSleepMs;
+ }
+
+ mStatsLogger.write(status, params.getStopReason(), durationMs, durationIncludingSleepMs);
+ }
+
/** Injector pattern for testing purpose */
@VisibleForTesting
static final class Injector {
@@ -962,8 +999,8 @@
}
boolean isBackgroundDexOptDisabled() {
- return SystemProperties.getBoolean("pm.dexopt.disable_bg_dexopt" /* key */,
- false /* default */);
+ return SystemProperties.getBoolean(
+ "pm.dexopt.disable_bg_dexopt" /* key */, false /* default */);
}
boolean isBatteryLevelLow() {
@@ -993,8 +1030,8 @@
}
int getCurrentThermalStatus() {
- IThermalService thermalService = IThermalService.Stub
- .asInterface(ServiceManager.getService(Context.THERMAL_SERVICE));
+ IThermalService thermalService = IThermalService.Stub.asInterface(
+ ServiceManager.getService(Context.THERMAL_SERVICE));
try {
return thermalService.getCurrentThermalStatus();
} catch (RemoteException e) {
@@ -1003,8 +1040,8 @@
}
int getDexOptThermalCutoff() {
- return SystemProperties.getInt("dalvik.vm.dexopt.thermal-cutoff",
- THERMAL_CUTOFF_DEFAULT);
+ return SystemProperties.getInt(
+ "dalvik.vm.dexopt.thermal-cutoff", THERMAL_CUTOFF_DEFAULT);
}
Thread createAndStartThread(String name, Runnable target) {
diff --git a/services/core/java/com/android/server/pm/BroadcastHelper.java b/services/core/java/com/android/server/pm/BroadcastHelper.java
index c1b25d7..2aec187 100644
--- a/services/core/java/com/android/server/pm/BroadcastHelper.java
+++ b/services/core/java/com/android/server/pm/BroadcastHelper.java
@@ -152,30 +152,40 @@
}
}
- public void sendResourcesChangedBroadcast(boolean mediaStatus, boolean replacing,
- ArrayList<String> pkgList, int[] uidArr, IIntentReceiver finishedReceiver) {
- sendResourcesChangedBroadcast(mediaStatus, replacing,
- pkgList.toArray(new String[pkgList.size()]), uidArr, finishedReceiver);
- }
+ public void sendResourcesChangedBroadcast(@NonNull Computer snapshot, boolean mediaStatus,
+ boolean replacing, @NonNull String[] pkgNames, @NonNull int[] uids) {
+ if (ArrayUtils.isEmpty(pkgNames) || ArrayUtils.isEmpty(uids)) {
+ return;
+ }
- public void sendResourcesChangedBroadcast(boolean mediaStatus, boolean replacing,
- String[] pkgList, int[] uidArr, IIntentReceiver finishedReceiver) {
- int size = pkgList.length;
- if (size > 0) {
- // Send broadcasts here
- Bundle extras = new Bundle();
- extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, pkgList);
- if (uidArr != null) {
- extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, uidArr);
+ try {
+ final IActivityManager am = ActivityManager.getService();
+ if (am == null) {
+ return;
}
- if (replacing) {
- extras.putBoolean(Intent.EXTRA_REPLACING, replacing);
+
+ final int[] resolvedUserIds = am.getRunningUserIds();
+ for (int userId : resolvedUserIds) {
+ final var lists = getBroadcastParams(snapshot, pkgNames, uids, userId);
+ for (int i = 0; i < lists.size(); i++) {
+ // Send broadcasts here
+ final Bundle extras = new Bundle(3);
+ final BroadcastParams list = lists.get(i);
+ extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST,
+ list.getPackageNames());
+ extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, list.getUids());
+ extras.putBoolean(Intent.EXTRA_REPLACING, replacing);
+ final SparseArray<int[]> allowList = list.getAllowList().size() == 0
+ ? null : list.getAllowList();
+ final String action =
+ mediaStatus ? Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE
+ : Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE;
+ sendPackageBroadcast(action, null /* pkg */, extras, 0 /* flags */,
+ null /* targetPkg */, null /* finishedReceiver */, new int[]{userId},
+ null /* instantUserIds */, allowList, null /* bOptions */);
+ }
}
- String action = mediaStatus ? Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE
- : Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE;
- // TODO: not sure how to handle this one.
- sendPackageBroadcast(action, null, extras, 0, null, finishedReceiver,
- null, null, null, null);
+ } catch (RemoteException ex) {
}
}
@@ -202,7 +212,7 @@
final BroadcastOptions bOptions = getTemporaryAppAllowlistBroadcastOptions(
REASON_LOCKED_BOOT_COMPLETED);
am.broadcastIntentWithFeature(null, null, lockedBcIntent, null, null, 0, null, null,
- requiredPermissions, null, android.app.AppOpsManager.OP_NONE,
+ requiredPermissions, null, null, android.app.AppOpsManager.OP_NONE,
bOptions.toBundle(), false, false, userId);
// Deliver BOOT_COMPLETED only if user is unlocked
@@ -212,7 +222,7 @@
bcIntent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
}
am.broadcastIntentWithFeature(null, null, bcIntent, null, null, 0, null, null,
- requiredPermissions, null, android.app.AppOpsManager.OP_NONE,
+ requiredPermissions, null, null, android.app.AppOpsManager.OP_NONE,
bOptions.toBundle(), false, false, userId);
}
} catch (RemoteException e) {
@@ -268,7 +278,7 @@
};
try {
am.broadcastIntentWithFeature(null, null, intent, null, null, 0, null, null,
- requiredPermissions, null, android.app.AppOpsManager.OP_NONE, null, false,
+ requiredPermissions, null, null, android.app.AppOpsManager.OP_NONE, null, false,
false, UserHandle.USER_ALL);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -306,7 +316,7 @@
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
try {
am.broadcastIntentWithFeature(null, null, intent, null, null,
- 0, null, null, null, null, android.app.AppOpsManager.OP_NONE,
+ 0, null, null, null, null, null, android.app.AppOpsManager.OP_NONE,
null, false, false, userId);
} catch (RemoteException e) {
}
diff --git a/services/core/java/com/android/server/pm/BroadcastParams.java b/services/core/java/com/android/server/pm/BroadcastParams.java
index 7883f48..279aab0 100644
--- a/services/core/java/com/android/server/pm/BroadcastParams.java
+++ b/services/core/java/com/android/server/pm/BroadcastParams.java
@@ -22,8 +22,6 @@
import android.util.IntArray;
import android.util.SparseArray;
-import com.android.internal.util.DataClass;
-
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -32,7 +30,6 @@
* A helper class that contains information about package names and uids that share the same allow
* list for sending broadcasts. Used by various package helpers.
*/
-@DataClass(genConstructor = false, genConstDefs = false)
final class BroadcastParams {
private final @NonNull List<String> mPackageNames;
private final @NonNull IntArray mUids;
@@ -51,46 +48,15 @@
mUids.add(uid);
}
-
-
- // Code below generated by codegen v1.0.23.
- //
- // DO NOT MODIFY!
- // CHECKSTYLE:OFF Generated code
- //
- // To regenerate run:
- // $ codegen $ANDROID_BUILD_TOP/frameworks/base/services/core/java/com/android/server/pm/BroadcastParams.java
- //
- // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
- // Settings > Editor > Code Style > Formatter Control
- //@formatter:off
-
-
- @DataClass.Generated.Member
- public @NonNull List<String> getPackageNames() {
- return mPackageNames;
+ public @NonNull String[] getPackageNames() {
+ return mPackageNames.toArray(new String[0]);
}
- @DataClass.Generated.Member
- public @NonNull IntArray getUids() {
- return mUids;
+ public @NonNull int[] getUids() {
+ return mUids.toArray();
}
- @DataClass.Generated.Member
public @NonNull SparseArray<int[]> getAllowList() {
return mAllowList;
}
-
- @DataClass.Generated(
- time = 1651554793681L,
- codegenVersion = "1.0.23",
- sourceFile = "frameworks/base/services/core/java/com/android/server/pm/BroadcastParams.java",
- inputSignatures = "private final @android.annotation.NonNull java.util.List<java.lang.String> mPackageNames\nprivate final @android.annotation.NonNull android.util.IntArray mUids\nprivate final @android.annotation.NonNull android.util.SparseArray<int[]> mAllowList\npublic void addPackage(java.lang.String,int)\nclass BroadcastParams extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genConstDefs=false)")
- @Deprecated
- private void __metadata() {}
-
-
- //@formatter:on
- // End of generated code
-
}
diff --git a/services/core/java/com/android/server/pm/Computer.java b/services/core/java/com/android/server/pm/Computer.java
index 8e8ca86..3042667 100644
--- a/services/core/java/com/android/server/pm/Computer.java
+++ b/services/core/java/com/android/server/pm/Computer.java
@@ -94,12 +94,13 @@
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
public interface Computer extends PackageDataSnapshot {
+ int getVersion();
+
/**
* Administrative statistics: record that the snapshot has been used. Every call
* to use() increments the usage counter.
*/
- default void use() {
- }
+ Computer use();
/**
* Fetch the snapshot usage counter.
* @return The number of times this snapshot was used.
@@ -227,8 +228,28 @@
int userId);
boolean shouldFilterApplication(@NonNull SharedUserSetting sus, int callingUid,
int userId);
+ /**
+ * Different form {@link #shouldFilterApplication(PackageStateInternal, int, int)}, the function
+ * returns {@code true} if the target package is not found in the device or uninstalled in the
+ * current user. Unless the caller's function needs to handle the package's uninstalled state
+ * by itself, using this function to keep the consistent behavior between conditions of package
+ * uninstalled and visibility not allowed to avoid the side channel leakage of package
+ * existence.
+ * <p>
+ * Package with {@link PackageManager#SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_HIDDEN} is not
+ * treated as an uninstalled package for the carrier apps customization.
+ */
boolean shouldFilterApplicationIncludingUninstalled(@Nullable PackageStateInternal ps,
int callingUid, int userId);
+ /**
+ * Different from {@link #shouldFilterApplication(SharedUserSetting, int, int)}, the function
+ * returns {@code true} if packages with the same shared user are all uninstalled in the current
+ * user.
+ *
+ * @see #shouldFilterApplicationIncludingUninstalled(PackageStateInternal, int, int)
+ */
+ boolean shouldFilterApplicationIncludingUninstalled(@NonNull SharedUserSetting sus,
+ int callingUid, int userId);
int checkUidPermission(String permName, int uid);
int getPackageUidInternal(String packageName, long flags, int userId, int callingUid);
long updateFlagsForApplication(long flags, int userId);
@@ -377,6 +398,8 @@
int checkUidSignatures(int uid1, int uid2);
+ int checkUidSignaturesForAllUsers(int uid1, int uid2);
+
boolean hasSigningCertificate(@NonNull String packageName, @NonNull byte[] certificate,
@PackageManager.CertificateInputType int type);
diff --git a/services/core/java/com/android/server/pm/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java
index 24004bc..c545e7d 100644
--- a/services/core/java/com/android/server/pm/ComputerEngine.java
+++ b/services/core/java/com/android/server/pm/ComputerEngine.java
@@ -367,6 +367,8 @@
return (v1 > v2) ? -1 : ((v1 < v2) ? 1 : 0);
};
+ private final int mVersion;
+
// The administrative use counter.
private int mUsed = 0;
@@ -425,7 +427,8 @@
return mLocalAndroidApplication;
}
- ComputerEngine(PackageManagerService.Snapshot args) {
+ ComputerEngine(PackageManagerService.Snapshot args, int version) {
+ mVersion = version;
mSettings = new Settings(args.settings);
mIsolatedOwners = args.isolatedOwners;
mPackages = args.packages;
@@ -466,11 +469,17 @@
mService = args.service;
}
+ @Override
+ public int getVersion() {
+ return mVersion;
+ }
+
/**
* Record that the snapshot was used.
*/
- public final void use() {
+ public final Computer use() {
mUsed++;
+ return this;
}
/**
@@ -2785,6 +2794,26 @@
}
/**
+ * @see #shouldFilterApplication(PackageStateInternal, int, ComponentName, int, int, boolean)
+ */
+ public final boolean shouldFilterApplicationIncludingUninstalled(
+ @NonNull SharedUserSetting sus, int callingUid, int userId) {
+ if (shouldFilterApplication(sus, callingUid, userId)) {
+ return true;
+ }
+ final ArraySet<PackageStateInternal> packageStates =
+ (ArraySet<PackageStateInternal>) sus.getPackageStates();
+ for (int index = 0; index < packageStates.size(); index++) {
+ final PackageStateInternal ps = packageStates.valueAt(index);
+ if (ps.getUserStateOrDefault(userId).isInstalled() || ps.isHiddenUntilInstalled()) {
+ return false;
+ }
+ }
+ // Filter it, all packages with the same shared uid are uninstalled.
+ return true;
+ }
+
+ /**
* Verification statuses are ordered from the worse to the best, except for
* INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER, which is the worse.
*/
@@ -4244,54 +4273,58 @@
public int checkUidSignatures(int uid1, int uid2) {
final int callingUid = Binder.getCallingUid();
final int callingUserId = UserHandle.getUserId(callingUid);
- // Map to base uids.
- final int appId1 = UserHandle.getAppId(uid1);
- final int appId2 = UserHandle.getAppId(uid2);
- SigningDetails p1SigningDetails;
- SigningDetails p2SigningDetails;
- Object obj = mSettings.getSettingBase(appId1);
- if (obj != null) {
- if (obj instanceof SharedUserSetting) {
- final SharedUserSetting sus = (SharedUserSetting) obj;
- if (shouldFilterApplication(sus, callingUid, callingUserId)) {
- return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
- }
- p1SigningDetails = sus.signatures.mSigningDetails;
- } else if (obj instanceof PackageSetting) {
- final PackageSetting ps = (PackageSetting) obj;
- if (shouldFilterApplication(ps, callingUid, callingUserId)) {
- return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
- }
- p1SigningDetails = ps.getSigningDetails();
- } else {
- return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
- }
- } else {
- return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
- }
- obj = mSettings.getSettingBase(appId2);
- if (obj != null) {
- if (obj instanceof SharedUserSetting) {
- final SharedUserSetting sus = (SharedUserSetting) obj;
- if (shouldFilterApplication(sus, callingUid, callingUserId)) {
- return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
- }
- p2SigningDetails = sus.signatures.mSigningDetails;
- } else if (obj instanceof PackageSetting) {
- final PackageSetting ps = (PackageSetting) obj;
- if (shouldFilterApplication(ps, callingUid, callingUserId)) {
- return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
- }
- p2SigningDetails = ps.getSigningDetails();
- } else {
- return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
- }
- } else {
+ final SigningDetails p1SigningDetails =
+ getSigningDetailsAndFilterAccess(uid1, callingUid, callingUserId);
+ final SigningDetails p2SigningDetails =
+ getSigningDetailsAndFilterAccess(uid2, callingUid, callingUserId);
+ if (p1SigningDetails == null || p2SigningDetails == null) {
return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
}
return checkSignaturesInternal(p1SigningDetails, p2SigningDetails);
}
+ @Override
+ public int checkUidSignaturesForAllUsers(int uid1, int uid2) {
+ final int callingUid = Binder.getCallingUid();
+ final int userId1 = UserHandle.getUserId(uid1);
+ final int userId2 = UserHandle.getUserId(uid2);
+ enforceCrossUserPermission(callingUid, userId1, false /* requireFullPermission */,
+ false /* checkShell */, "checkUidSignaturesForAllUsers");
+ enforceCrossUserPermission(callingUid, userId2, false /* requireFullPermission */,
+ false /* checkShell */, "checkUidSignaturesForAllUsers");
+ final SigningDetails p1SigningDetails =
+ getSigningDetailsAndFilterAccess(uid1, callingUid, userId1);
+ final SigningDetails p2SigningDetails =
+ getSigningDetailsAndFilterAccess(uid2, callingUid, userId2);
+ if (p1SigningDetails == null || p2SigningDetails == null) {
+ return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
+ }
+ return checkSignaturesInternal(p1SigningDetails, p2SigningDetails);
+ }
+
+ private SigningDetails getSigningDetailsAndFilterAccess(int uid, int callingUid, int userId) {
+ // Map to base uids.
+ final int appId = UserHandle.getAppId(uid);
+ final Object obj = mSettings.getSettingBase(appId);
+ if (obj == null) {
+ return null;
+ }
+ if (obj instanceof SharedUserSetting) {
+ final SharedUserSetting sus = (SharedUserSetting) obj;
+ if (shouldFilterApplicationIncludingUninstalled(sus, callingUid, userId)) {
+ return null;
+ }
+ return sus.signatures.mSigningDetails;
+ } else if (obj instanceof PackageSetting) {
+ final PackageSetting ps = (PackageSetting) obj;
+ if (shouldFilterApplicationIncludingUninstalled(ps, callingUid, userId)) {
+ return null;
+ }
+ return ps.getSigningDetails();
+ }
+ return null;
+ }
+
private int checkSignaturesInternal(SigningDetails p1SigningDetails,
SigningDetails p2SigningDetails) {
if (p1SigningDetails == null) {
@@ -4354,27 +4387,9 @@
@PackageManager.CertificateInputType int type) {
final int callingUid = Binder.getCallingUid();
final int callingUserId = UserHandle.getUserId(callingUid);
- // Map to base uids.
- final int appId = UserHandle.getAppId(uid);
- final SigningDetails signingDetails;
- final Object obj = mSettings.getSettingBase(appId);
- if (obj != null) {
- if (obj instanceof SharedUserSetting) {
- final SharedUserSetting sus = (SharedUserSetting) obj;
- if (shouldFilterApplication(sus, callingUid, callingUserId)) {
- return false;
- }
- signingDetails = sus.signatures.mSigningDetails;
- } else if (obj instanceof PackageSetting) {
- final PackageSetting ps = (PackageSetting) obj;
- if (shouldFilterApplication(ps, callingUid, callingUserId)) {
- return false;
- }
- signingDetails = ps.getSigningDetails();
- } else {
- return false;
- }
- } else {
+ final SigningDetails signingDetails =
+ getSigningDetailsAndFilterAccess(uid, callingUid, callingUserId);
+ if (signingDetails == null) {
return false;
}
switch (type) {
@@ -4437,13 +4452,13 @@
final Object obj = mSettings.getSettingBase(appId);
if (obj instanceof SharedUserSetting) {
final SharedUserSetting sus = (SharedUserSetting) obj;
- if (shouldFilterApplication(sus, callingUid, callingUserId)) {
+ if (shouldFilterApplicationIncludingUninstalled(sus, callingUid, callingUserId)) {
return null;
}
return sus.name + ":" + sus.mAppId;
} else if (obj instanceof PackageSetting) {
final PackageSetting ps = (PackageSetting) obj;
- if (shouldFilterApplication(ps, callingUid, callingUserId)) {
+ if (shouldFilterApplicationIncludingUninstalled(ps, callingUid, callingUserId)) {
return null;
}
return ps.getPackageName();
@@ -4472,14 +4487,14 @@
final Object obj = mSettings.getSettingBase(appId);
if (obj instanceof SharedUserSetting) {
final SharedUserSetting sus = (SharedUserSetting) obj;
- if (shouldFilterApplication(sus, callingUid, callingUserId)) {
+ if (shouldFilterApplicationIncludingUninstalled(sus, callingUid, callingUserId)) {
names[i] = null;
} else {
names[i] = "shared:" + sus.name;
}
} else if (obj instanceof PackageSetting) {
final PackageSetting ps = (PackageSetting) obj;
- if (shouldFilterApplication(ps, callingUid, callingUserId)) {
+ if (shouldFilterApplicationIncludingUninstalled(ps, callingUid, callingUserId)) {
names[i] = null;
} else {
names[i] = ps.getPackageName();
@@ -4501,7 +4516,7 @@
return Process.INVALID_UID;
}
final SharedUserSetting suid = mSettings.getSharedUserFromId(sharedUserName);
- if (suid != null && !shouldFilterApplication(suid, callingUid,
+ if (suid != null && !shouldFilterApplicationIncludingUninstalled(suid, callingUid,
UserHandle.getUserId(callingUid))) {
return suid.mAppId;
}
@@ -4522,13 +4537,13 @@
final Object obj = mSettings.getSettingBase(appId);
if (obj instanceof SharedUserSetting) {
final SharedUserSetting sus = (SharedUserSetting) obj;
- if (shouldFilterApplication(sus, callingUid, callingUserId)) {
+ if (shouldFilterApplicationIncludingUninstalled(sus, callingUid, callingUserId)) {
return 0;
}
return sus.getFlags();
} else if (obj instanceof PackageSetting) {
final PackageSetting ps = (PackageSetting) obj;
- if (shouldFilterApplication(ps, callingUid, callingUserId)) {
+ if (shouldFilterApplicationIncludingUninstalled(ps, callingUid, callingUserId)) {
return 0;
}
return ps.getFlags();
@@ -4550,13 +4565,13 @@
final Object obj = mSettings.getSettingBase(appId);
if (obj instanceof SharedUserSetting) {
final SharedUserSetting sus = (SharedUserSetting) obj;
- if (shouldFilterApplication(sus, callingUid, callingUserId)) {
+ if (shouldFilterApplicationIncludingUninstalled(sus, callingUid, callingUserId)) {
return 0;
}
return sus.getPrivateFlags();
} else if (obj instanceof PackageSetting) {
final PackageSetting ps = (PackageSetting) obj;
- if (shouldFilterApplication(ps, callingUid, callingUserId)) {
+ if (shouldFilterApplicationIncludingUninstalled(ps, callingUid, callingUserId)) {
return 0;
}
return ps.getPrivateFlags();
diff --git a/services/core/java/com/android/server/pm/ComputerLocked.java b/services/core/java/com/android/server/pm/ComputerLocked.java
index af196d5..37070db 100644
--- a/services/core/java/com/android/server/pm/ComputerLocked.java
+++ b/services/core/java/com/android/server/pm/ComputerLocked.java
@@ -30,7 +30,7 @@
public final class ComputerLocked extends ComputerEngine {
ComputerLocked(PackageManagerService.Snapshot args) {
- super(args);
+ super(args, -1);
}
protected ComponentName resolveComponentName() {
diff --git a/services/core/java/com/android/server/pm/DeletePackageHelper.java b/services/core/java/com/android/server/pm/DeletePackageHelper.java
index 5e397bd..b0b9e61c 100644
--- a/services/core/java/com/android/server/pm/DeletePackageHelper.java
+++ b/services/core/java/com/android/server/pm/DeletePackageHelper.java
@@ -165,9 +165,10 @@
if (PackageManagerServiceUtils.isSystemApp(uninstalledPs)) {
UserInfo userInfo = mUserManagerInternal.getUserInfo(userId);
- if (userInfo == null || !userInfo.isAdmin()) {
+ if (userInfo == null || (!userInfo.isAdmin() && !mUserManagerInternal.getUserInfo(
+ mUserManagerInternal.getProfileParentId(userId)).isAdmin())) {
Slog.w(TAG, "Not removing package " + packageName
- + " as only admin user may downgrade system apps");
+ + " as only admin user (or their profile) may downgrade system apps");
EventLog.writeEvent(0x534e4554, "170646036", -1, packageName);
return PackageManager.DELETE_FAILED_USER_RESTRICTED;
}
diff --git a/services/core/java/com/android/server/pm/DexOptHelper.java b/services/core/java/com/android/server/pm/DexOptHelper.java
index f1296e0..29b122d 100644
--- a/services/core/java/com/android/server/pm/DexOptHelper.java
+++ b/services/core/java/com/android/server/pm/DexOptHelper.java
@@ -26,6 +26,7 @@
import static com.android.server.pm.PackageManagerService.REASON_FIRST_BOOT;
import static com.android.server.pm.PackageManagerService.STUB_SUFFIX;
import static com.android.server.pm.PackageManagerService.TAG;
+import static com.android.server.pm.PackageManagerServiceCompilerMapping.getCompilerFilterForReason;
import static com.android.server.pm.PackageManagerServiceCompilerMapping.getDefaultCompilerFilter;
import static com.android.server.pm.PackageManagerServiceUtils.REMOVE_IF_NULL_PKG;
@@ -58,6 +59,8 @@
import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
import com.android.server.pm.pkg.PackageStateInternal;
+import dalvik.system.DexFile;
+
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
@@ -267,31 +270,42 @@
return;
}
- boolean useProfileForDexopt = false;
- File profileFile = new File(getPrebuildProfilePath(pkg));
- // Copy the profile to the reference profile path if it exists. Installd can only use a
- // profile at the reference profile path for dexopt.
- if (profileFile.exists()) {
- try {
- synchronized (mPm.mInstallLock) {
- if (mPm.mInstaller.copySystemProfile(profileFile.getAbsolutePath(),
- pkg.getUid(), pkg.getPackageName(),
- ArtManager.getProfileName(null))) {
- useProfileForDexopt = true;
- } else {
- Log.e(TAG, "Failed to copy profile " + profileFile.getAbsolutePath());
- }
- }
- } catch (Exception e) {
- Log.e(TAG, "Failed to copy profile " + profileFile.getAbsolutePath(), e);
- }
- }
-
// It could also be after mainline update, but we're not introducing a new reason just for
// this special case.
+ int reason = REASON_BOOT_AFTER_OTA;
+
+ String defaultCompilerFilter = getCompilerFilterForReason(reason);
+ String targetCompilerFilter =
+ SystemProperties.get("dalvik.vm.systemuicompilerfilter", defaultCompilerFilter);
+ String compilerFilter;
+
+ if (DexFile.isProfileGuidedCompilerFilter(targetCompilerFilter)) {
+ compilerFilter = defaultCompilerFilter;
+ File profileFile = new File(getPrebuildProfilePath(pkg));
+
+ // Copy the profile to the reference profile path if it exists. Installd can only use a
+ // profile at the reference profile path for dexopt.
+ if (profileFile.exists()) {
+ try {
+ synchronized (mPm.mInstallLock) {
+ if (mPm.mInstaller.copySystemProfile(profileFile.getAbsolutePath(),
+ pkg.getUid(), pkg.getPackageName(),
+ ArtManager.getProfileName(null))) {
+ compilerFilter = targetCompilerFilter;
+ } else {
+ Log.e(TAG, "Failed to copy profile " + profileFile.getAbsolutePath());
+ }
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Failed to copy profile " + profileFile.getAbsolutePath(), e);
+ }
+ }
+ } else {
+ compilerFilter = targetCompilerFilter;
+ }
+
performDexOptTraced(new DexoptOptions(pkg.getPackageName(), REASON_BOOT_AFTER_OTA,
- useProfileForDexopt ? "speed-profile" : "speed", null /* splitName */,
- 0 /* dexoptFlags */));
+ compilerFilter, null /* splitName */, 0 /* dexoptFlags */));
}
@RequiresPermission(Manifest.permission.READ_DEVICE_CONFIG)
diff --git a/services/core/java/com/android/server/pm/DistractingPackageHelper.java b/services/core/java/com/android/server/pm/DistractingPackageHelper.java
index 90dff16..b9fb3bd 100644
--- a/services/core/java/com/android/server/pm/DistractingPackageHelper.java
+++ b/services/core/java/com/android/server/pm/DistractingPackageHelper.java
@@ -190,9 +190,8 @@
for (int i = 0; i < lists.size(); i++) {
final Bundle extras = new Bundle(3);
final BroadcastParams list = lists.get(i);
- extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST,
- list.getPackageNames().toArray(new String[0]));
- extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, list.getUids().toArray());
+ extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, list.getPackageNames());
+ extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, list.getUids());
extras.putInt(Intent.EXTRA_DISTRACTION_RESTRICTIONS, distractionFlags);
final SparseArray<int[]> allowList = list.getAllowList().size() == 0
? null : list.getAllowList();
diff --git a/services/core/java/com/android/server/pm/FileInstallArgs.java b/services/core/java/com/android/server/pm/FileInstallArgs.java
index 85c3cc9..e3ceccd 100644
--- a/services/core/java/com/android/server/pm/FileInstallArgs.java
+++ b/services/core/java/com/android/server/pm/FileInstallArgs.java
@@ -172,9 +172,22 @@
return false;
}
- if (!onIncremental && !SELinux.restoreconRecursive(afterCodeFile)) {
- Slog.w(TAG, "Failed to restorecon");
- return false;
+ if (onIncremental) {
+ Slog.i(TAG, PackageManagerServiceUtils.SELINUX_BUG
+ + ": Skipping restorecon for Incremental install of " + beforeCodeFile);
+ } else {
+ try {
+ if (!SELinux.restoreconRecursive(afterCodeFile)) {
+ Slog.w(TAG, "Failed to restorecon");
+ return false;
+ }
+ PackageManagerServiceUtils.verifySelinuxLabels(afterCodeFile.getAbsolutePath());
+ } catch (Exception e) {
+ Slog.e(TAG,
+ PackageManagerServiceUtils.SELINUX_BUG + ": Exception from restorecon on "
+ + beforeCodeFile, e);
+ throw e;
+ }
}
// Reflect the rename internally
diff --git a/services/core/java/com/android/server/pm/InitAppsHelper.java b/services/core/java/com/android/server/pm/InitAppsHelper.java
index c1e3c75..4019c15 100644
--- a/services/core/java/com/android/server/pm/InitAppsHelper.java
+++ b/services/core/java/com/android/server/pm/InitAppsHelper.java
@@ -25,6 +25,7 @@
import static com.android.server.pm.PackageManagerService.SCAN_AS_PRIVILEGED;
import static com.android.server.pm.PackageManagerService.SCAN_AS_SYSTEM;
import static com.android.server.pm.PackageManagerService.SCAN_BOOTING;
+import static com.android.server.pm.PackageManagerService.SCAN_DROP_CACHE;
import static com.android.server.pm.PackageManagerService.SCAN_FIRST_BOOT_OR_UPGRADE;
import static com.android.server.pm.PackageManagerService.SCAN_INITIAL;
import static com.android.server.pm.PackageManagerService.SCAN_NO_DEX;
@@ -174,6 +175,9 @@
if (apexInfo.isFactory) {
additionalScanFlag |= SCAN_AS_FACTORY;
}
+ if (apexInfo.activeApexChanged) {
+ additionalScanFlag |= SCAN_DROP_CACHE;
+ }
return new ScanPartition(apexInfo.apexDirectory, sp, additionalScanFlag);
}
}
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index c365986..c6e421b 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -74,6 +74,7 @@
import static com.android.server.pm.PackageManagerService.SCAN_AS_VIRTUAL_PRELOAD;
import static com.android.server.pm.PackageManagerService.SCAN_BOOTING;
import static com.android.server.pm.PackageManagerService.SCAN_DONT_KILL_APP;
+import static com.android.server.pm.PackageManagerService.SCAN_DROP_CACHE;
import static com.android.server.pm.PackageManagerService.SCAN_FIRST_BOOT_OR_UPGRADE;
import static com.android.server.pm.PackageManagerService.SCAN_IGNORE_FROZEN;
import static com.android.server.pm.PackageManagerService.SCAN_INITIAL;
@@ -154,6 +155,7 @@
import com.android.server.pm.dex.DexManager;
import com.android.server.pm.dex.DexoptOptions;
import com.android.server.pm.dex.ViewCompiler;
+import com.android.server.pm.parsing.PackageCacher;
import com.android.server.pm.parsing.PackageParser2;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
@@ -656,6 +658,10 @@
Log.v(TAG, "restoreAndPostInstall userId=" + userId + " package=" + res.mPkg);
}
+ if (res.mPkg != null) {
+ PackageManagerServiceUtils.verifySelinuxLabels(res.mPkg.getPath());
+ }
+
// A restore should be requested at this point if (a) the install
// succeeded, (b) the operation is not an update.
final boolean update = res.mRemovedInfo != null
@@ -2629,11 +2635,10 @@
Slog.i(TAG, "upgrading pkg " + res.mRemovedInfo.mRemovedPackage
+ " is ASEC-hosted -> UNAVAILABLE");
}
- final int[] uidArray = new int[]{res.mRemovedInfo.mUid};
- final ArrayList<String> pkgList = new ArrayList<>(1);
- pkgList.add(res.mRemovedInfo.mRemovedPackage);
- mBroadcastHelper.sendResourcesChangedBroadcast(
- false, true, pkgList, uidArray, null);
+ final String[] pkgNames = new String[]{res.mRemovedInfo.mRemovedPackage};
+ final int[] uids = new int[]{res.mRemovedInfo.mUid};
+ mBroadcastHelper.sendResourcesChangedBroadcast(mPm.snapshotComputer(),
+ false /* mediaStatus */, true /* replacing */, pkgNames, uids);
}
res.mRemovedInfo.sendPackageRemovedBroadcasts(killApp, false /*removedBySystem*/);
}
@@ -2805,11 +2810,10 @@
if (DEBUG_INSTALL) {
Slog.i(TAG, "upgrading pkg " + res.mPkg + " is external");
}
- final int[] uidArray = new int[]{res.mPkg.getUid()};
- ArrayList<String> pkgList = new ArrayList<>(1);
- pkgList.add(packageName);
- mBroadcastHelper.sendResourcesChangedBroadcast(
- true, true, pkgList, uidArray, null);
+ final String[] pkgNames = new String[]{packageName};
+ final int[] uids = new int[]{res.mPkg.getUid()};
+ mBroadcastHelper.sendResourcesChangedBroadcast(mPm.snapshotComputer(),
+ true /* mediaStatus */, true /* replacing */, pkgNames, uids);
}
} else if (!ArrayUtils.isEmpty(res.mLibraryConsumers)) { // if static shared lib
// No need to kill consumers if it's installation of new version static shared lib.
@@ -3457,6 +3461,11 @@
// Ignore entries which are not packages
continue;
}
+ if ((scanFlags & SCAN_DROP_CACHE) != 0) {
+ final PackageCacher cacher = new PackageCacher(mPm.getCacheDir());
+ Log.w(TAG, "Dropping cache of " + file.getAbsolutePath());
+ cacher.cleanCachedResult(file);
+ }
parallelPackageParser.submit(file, parseFlags);
fileCount++;
}
@@ -3609,6 +3618,7 @@
@ParsingPackageUtils.ParseFlags int parseFlags,
@PackageManagerService.ScanFlags int scanFlags,
@Nullable UserHandle user) throws PackageManagerException {
+ PackageManagerServiceUtils.verifySelinuxLabels(parsedPackage.getPath());
final Pair<ScanResult, Boolean> scanResultPair = scanSystemPackageLI(
parsedPackage, parseFlags, scanFlags, user);
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index 32f0f10..a078b5d 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -44,6 +44,8 @@
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
public class Installer extends SystemService {
private static final String TAG = "Installer";
@@ -118,9 +120,13 @@
public static final int FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES =
IInstalld.FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES;
+ private static final long CONNECT_RETRY_DELAY_MS = DateUtils.SECOND_IN_MILLIS;
+ private static final long CONNECT_WAIT_MS = 10 * DateUtils.SECOND_IN_MILLIS;
+
private final boolean mIsolated;
private volatile boolean mDeferSetFirstBoot;
- private volatile IInstalld mInstalld;
+ private volatile IInstalld mInstalld = null;
+ private volatile CountDownLatch mInstalldLatch = new CountDownLatch(1);
private volatile Object mWarnIfHeld;
public Installer(Context context) {
@@ -149,6 +155,7 @@
public void onStart() {
if (mIsolated) {
mInstalld = null;
+ mInstalldLatch.countDown();
} else {
connect();
}
@@ -160,6 +167,7 @@
try {
binder.linkToDeath(() -> {
Slog.w(TAG, "installd died; reconnecting");
+ mInstalldLatch = new CountDownLatch(1);
connect();
}, 0);
} catch (RemoteException e) {
@@ -168,7 +176,9 @@
}
if (binder != null) {
- mInstalld = IInstalld.Stub.asInterface(binder);
+ IInstalld installd = IInstalld.Stub.asInterface(binder);
+ mInstalld = installd;
+ mInstalldLatch.countDown();
try {
invalidateMounts();
executeDeferredActions();
@@ -176,7 +186,7 @@
}
} else {
Slog.w(TAG, "installd not found; trying again");
- BackgroundThread.getHandler().postDelayed(this::connect, DateUtils.SECOND_IN_MILLIS);
+ BackgroundThread.getHandler().postDelayed(this::connect, CONNECT_RETRY_DELAY_MS);
}
}
@@ -194,7 +204,7 @@
*
* @return if the remote call should continue.
*/
- private boolean checkBeforeRemote() {
+ private boolean checkBeforeRemote() throws InstallerException {
if (mWarnIfHeld != null && Thread.holdsLock(mWarnIfHeld)) {
Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName() + " is holding 0x"
+ Integer.toHexString(System.identityHashCode(mWarnIfHeld)), new Throwable());
@@ -202,9 +212,17 @@
if (mIsolated) {
Slog.i(TAG, "Ignoring request because this installer is isolated");
return false;
- } else {
- return true;
}
+
+ try {
+ if (!mInstalldLatch.await(CONNECT_WAIT_MS, TimeUnit.MILLISECONDS)) {
+ throw new InstallerException("time out waiting for the installer to be ready");
+ }
+ } catch (InterruptedException e) {
+ // Do nothing.
+ }
+
+ return true;
}
// We explicitly do NOT set previousAppId because the default value should always be 0.
diff --git a/services/core/java/com/android/server/pm/IntentResolverInterceptor.java b/services/core/java/com/android/server/pm/IntentResolverInterceptor.java
deleted file mode 100644
index f5eee5a..0000000
--- a/services/core/java/com/android/server/pm/IntentResolverInterceptor.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.pm;
-
-import static com.android.server.wm.ActivityInterceptorCallback.INTENT_RESOLVER_ORDERED_ID;
-
-import android.Manifest;
-import android.annotation.Nullable;
-import android.annotation.RequiresPermission;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.res.Resources;
-import android.provider.DeviceConfig;
-import android.util.Slog;
-
-import com.android.internal.R;
-import com.android.internal.app.ChooserActivity;
-import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
-import com.android.server.LocalServices;
-import com.android.server.wm.ActivityInterceptorCallback;
-import com.android.server.wm.ActivityInterceptorCallback.ActivityInterceptorInfo;
-import com.android.server.wm.ActivityTaskManagerInternal;
-
-/**
- * Redirects Activity starts for the system bundled {@link ChooserActivity} to an external
- * Sharesheet implementation by modifying the target component when appropriate.
- * <p>
- * Note: config_chooserActivity (Used also by ActivityTaskSupervisor) is already updated to point
- * to the new instance. This value is read and used for the new target component.
- */
-public final class IntentResolverInterceptor {
- private static final String TAG = "IntentResolverIntercept";
- private final Context mContext;
- private final ComponentName mFrameworkChooserComponent;
- private final ComponentName mUnbundledChooserComponent;
- private boolean mUseUnbundledSharesheet;
-
- private final ActivityInterceptorCallback mActivityInterceptorCallback =
- new ActivityInterceptorCallback() {
- @Nullable
- @Override
- public ActivityInterceptResult intercept(ActivityInterceptorInfo info) {
- if (mUseUnbundledSharesheet && isSystemChooserActivity(info)) {
- Slog.d(TAG, "Redirecting to UNBUNDLED Sharesheet");
- info.intent.setComponent(mUnbundledChooserComponent);
- return new ActivityInterceptResult(info.intent, info.checkedOptions);
- }
- return null;
- }
- };
-
- public IntentResolverInterceptor(Context context) {
- mContext = context;
- mFrameworkChooserComponent = new ComponentName(mContext, ChooserActivity.class);
- mUnbundledChooserComponent = ComponentName.unflattenFromString(
- Resources.getSystem().getString(R.string.config_chooserActivity));
- }
-
- /**
- * Start listening for intents and USE_UNBUNDLED_SHARESHEET property changes.
- */
- @RequiresPermission(Manifest.permission.READ_DEVICE_CONFIG)
- public void registerListeners() {
- LocalServices.getService(ActivityTaskManagerInternal.class)
- .registerActivityStartInterceptor(INTENT_RESOLVER_ORDERED_ID,
- mActivityInterceptorCallback);
-
- DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI,
- mContext.getMainExecutor(), properties -> updateUseUnbundledSharesheet());
- updateUseUnbundledSharesheet();
- }
-
- @RequiresPermission(Manifest.permission.READ_DEVICE_CONFIG)
- private void updateUseUnbundledSharesheet() {
- mUseUnbundledSharesheet = DeviceConfig.getBoolean(
- DeviceConfig.NAMESPACE_SYSTEMUI,
- SystemUiDeviceConfigFlags.USE_UNBUNDLED_SHARESHEET,
- false);
- if (mUseUnbundledSharesheet) {
- Slog.d(TAG, "using UNBUNDLED Sharesheet");
- } else {
- Slog.d(TAG, "using FRAMEWORK Sharesheet");
- }
- }
-
- private boolean isSystemChooserActivity(ActivityInterceptorInfo info) {
- return mFrameworkChooserComponent.getPackageName().equals(info.aInfo.packageName)
- && mFrameworkChooserComponent.getClassName().equals(info.aInfo.name);
- }
-}
diff --git a/services/core/java/com/android/server/pm/PackageManagerInternalBase.java b/services/core/java/com/android/server/pm/PackageManagerInternalBase.java
index 4a3b79e..b594866 100644
--- a/services/core/java/com/android/server/pm/PackageManagerInternalBase.java
+++ b/services/core/java/com/android/server/pm/PackageManagerInternalBase.java
@@ -315,9 +315,9 @@
@Deprecated
public final List<ResolveInfo> queryIntentReceivers(Intent intent,
String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags,
- int filterCallingUid, int userId) {
- return getResolveIntentHelper().queryIntentReceiversInternal(
- snapshot(), intent, resolvedType, flags, userId, filterCallingUid);
+ int filterCallingUid, int userId, boolean forSend) {
+ return getResolveIntentHelper().queryIntentReceiversInternal(snapshot(), intent,
+ resolvedType, flags, userId, filterCallingUid, forSend);
}
@Override
@@ -352,10 +352,9 @@
@Override
@Deprecated
- public final void setDeviceOwnerProtectedPackages(
- String deviceOwnerPackageName, List<String> packageNames) {
- getProtectedPackages().setDeviceOwnerProtectedPackages(
- deviceOwnerPackageName, packageNames);
+ public final void setOwnerProtectedPackages(
+ @UserIdInt int userId, @NonNull List<String> packageNames) {
+ getProtectedPackages().setOwnerProtectedPackages(userId, packageNames);
}
@Override
@@ -721,6 +720,11 @@
return snapshot().isUidPrivileged(uid);
}
+ @Override
+ public int checkUidSignaturesForAllUsers(int uid1, int uid2) {
+ return snapshot().checkUidSignaturesForAllUsers(uid1, uid2);
+ }
+
@NonNull
@Override
@Deprecated
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 5dff5e7..88ee4c7 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -269,8 +269,8 @@
import java.util.concurrent.Executor;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
/**
@@ -374,8 +374,9 @@
static final int SCAN_AS_SYSTEM_EXT = 1 << 21;
static final int SCAN_AS_ODM = 1 << 22;
static final int SCAN_AS_APK_IN_APEX = 1 << 23;
- static final int SCAN_AS_FACTORY = 1 << 24;
- static final int SCAN_AS_APEX = 1 << 25;
+ static final int SCAN_DROP_CACHE = 1 << 24;
+ static final int SCAN_AS_FACTORY = 1 << 25;
+ static final int SCAN_AS_APEX = 1 << 26;
@IntDef(flag = true, prefix = { "SCAN_" }, value = {
SCAN_NO_DEX,
@@ -935,7 +936,6 @@
private final DexOptHelper mDexOptHelper;
private final SuspendPackageHelper mSuspendPackageHelper;
private final DistractingPackageHelper mDistractingPackageHelper;
- private final IntentResolverInterceptor mIntentResolverInterceptor;
private final StorageEventHelper mStorageEventHelper;
/**
@@ -1034,22 +1034,15 @@
// times during the PackageManagerService constructor but it should not be modified thereafter.
private ComputerLocked mLiveComputer;
- // A lock-free cache for frequently called functions.
- private volatile Computer mSnapshotComputer;
+ private static final AtomicReference<Computer> sSnapshot = new AtomicReference<>();
- // If true, the snapshot is invalid (stale). The attribute is static since it may be
- // set from outside classes. The attribute may be set to true anywhere, although it
- // should only be set true while holding mLock. However, the attribute id guaranteed
- // to be set false only while mLock and mSnapshotLock are both held.
- private static final AtomicBoolean sSnapshotInvalid = new AtomicBoolean(true);
-
- static final ThreadLocal<ThreadComputer> sThreadComputer =
- ThreadLocal.withInitial(ThreadComputer::new);
+ // If this differs from Computer#getVersion, the snapshot is invalid (stale).
+ private static final AtomicInteger sSnapshotPendingVersion = new AtomicInteger(1);
/**
- * This lock is used to make reads from {@link #sSnapshotInvalid} and
- * {@link #mSnapshotComputer} atomic inside {@code snapshotComputer()}. This lock is
- * not meant to be used outside that method. This lock must be taken before
+ * This lock is used to make reads from {@link #sSnapshotPendingVersion} and
+ * {@link #sSnapshot} atomic inside {@code snapshotComputer()} when the versions mismatch.
+ * This lock is not meant to be used outside that method. This lock must be taken before
* {@link #mLock} is taken.
*/
private final Object mSnapshotLock = new Object();
@@ -1073,48 +1066,53 @@
// yet invalidated the snapshot. Always give the thread the live computer.
return mLiveComputer;
}
- synchronized (mSnapshotLock) {
- // This synchronization block serializes access to the snapshot computer and
- // to the code that samples mSnapshotInvalid.
- Computer c = mSnapshotComputer;
- if (sSnapshotInvalid.getAndSet(false) || (c == null)) {
- // The snapshot is invalid if it is marked as invalid or if it is null. If it
- // is null, then it is currently being rebuilt by rebuildSnapshot().
- synchronized (mLock) {
- // Rebuild the snapshot if it is invalid. Note that the snapshot might be
- // invalidated as it is rebuilt. However, the snapshot is still
- // self-consistent (the lock is being held) and is current as of the time
- // this function is entered.
- rebuildSnapshot();
- // Guaranteed to be non-null. mSnapshotComputer is only be set to null
- // temporarily in rebuildSnapshot(), which is guarded by mLock(). Since
- // the mLock is held in this block and since rebuildSnapshot() is
- // complete, the attribute can not now be null.
- c = mSnapshotComputer;
- }
+ var oldSnapshot = sSnapshot.get();
+ var pendingVersion = sSnapshotPendingVersion.get();
+
+ if (oldSnapshot != null && oldSnapshot.getVersion() == pendingVersion) {
+ return oldSnapshot.use();
+ }
+
+ synchronized (mSnapshotLock) {
+ // Re-capture pending version in case a new invalidation occurred since last check
+ var rebuildSnapshot = sSnapshot.get();
+ var rebuildVersion = sSnapshotPendingVersion.get();
+
+ // Check the versions again while the lock is held, in case the rebuild time caused
+ // multiple threads to wait on the snapshot lock. When the first thread finishes
+ // a rebuild, the snapshot is now valid and the other waiting threads can use it
+ // without kicking off their own rebuilds.
+ if (rebuildSnapshot != null && rebuildSnapshot.getVersion() == rebuildVersion) {
+ return rebuildSnapshot.use();
}
- c.use();
- return c;
+
+ synchronized (mLock) {
+ // Fetch version one last time to ensure that the rebuilt snapshot matches
+ // the latest invalidation, which could have come in between entering the
+ // SnapshotLock and mLock sync blocks.
+ rebuildVersion = sSnapshotPendingVersion.get();
+
+ // Build the snapshot for this version
+ var newSnapshot = rebuildSnapshot(rebuildSnapshot, rebuildVersion);
+ sSnapshot.set(newSnapshot);
+ return newSnapshot.use();
+ }
}
}
- /**
- * Rebuild the cached computer. mSnapshotComputer is temporarily set to null to block other
- * threads from using the invalid computer until it is rebuilt.
- */
@GuardedBy({ "mLock", "mSnapshotLock"})
- private void rebuildSnapshot() {
- final long now = SystemClock.currentTimeMicro();
- final int hits = mSnapshotComputer == null ? -1 : mSnapshotComputer.getUsed();
- mSnapshotComputer = null;
- final Snapshot args = new Snapshot(Snapshot.SNAPPED);
- mSnapshotComputer = new ComputerEngine(args);
- final long done = SystemClock.currentTimeMicro();
+ private Computer rebuildSnapshot(@Nullable Computer oldSnapshot, int newVersion) {
+ var now = SystemClock.currentTimeMicro();
+ var hits = oldSnapshot == null ? -1 : oldSnapshot.getUsed();
+ var args = new Snapshot(Snapshot.SNAPPED);
+ var newSnapshot = new ComputerEngine(args, newVersion);
+ var done = SystemClock.currentTimeMicro();
if (mSnapshotStatistics != null) {
mSnapshotStatistics.rebuild(now, done, hits);
}
+ return newSnapshot;
}
/**
@@ -1134,7 +1132,7 @@
if (TRACE_SNAPSHOTS) {
Log.i(TAG, "snapshot: onChange(" + what + ")");
}
- sSnapshotInvalid.set(true);
+ sSnapshotPendingVersion.incrementAndGet();
}
/**
@@ -1659,7 +1657,6 @@
mRequiredSdkSandboxPackage = testParams.requiredSdkSandboxPackage;
mLiveComputer = createLiveComputer();
- mSnapshotComputer = null;
mSnapshotStatistics = null;
mPackages.putAll(testParams.packages);
@@ -1685,7 +1682,6 @@
mSharedLibraries.setDeletePackageHelper(mDeletePackageHelper);
- mIntentResolverInterceptor = null;
mStorageEventHelper = testParams.storageEventHelper;
registerObservers(false);
@@ -1849,9 +1845,8 @@
// cached computer is the same as the live computer until the end of the
// constructor, at which time the invalidation method updates it.
mSnapshotStatistics = new SnapshotStatistics();
- sSnapshotInvalid.set(true);
+ sSnapshotPendingVersion.incrementAndGet();
mLiveComputer = createLiveComputer();
- mSnapshotComputer = null;
registerObservers(true);
}
@@ -2236,8 +2231,6 @@
mServiceStartWithDelay = SystemClock.uptimeMillis() + (60 * 1000L);
- mIntentResolverInterceptor = new IntentResolverInterceptor(mContext);
-
Slog.i(TAG, "Fix for b/169414761 is applied");
}
@@ -4104,11 +4097,6 @@
// Prune unused static shared libraries which have been cached a period of time
schedulePruneUnusedStaticSharedLibraries(false /* delay */);
-
- // TODO(b/222706900): Remove this intent interceptor before T launch
- if (mIntentResolverInterceptor != null) {
- mIntentResolverInterceptor.registerListeners();
- }
}
//TODO: b/111402650
@@ -4450,8 +4438,8 @@
@Override
public void clearApplicationProfileData(String packageName) {
- PackageManagerServiceUtils.enforceSystemOrRoot(
- "Only the system can clear all profile data");
+ PackageManagerServiceUtils.enforceSystemOrRootOrShell(
+ "Only the system or shell can clear all profile data");
final Computer snapshot = snapshotComputer();
final AndroidPackage pkg = snapshot.getPackage(packageName);
@@ -5353,10 +5341,8 @@
@Override
public void setApplicationCategoryHint(String packageName, int categoryHint,
String callerPackageName) {
- final PackageStateMutator.InitialState initialState = recordInitialState();
-
- final FunctionalUtils.ThrowingFunction<Computer, PackageStateMutator.Result>
- implementation = computer -> {
+ final FunctionalUtils.ThrowingBiFunction<PackageStateMutator.InitialState, Computer,
+ PackageStateMutator.Result> implementation = (initialState, computer) -> {
if (computer.getInstantAppPackageName(Binder.getCallingUid()) != null) {
throw new SecurityException(
"Instant applications don't have access to this method");
@@ -5384,12 +5370,13 @@
}
};
- PackageStateMutator.Result result = implementation.apply(snapshotComputer());
+ PackageStateMutator.Result result =
+ implementation.apply(recordInitialState(), snapshotComputer());
if (result != null && result.isStateChanged() && !result.isSpecificPackageNull()) {
// TODO: Specific return value of what state changed?
// The installer on record might have changed, retry with lock
synchronized (mPackageStateWriteLock) {
- result = implementation.apply(snapshotComputer());
+ result = implementation.apply(recordInitialState(), snapshotComputer());
}
}
@@ -7155,9 +7142,19 @@
public PackageStateMutator.Result commitPackageStateMutation(
@Nullable PackageStateMutator.InitialState initialState, @NonNull String packageName,
@NonNull Consumer<PackageStateWrite> consumer) {
+ PackageStateMutator.Result result = null;
+ if (Thread.holdsLock(mPackageStateWriteLock)) {
+ // If the thread is already holding the lock, this is likely a retry based on a prior
+ // failure, and re-calculating whether a state change occurred can be skipped.
+ result = PackageStateMutator.Result.SUCCESS;
+ }
synchronized (mPackageStateWriteLock) {
- final PackageStateMutator.Result result = mPackageStateMutator.generateResult(
- initialState, mChangedPackagesTracker.getSequenceNumber());
+ if (result == null) {
+ // If the thread wasn't previously holding, this is a first-try commit and so a
+ // state change may have happened.
+ result = mPackageStateMutator.generateResult(
+ initialState, mChangedPackagesTracker.getSequenceNumber());
+ }
if (result != PackageStateMutator.Result.SUCCESS) {
return result;
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index 4d11b13..703be16 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -19,6 +19,7 @@
import static android.content.pm.PackageManager.INSTALL_FAILED_SHARED_USER_INCOMPATIBLE;
import static android.content.pm.PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE;
import static android.content.pm.PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE;
+import static android.content.pm.SigningDetails.CertCapabilities.SHARED_USER_ID;
import static android.system.OsConstants.O_CREAT;
import static android.system.OsConstants.O_RDWR;
@@ -60,6 +61,7 @@
import android.os.Environment;
import android.os.FileUtils;
import android.os.Process;
+import android.os.SELinux;
import android.os.SystemProperties;
import android.os.incremental.IncrementalManager;
import android.os.incremental.IncrementalStorage;
@@ -564,13 +566,8 @@
// the older ones. We check to see if either the new package is signed by an older cert
// with which the current sharedUser is ok, or if it is signed by a newer one, and is ok
// with being sharedUser with the existing signing cert.
- boolean match =
- parsedSignatures.checkCapability(
- sharedUserSetting.getSigningDetails(),
- SigningDetails.CertCapabilities.SHARED_USER_ID)
- || sharedUserSetting.getSigningDetails().checkCapability(
- parsedSignatures,
- SigningDetails.CertCapabilities.SHARED_USER_ID);
+ boolean match = canJoinSharedUserId(parsedSignatures,
+ sharedUserSetting.getSigningDetails());
// Special case: if the sharedUserId capability check failed it could be due to this
// being the only package in the sharedUserId so far and the lineage being updated to
// deny the sharedUserId capability of the previous key in the lineage.
@@ -645,6 +642,28 @@
}
/**
+ * Returns whether the package with {@code packageSigningDetails} can join the sharedUserId
+ * with {@code sharedUserSigningDetails}.
+ * <p>
+ * A sharedUserId maintains a shared {@link SigningDetails} containing the full lineage and
+ * capabilities for each package in the sharedUserId. A package can join the sharedUserId if
+ * its current signer is the same as the shared signer, or if the current signer of either
+ * is in the signing lineage of the other with the {@link
+ * SigningDetails.CertCapabilities#SHARED_USER_ID} capability granted to that previous signer
+ * in the lineage.
+ *
+ * @param packageSigningDetails the {@code SigningDetails} of the package seeking to join the
+ * sharedUserId
+ * @param sharedUserSigningDetails the {@code SigningDetails} of the sharedUserId
+ * @return true if the package seeking to join the sharedUserId meets the requirements
+ */
+ public static boolean canJoinSharedUserId(@NonNull SigningDetails packageSigningDetails,
+ @NonNull SigningDetails sharedUserSigningDetails) {
+ return packageSigningDetails.checkCapability(sharedUserSigningDetails, SHARED_USER_ID)
+ || sharedUserSigningDetails.checkCapability(packageSigningDetails, SHARED_USER_ID);
+ }
+
+ /**
* Extract native libraries to a target path
*/
public static int extractNativeBinaries(File dstCodePath, String packageName) {
@@ -1388,4 +1407,28 @@
}
}
}
+
+ // TODO(b/231951809): remove this workaround after figuring out why apk_tmp_file labels stay
+ // on the installed apps instead of the correct apk_data_file ones
+
+ public static final String SELINUX_BUG = "b/231951809";
+
+ /**
+ * A workaround for b/231951809:
+ * Verifies the SELinux labels of the passed path, and tries to correct them if detects them
+ * wrong or missing.
+ */
+ public static void verifySelinuxLabels(String path) {
+ final String expectedCon = SELinux.fileSelabelLookup(path);
+ final String actualCon = SELinux.getFileContext(path);
+ Slog.i(TAG, SELINUX_BUG + ": checking selinux labels for " + path + " expected / actual: "
+ + expectedCon + " / " + actualCon);
+ if (expectedCon == null || !expectedCon.equals(actualCon)) {
+ Slog.w(TAG, SELINUX_BUG + ": labels don't match, reapplying for " + path);
+ if (!SELinux.restoreconRecursive(new File(path))) {
+ Slog.w(TAG, SELINUX_BUG + ": Failed to reapply restorecon");
+ }
+ // well, if it didn't work now after not working at first, not much else can be done
+ }
+ }
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 48c6ab0..f5981e2 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -352,12 +352,7 @@
case "set-silent-updates-policy":
return runSetSilentUpdatesPolicy();
case "art":
- // Remove the first arg "art" and forward to ART module.
- String[] args = getAllArgs();
- args = Arrays.copyOfRange(args, 1, args.length);
- return LocalManagerRegistry.getManagerOrThrow(ArtManagerLocal.class)
- .handleShellCommand(getTarget(), getInFileDescriptor(),
- getOutFileDescriptor(), getErrFileDescriptor(), args);
+ return runArtSubCommand();
default: {
Boolean domainVerificationResult =
mDomainVerificationShell.runCommand(this, cmd);
@@ -2285,10 +2280,23 @@
}
private int runClear() throws RemoteException {
+ final PrintWriter pw = getOutPrintWriter();
int userId = UserHandle.USER_SYSTEM;
- String option = getNextOption();
- if (option != null && option.equals("--user")) {
- userId = UserHandle.parseUserArg(getNextArgRequired());
+ boolean cacheOnly = false;
+
+ String opt;
+ while ((opt = getNextOption()) != null) {
+ switch (opt) {
+ case "--user":
+ userId = UserHandle.parseUserArg(getNextArgRequired());
+ break;
+ case "--cache-only":
+ cacheOnly = true;
+ break;
+ default:
+ pw.println("Error: Unknown option: " + opt);
+ return 1;
+ }
}
String pkg = getNextArg();
@@ -2300,7 +2308,12 @@
final int translatedUserId =
translateUserId(userId, UserHandle.USER_NULL, "runClear");
final ClearDataObserver obs = new ClearDataObserver();
- ActivityManager.getService().clearApplicationUserData(pkg, false, obs, translatedUserId);
+ if (!cacheOnly) {
+ ActivityManager.getService()
+ .clearApplicationUserData(pkg, false, obs, translatedUserId);
+ } else {
+ mInterface.deleteApplicationCacheFilesAsUser(pkg, translatedUserId, obs);
+ }
synchronized (obs) {
while (!obs.finished) {
try {
@@ -3395,6 +3408,15 @@
return 1;
}
+ private int runArtSubCommand() throws ManagerNotFoundException {
+ // Remove the first arg "art" and forward to ART module.
+ String[] args = getAllArgs();
+ args = Arrays.copyOfRange(args, 1, args.length);
+ return LocalManagerRegistry.getManagerOrThrow(ArtManagerLocal.class)
+ .handleShellCommand(getTarget(), getInFileDescriptor(), getOutFileDescriptor(),
+ getErrFileDescriptor(), args);
+ }
+
private static String checkAbiArgument(String abi) {
if (TextUtils.isEmpty(abi)) {
throw new IllegalArgumentException("Missing ABI argument");
@@ -4060,8 +4082,10 @@
pw.println(" --user: remove the app from the given user.");
pw.println(" --versionCode: only uninstall if the app has the given version code.");
pw.println("");
- pw.println(" clear [--user USER_ID] PACKAGE");
- pw.println(" Deletes all data associated with a package.");
+ pw.println(" clear [--user USER_ID] [--cache-only] PACKAGE");
+ pw.println(" Deletes data associated with a package. Options are:");
+ pw.println(" --user: specifies the user for which we need to clear data");
+ pw.println(" --cache-only: a flag which tells if we only need to clear cache data");
pw.println("");
pw.println(" enable [--user USER_ID] PACKAGE_OR_COMPONENT");
pw.println(" disable [--user USER_ID] PACKAGE_OR_COMPONENT");
diff --git a/services/core/java/com/android/server/pm/ProtectedPackages.java b/services/core/java/com/android/server/pm/ProtectedPackages.java
index bf46129..e923988 100644
--- a/services/core/java/com/android/server/pm/ProtectedPackages.java
+++ b/services/core/java/com/android/server/pm/ProtectedPackages.java
@@ -16,11 +16,11 @@
package com.android.server.pm;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.content.Context;
import android.os.UserHandle;
-import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.SparseArray;
@@ -56,7 +56,7 @@
@Nullable
@GuardedBy("this")
- private final ArrayMap<String, Set<String>> mDeviceOwnerProtectedPackages = new ArrayMap<>();
+ private final SparseArray<Set<String>> mOwnerProtectedPackages = new SparseArray<>();
private final Context mContext;
@@ -79,13 +79,13 @@
: profileOwnerPackages.clone();
}
- /** Sets the protected packages for the device owner. */
- public synchronized void setDeviceOwnerProtectedPackages(
- String deviceOwnerPackageName, List<String> packageNames) {
+ /** Sets packages protected by a device or profile owner. */
+ public synchronized void setOwnerProtectedPackages(
+ @UserIdInt int userId, @NonNull List<String> packageNames) {
if (packageNames.isEmpty()) {
- mDeviceOwnerProtectedPackages.remove(deviceOwnerPackageName);
+ mOwnerProtectedPackages.remove(userId);
} else {
- mDeviceOwnerProtectedPackages.put(deviceOwnerPackageName, new ArraySet<>(packageNames));
+ mOwnerProtectedPackages.put(userId, new ArraySet<>(packageNames));
}
}
@@ -123,19 +123,24 @@
* <p>A protected package means that, apart from the package owner, no system or privileged apps
* can modify its data or package state.
*/
- private synchronized boolean isProtectedPackage(String packageName) {
+ private synchronized boolean isProtectedPackage(@UserIdInt int userId, String packageName) {
return packageName != null && (packageName.equals(mDeviceProvisioningPackage)
- || isDeviceOwnerProtectedPackage(packageName));
+ || isOwnerProtectedPackage(userId, packageName));
}
- /** Returns {@code true} if the given package is a protected package set by any device owner. */
- private synchronized boolean isDeviceOwnerProtectedPackage(String packageName) {
- for (Set<String> protectedPackages : mDeviceOwnerProtectedPackages.values()) {
- if (protectedPackages.contains(packageName)) {
- return true;
- }
- }
- return false;
+ /**
+ * Returns {@code true} if the given package is a protected package set by any device or
+ * profile owner.
+ */
+ private synchronized boolean isOwnerProtectedPackage(
+ @UserIdInt int userId, String packageName) {
+ return isPackageProtectedForUser(UserHandle.USER_ALL, packageName)
+ || isPackageProtectedForUser(userId, packageName);
+ }
+
+ private synchronized boolean isPackageProtectedForUser(int userId, String packageName) {
+ int userIdx = mOwnerProtectedPackages.indexOfKey(userId);
+ return userIdx >= 0 && mOwnerProtectedPackages.valueAt(userIdx).contains(packageName);
}
/**
@@ -146,7 +151,7 @@
*/
public boolean isPackageStateProtected(@UserIdInt int userId, String packageName) {
return hasDeviceOwnerOrProfileOwner(userId, packageName)
- || isProtectedPackage(packageName);
+ || isProtectedPackage(userId, packageName);
}
/**
@@ -155,6 +160,6 @@
*/
public boolean isPackageDataProtected(@UserIdInt int userId, String packageName) {
return hasDeviceOwnerOrProfileOwner(userId, packageName)
- || isProtectedPackage(packageName);
+ || isProtectedPackage(userId, packageName);
}
}
diff --git a/services/core/java/com/android/server/pm/ReconcilePackageUtils.java b/services/core/java/com/android/server/pm/ReconcilePackageUtils.java
index 5fc916f..d6a133e 100644
--- a/services/core/java/com/android/server/pm/ReconcilePackageUtils.java
+++ b/services/core/java/com/android/server/pm/ReconcilePackageUtils.java
@@ -22,11 +22,9 @@
import static com.android.server.pm.PackageManagerService.SCAN_BOOTING;
import static com.android.server.pm.PackageManagerService.SCAN_DONT_KILL_APP;
-import static com.android.server.pm.PackageManagerServiceUtils.compareSignatures;
import android.content.pm.PackageManager;
import android.content.pm.SharedLibraryInfo;
-import android.content.pm.Signature;
import android.content.pm.SigningDetails;
import android.os.SystemProperties;
import android.util.ArrayMap;
@@ -212,12 +210,10 @@
// the signatures on the first package scanned for the shared user (i.e. if the
// signaturesChanged state hasn't been initialized yet in SharedUserSetting).
if (sharedUserSetting != null) {
- final Signature[] sharedUserSignatures = sharedUserSetting
- .signatures.mSigningDetails.getSignatures();
if (sharedUserSetting.signaturesChanged != null
- && compareSignatures(sharedUserSignatures,
- parsedPackage.getSigningDetails().getSignatures())
- != PackageManager.SIGNATURE_MATCH) {
+ && !PackageManagerServiceUtils.canJoinSharedUserId(
+ parsedPackage.getSigningDetails(),
+ sharedUserSetting.getSigningDetails())) {
if (SystemProperties.getInt("ro.product.first_api_level", 0) <= 29) {
// Mismatched signatures is an error and silently skipping system
// packages will likely break the device in unforeseen ways.
diff --git a/services/core/java/com/android/server/pm/ResolveIntentHelper.java b/services/core/java/com/android/server/pm/ResolveIntentHelper.java
index b74670b..2db1c20 100644
--- a/services/core/java/com/android/server/pm/ResolveIntentHelper.java
+++ b/services/core/java/com/android/server/pm/ResolveIntentHelper.java
@@ -306,16 +306,32 @@
return new IntentSender(target);
}
- // In this method, we have to know the actual calling UID, but in some cases Binder's
- // call identity is removed, so the UID has to be passed in explicitly.
- public @NonNull List<ResolveInfo> queryIntentReceiversInternal(Computer computer, Intent intent,
+ /**
+ * Retrieve all receivers that can handle a broadcast of the given intent.
+ * @param queryingUid the results will be filtered in the context of this UID instead.
+ */
+ @NonNull
+ public List<ResolveInfo> queryIntentReceiversInternal(Computer computer, Intent intent,
String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int userId,
- int filterCallingUid) {
+ int queryingUid) {
+ return queryIntentReceiversInternal(computer, intent, resolvedType, flags, userId,
+ queryingUid, false);
+ }
+
+ /**
+ * @see PackageManagerInternal#queryIntentReceivers(Intent, String, long, int, int, boolean)
+ */
+ @NonNull
+ public List<ResolveInfo> queryIntentReceiversInternal(Computer computer, Intent intent,
+ String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int userId,
+ int filterCallingUid, boolean forSend) {
if (!mUserManager.exists(userId)) return Collections.emptyList();
- computer.enforceCrossUserPermission(filterCallingUid, userId, false /*requireFullPermission*/,
- false /*checkShell*/, "query intent receivers");
- final String instantAppPkgName = computer.getInstantAppPackageName(filterCallingUid);
- flags = computer.updateFlagsForResolve(flags, userId, filterCallingUid,
+ // The identity used to filter the receiver components
+ final int queryingUid = forSend ? Process.SYSTEM_UID : filterCallingUid;
+ computer.enforceCrossUserPermission(queryingUid, userId,
+ false /*requireFullPermission*/, false /*checkShell*/, "query intent receivers");
+ final String instantAppPkgName = computer.getInstantAppPackageName(queryingUid);
+ flags = computer.updateFlagsForResolve(flags, userId, queryingUid,
false /*includeInstantApps*/,
computer.isImplicitImageCaptureIntentAndNotSetByDpc(intent, userId,
resolvedType, flags));
@@ -397,7 +413,7 @@
list, true, originalIntent, resolvedType, filterCallingUid);
}
- return computer.applyPostResolutionFilter(list, instantAppPkgName, false, filterCallingUid,
+ return computer.applyPostResolutionFilter(list, instantAppPkgName, false, queryingUid,
false, userId, intent);
}
diff --git a/services/core/java/com/android/server/pm/StorageEventHelper.java b/services/core/java/com/android/server/pm/StorageEventHelper.java
index 666776b..fe1c83b 100644
--- a/services/core/java/com/android/server/pm/StorageEventHelper.java
+++ b/services/core/java/com/android/server/pm/StorageEventHelper.java
@@ -28,7 +28,6 @@
import android.annotation.NonNull;
import android.app.ResourcesManager;
-import android.content.IIntentReceiver;
import android.content.pm.PackageManager;
import android.content.pm.PackagePartitions;
import android.content.pm.UserInfo;
@@ -223,7 +222,7 @@
}
if (DEBUG_INSTALL) Slog.d(TAG, "Loaded packages " + loaded);
- sendResourcesChangedBroadcast(true, false, loaded, null);
+ sendResourcesChangedBroadcast(true /* mediaStatus */, false /* replacing */, loaded);
synchronized (mLoadedVolumes) {
mLoadedVolumes.add(vol.getId());
}
@@ -274,7 +273,7 @@
}
if (DEBUG_INSTALL) Slog.d(TAG, "Unloaded packages " + unloaded);
- sendResourcesChangedBroadcast(false, false, unloaded, null);
+ sendResourcesChangedBroadcast(false /* mediaStatus */, false /* replacing */, unloaded);
synchronized (mLoadedVolumes) {
mLoadedVolumes.remove(vol.getId());
}
@@ -290,7 +289,7 @@
}
private void sendResourcesChangedBroadcast(boolean mediaStatus, boolean replacing,
- ArrayList<AndroidPackage> packages, IIntentReceiver finishedReceiver) {
+ ArrayList<AndroidPackage> packages) {
final int size = packages.size();
final String[] packageNames = new String[size];
final int[] packageUids = new int[size];
@@ -299,8 +298,8 @@
packageNames[i] = pkg.getPackageName();
packageUids[i] = pkg.getUid();
}
- mBroadcastHelper.sendResourcesChangedBroadcast(mediaStatus, replacing, packageNames,
- packageUids, finishedReceiver);
+ mBroadcastHelper.sendResourcesChangedBroadcast(mPm.snapshotComputer(), mediaStatus,
+ replacing, packageNames, packageUids);
}
/**
diff --git a/services/core/java/com/android/server/pm/SuspendPackageHelper.java b/services/core/java/com/android/server/pm/SuspendPackageHelper.java
index b475840..5f44c63 100644
--- a/services/core/java/com/android/server/pm/SuspendPackageHelper.java
+++ b/services/core/java/com/android/server/pm/SuspendPackageHelper.java
@@ -593,9 +593,8 @@
for (int i = 0; i < lists.size(); i++) {
final Bundle extras = new Bundle(3);
final BroadcastParams list = lists.get(i);
- extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST,
- list.getPackageNames().toArray(new String[0]));
- extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, list.getUids().toArray());
+ extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, list.getPackageNames());
+ extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, list.getUids());
final SparseArray<int[]> allowList = list.getAllowList().size() == 0
? null : list.getAllowList();
handler.post(() -> mBroadcastHelper.sendPackageBroadcast(intent, null /* pkg */,
diff --git a/services/core/java/com/android/server/pm/ThreadComputer.java b/services/core/java/com/android/server/pm/ThreadComputer.java
deleted file mode 100644
index f603e63..0000000
--- a/services/core/java/com/android/server/pm/ThreadComputer.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.pm;
-
-/**
- * This class records the Computer being used by a thread and the Computer's reference
- * count. There is a thread-local copy of this class.
- */
-public final class ThreadComputer implements AutoCloseable {
- Computer mComputer = null;
- int mRefCount = 0;
-
- void acquire(Computer c) {
- if (mRefCount != 0 && mComputer != c) {
- throw new RuntimeException("computer mismatch, count = " + mRefCount);
- }
- mComputer = c;
- mRefCount++;
- }
-
- void acquire() {
- if (mRefCount == 0 || mComputer == null) {
- throw new RuntimeException("computer acquire on empty ref count");
- }
- mRefCount++;
- }
-
- void release() {
- if (--mRefCount == 0) {
- mComputer = null;
- }
- }
-
- @Override
- public void close() {
- release();
- }
-}
diff --git a/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java b/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java
index b26b694..d49227d 100644
--- a/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java
+++ b/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java
@@ -22,11 +22,13 @@
import static com.android.internal.art.ArtStatsLog.ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_FAKE_RUN_FROM_APK_FALLBACK;
import static com.android.internal.art.ArtStatsLog.ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_FAKE_RUN_FROM_VDEX_FALLBACK;
+import android.app.job.JobParameters;
import android.os.SystemClock;
import android.util.Slog;
import android.util.jar.StrictJarFile;
import com.android.internal.art.ArtStatsLog;
+import com.android.server.pm.BackgroundDexOptService;
import com.android.server.pm.PackageManagerService;
import java.io.IOException;
@@ -299,4 +301,31 @@
ArtStatsLog.ART_DATUM_REPORTED__ISA__ART_ISA_UNKNOWN));
}
}
+
+ private static final Map<Integer, Integer> STATUS_MAP =
+ Map.of(BackgroundDexOptService.STATUS_OK,
+ ArtStatsLog.BACKGROUND_DEXOPT_JOB_ENDED__STATUS__STATUS_JOB_FINISHED,
+ BackgroundDexOptService.STATUS_ABORT_BY_CANCELLATION,
+ ArtStatsLog.BACKGROUND_DEXOPT_JOB_ENDED__STATUS__STATUS_ABORT_BY_CANCELLATION,
+ BackgroundDexOptService.STATUS_ABORT_NO_SPACE_LEFT,
+ ArtStatsLog.BACKGROUND_DEXOPT_JOB_ENDED__STATUS__STATUS_ABORT_NO_SPACE_LEFT,
+ BackgroundDexOptService.STATUS_ABORT_THERMAL,
+ ArtStatsLog.BACKGROUND_DEXOPT_JOB_ENDED__STATUS__STATUS_ABORT_THERMAL,
+ BackgroundDexOptService.STATUS_ABORT_BATTERY,
+ ArtStatsLog.BACKGROUND_DEXOPT_JOB_ENDED__STATUS__STATUS_ABORT_BATTERY,
+ BackgroundDexOptService.STATUS_DEX_OPT_FAILED,
+ ArtStatsLog.BACKGROUND_DEXOPT_JOB_ENDED__STATUS__STATUS_JOB_FINISHED);
+
+ /** Helper class to write background dexopt job stats to statsd. */
+ public static class BackgroundDexoptJobStatsLogger {
+ /** Writes background dexopt job stats to statsd. */
+ public void write(@BackgroundDexOptService.Status int status,
+ @JobParameters.StopReason int cancellationReason, long durationMs,
+ long durationIncludingSleepMs) {
+ ArtStatsLog.write(ArtStatsLog.BACKGROUND_DEXOPT_JOB_ENDED,
+ STATUS_MAP.getOrDefault(status,
+ ArtStatsLog.BACKGROUND_DEXOPT_JOB_ENDED__STATUS__STATUS_UNKNOWN),
+ cancellationReason, durationMs, durationIncludingSleepMs);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index 383f3f8..1fb891d 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -57,7 +57,6 @@
import android.security.Credentials;
import android.speech.RecognitionService;
import android.telephony.TelephonyManager;
-import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
@@ -618,6 +617,10 @@
grantPermissionsToSystemPackage(pm, getDefaultSearchSelectorPackage(), userId,
NOTIFICATION_PERMISSIONS);
+ // Captive Portal Login
+ grantPermissionsToSystemPackage(pm, getDefaultCaptivePortalLoginPackage(), userId,
+ NOTIFICATION_PERMISSIONS);
+
// Camera
grantPermissionsToSystemPackage(pm,
getDefaultSystemHandlerActivityPackage(pm, MediaStore.ACTION_IMAGE_CAPTURE, userId),
@@ -910,14 +913,6 @@
grantSystemFixedPermissionsToSystemPackage(pm, "com.android.sharedstoragebackup", userId,
STORAGE_PERMISSIONS);
- // System Captions Service
- String systemCaptionsServicePackageName =
- mContext.getPackageManager().getSystemCaptionsServicePackageName();
- if (!TextUtils.isEmpty(systemCaptionsServicePackageName)) {
- grantPermissionsToSystemPackage(pm, systemCaptionsServicePackageName, userId,
- MICROPHONE_PERMISSIONS);
- }
-
// Bluetooth MIDI Service
grantSystemFixedPermissionsToSystemPackage(pm,
MidiManager.BLUETOOTH_MIDI_SERVICE_PACKAGE, userId,
@@ -934,6 +929,10 @@
return mContext.getString(R.string.config_defaultSearchSelectorPackageName);
}
+ private String getDefaultCaptivePortalLoginPackage() {
+ return mContext.getString(R.string.config_defaultCaptivePortalLoginPackageName);
+ }
+
@SafeVarargs
private final void grantPermissionToEachSystemPackage(PackageManagerWrapper pm,
ArrayList<String> packages, int userId, Set<String>... permissions) {
@@ -1019,8 +1018,6 @@
for (String packageName : packageNames) {
grantPermissionsToSystemPackage(NO_PM_CACHE, packageName, userId,
PHONE_PERMISSIONS, ALWAYS_LOCATION_PERMISSIONS, SMS_PERMISSIONS);
- grantPermissionsToPackage(NO_PM_CACHE, packageName, userId, false, false,
- NOTIFICATION_PERMISSIONS);
}
}
diff --git a/services/core/java/com/android/server/pm/permission/LegacyPermissionManagerInternal.java b/services/core/java/com/android/server/pm/permission/LegacyPermissionManagerInternal.java
index 446e20b7..6c2354f 100644
--- a/services/core/java/com/android/server/pm/permission/LegacyPermissionManagerInternal.java
+++ b/services/core/java/com/android/server/pm/permission/LegacyPermissionManagerInternal.java
@@ -17,6 +17,7 @@
package com.android.server.pm.permission;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.UserIdInt;
/**
@@ -105,6 +106,20 @@
void scheduleReadDefaultPermissionExceptions();
/**
+ * Check whether a particular package should have access to the microphone data from the
+ * SoundTrigger.
+ *
+ * @param uid the uid of the package you are checking against
+ * @param packageName the name of the package you are checking against
+ * @param attributionTag the attributionTag to attach to the app op transaction
+ * @param reason the reason to attach to the app op transaction
+ * @return {@code PERMISSION_GRANTED} if the permission is granted,
+ * or {@code PERMISSION_SOFT/HARD DENIED otherwise
+ */
+ int checkSoundTriggerRecordAudioPermissionForDataDelivery(int uid,
+ @NonNull String packageName, @Nullable String attributionTag, @NonNull String reason);
+
+ /**
* Provider for package names.
*/
interface PackagesProvider {
diff --git a/services/core/java/com/android/server/pm/permission/LegacyPermissionManagerService.java b/services/core/java/com/android/server/pm/permission/LegacyPermissionManagerService.java
index 360a04f..88b4a94 100644
--- a/services/core/java/com/android/server/pm/permission/LegacyPermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/LegacyPermissionManagerService.java
@@ -16,12 +16,15 @@
package com.android.server.pm.permission;
+import static android.Manifest.permission.RECORD_AUDIO;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.AppOpsManager;
import android.app.admin.DevicePolicyManager;
import android.content.Context;
+import android.content.PermissionChecker;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
@@ -399,6 +402,21 @@
public void scheduleReadDefaultPermissionExceptions() {
mDefaultPermissionGrantPolicy.scheduleReadDefaultPermissionExceptions();
}
+
+ @Override
+ public int checkSoundTriggerRecordAudioPermissionForDataDelivery(int uid,
+ @NonNull String packageName, @Nullable String attributionTag,
+ @NonNull String reason) {
+ int result = PermissionChecker.checkPermissionForPreflight(mContext, RECORD_AUDIO, -1,
+ uid, packageName);
+ if (result != PermissionChecker.PERMISSION_GRANTED) {
+ return result;
+ }
+ mContext.getSystemService(AppOpsManager.class).noteOpNoThrow(
+ AppOpsManager.OP_RECEIVE_AMBIENT_TRIGGER_AUDIO, uid, packageName,
+ attributionTag, reason);
+ return result;
+ }
}
/**
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 5d6ebec..edbfa1a 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -17,7 +17,6 @@
package com.android.server.pm.permission;
import static android.Manifest.permission.CAPTURE_AUDIO_HOTWORD;
-import static android.Manifest.permission.POST_NOTIFICATIONS;
import static android.Manifest.permission.RECORD_AUDIO;
import static android.Manifest.permission.UPDATE_APP_OPS_STATS;
import static android.app.AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE;
@@ -51,7 +50,6 @@
import android.content.pm.PermissionInfo;
import android.content.pm.permission.SplitPermissionInfoParcelable;
import android.os.Binder;
-import android.os.Build;
import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException;
@@ -595,26 +593,6 @@
}
@Override
- public int checkPostNotificationsPermissionGrantedOrLegacyAccess(int uid) {
- int granted = PermissionManagerService.this.checkUidPermission(uid,
- POST_NOTIFICATIONS);
- AndroidPackage pkg = mPackageManagerInt.getPackage(uid);
- if (pkg == null) {
- Slog.e(LOG_TAG, "No package for uid " + uid);
- return granted;
- }
- if (granted != PackageManager.PERMISSION_GRANTED
- && pkg.getTargetSdkVersion() >= Build.VERSION_CODES.M) {
- int flags = PermissionManagerService.this.getPermissionFlags(pkg.getPackageName(),
- POST_NOTIFICATIONS, UserHandle.getUserId(uid));
- if ((flags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) != 0) {
- return PackageManager.PERMISSION_GRANTED;
- }
- }
- return granted;
- }
-
- @Override
public void startShellPermissionIdentityDelegation(int uid, @NonNull String packageName,
@Nullable List<String> permissionNames) {
Objects.requireNonNull(packageName, "packageName");
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 ef2f2e9..bd3fc50 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
@@ -42,6 +42,7 @@
import static android.content.pm.PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE;
import static android.content.pm.PackageManager.MASK_PERMISSION_FLAGS_ALL;
import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.Process.INVALID_UID;
import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
import static android.permission.PermissionManager.KILL_APP_REASON_GIDS_CHANGED;
@@ -96,6 +97,7 @@
import android.permission.IOnPermissionsChangeListener;
import android.permission.PermissionControllerManager;
import android.permission.PermissionManager;
+import android.provider.Settings;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -332,7 +334,8 @@
mPackageManagerInt.writeSettings(true);
}
@Override
- public void onPermissionRevoked(int uid, int userId, String reason, boolean overrideKill) {
+ public void onPermissionRevoked(int uid, int userId, String reason, boolean overrideKill,
+ @Nullable String permissionName) {
mOnPermissionChangeListeners.onPermissionsChanged(uid);
// Critical; after this call the application should never have the permission
@@ -341,13 +344,41 @@
return;
}
- final int appId = UserHandle.getAppId(uid);
- if (reason == null) {
- mHandler.post(() -> killUid(appId, userId, KILL_APP_REASON_PERMISSIONS_REVOKED));
- } else {
- mHandler.post(() -> killUid(appId, userId, reason));
+ mHandler.post(() -> {
+ if (POST_NOTIFICATIONS.equals(permissionName)
+ && isAppBackupAndRestoreRunning(uid)) {
+ return;
+ }
+
+ final int appId = UserHandle.getAppId(uid);
+ if (reason == null) {
+ killUid(appId, userId, KILL_APP_REASON_PERMISSIONS_REVOKED);
+ } else {
+ killUid(appId, userId, reason);
+ }
+ });
+ }
+
+ private boolean isAppBackupAndRestoreRunning(int uid) {
+ if (checkUidPermission(uid, Manifest.permission.BACKUP) != PERMISSION_GRANTED) {
+ return false;
+ }
+
+ try {
+ int userId = UserHandle.getUserId(uid);
+ boolean isInSetup = Settings.Secure.getIntForUser(mContext.getContentResolver(),
+ Settings.Secure.USER_SETUP_COMPLETE, userId) == 0;
+ boolean isInDeferredSetup = Settings.Secure.getIntForUser(
+ mContext.getContentResolver(),
+ Settings.Secure.USER_SETUP_PERSONALIZATION_STATE, userId)
+ == Settings.Secure.USER_SETUP_PERSONALIZATION_STARTED;
+ return isInSetup || isInDeferredSetup;
+ } catch (Settings.SettingNotFoundException e) {
+ Slog.w(LOG_TAG, "Failed to check if the user is in restore: " + e);
+ return false;
}
}
+
@Override
public void onInstallPermissionRevoked() {
mPackageManagerInt.writeSettings(true);
@@ -593,8 +624,8 @@
}
final int callingUserId = UserHandle.getUserId(callingUid);
- if (mPackageManagerInt.filterAppAccess(permissionGroup.getPackageName(), callingUid,
- callingUserId)) {
+ if (permissionGroup != null && mPackageManagerInt.filterAppAccess(
+ permissionGroup.getPackageName(), callingUid, callingUserId)) {
return null;
}
out.removeIf(it -> mPackageManagerInt.filterAppAccess(it.packageName, callingUid,
@@ -1605,7 +1636,7 @@
if (callback != null) {
if (isRuntimePermission) {
callback.onPermissionRevoked(UserHandle.getUid(userId, pkg.getUid()), userId,
- reason, overrideKill);
+ reason, overrideKill, permName);
} else {
mDefaultPermissionCallback.onInstallPermissionRevoked();
}
@@ -5249,7 +5280,11 @@
onPermissionRevoked(uid, userId, reason, false);
}
public void onPermissionRevoked(int uid, @UserIdInt int userId, String reason,
- boolean overrideKill) {}
+ boolean overrideKill) {
+ onPermissionRevoked(uid, userId, reason, false, null);
+ }
+ public void onPermissionRevoked(int uid, @UserIdInt int userId, String reason,
+ boolean overrideKill, @Nullable String permissionName) {}
public void onInstallPermissionRevoked() {}
public void onPermissionUpdated(@UserIdInt int[] updatedUserIds, boolean sync) {}
public void onPermissionUpdatedNotifyListener(@UserIdInt int[] updatedUserIds, boolean sync,
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
index 812d7a0..d2c4ec4 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
@@ -63,17 +63,6 @@
int checkUidPermission(int uid, @NonNull String permissionName);
/**
- * Check whether a particular UID has been granted the POST_NOTIFICATIONS permission, or if
- * access should be granted based on legacy access (currently symbolized by the REVIEW_REQUIRED
- * permission flag
- *
- * @param uid the UID
- * @return {@code PERMISSION_GRANTED} if the permission is granted, or legacy access is granted,
- * {@code PERMISSION_DENIED} otherwise
- */
- int checkPostNotificationsPermissionGrantedOrLegacyAccess(int uid);
-
- /**
* Adds a listener for runtime permission state (permissions or flags) changes.
*
* @param listener The listener.
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedPermissionUtils.java b/services/core/java/com/android/server/pm/pkg/component/ParsedPermissionUtils.java
index fa15aaa..10e8c47 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedPermissionUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ParsedPermissionUtils.java
@@ -27,6 +27,7 @@
import android.content.res.XmlResourceParser;
import android.os.Build;
import android.util.ArrayMap;
+import android.util.EventLog;
import android.util.Slog;
import com.android.internal.R;
@@ -37,6 +38,7 @@
import java.io.IOException;
import java.util.List;
+import java.util.Objects;
/**
* @hide
@@ -280,8 +282,28 @@
}
/**
- * @return {@code true} if the package declares duplicate permissions with different
- * protection levels.
+ * Determines if a duplicate permission is malformed .i.e. defines different protection level
+ * or group.
+ */
+ private static boolean isMalformedDuplicate(ParsedPermission p1, ParsedPermission p2) {
+ // Since a permission tree is also added as a permission with normal protection
+ // level, we need to skip if the parsedPermission is a permission tree.
+ if (p1 == null || p2 == null || p1.isTree() || p2.isTree()) {
+ return false;
+ }
+
+ if (p1.getProtectionLevel() != p2.getProtectionLevel()) {
+ return true;
+ }
+ if (!Objects.equals(p1.getGroup(), p2.getGroup())) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * @return {@code true} if the package declares malformed duplicate permissions.
*/
public static boolean declareDuplicatePermission(@NonNull ParsingPackage pkg) {
final List<ParsedPermission> permissions = pkg.getPermissions();
@@ -292,10 +314,10 @@
final ParsedPermission parsedPermission = permissions.get(i);
final String name = parsedPermission.getName();
final ParsedPermission perm = checkDuplicatePerm.get(name);
- // Since a permission tree is also added as a permission with normal protection
- // level, we need to skip if the parsedPermission is a permission tree.
- if (perm != null && !(perm.isTree() || parsedPermission.isTree())
- && perm.getProtectionLevel() != parsedPermission.getProtectionLevel()) {
+ if (isMalformedDuplicate(parsedPermission, perm)) {
+ // Fix for b/213323615
+ EventLog.writeEvent(0x534e4554, "213323615",
+ "The package " + pkg.getPackageName() + " seems malicious");
return true;
}
checkDuplicatePerm.put(name, parsedPermission);
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
index 33dc777..fc0f380 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
@@ -954,7 +954,7 @@
if (ParsedPermissionUtils.declareDuplicatePermission(pkg)) {
return input.error(
INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
- "Declare duplicate permissions with different protection levels."
+ "Found duplicate permission with a different attribute value."
);
}
diff --git a/services/core/java/com/android/server/policy/AppOpsPolicy.java b/services/core/java/com/android/server/policy/AppOpsPolicy.java
index e157a27..a6d148c 100644
--- a/services/core/java/com/android/server/policy/AppOpsPolicy.java
+++ b/services/core/java/com/android/server/policy/AppOpsPolicy.java
@@ -87,8 +87,8 @@
private final VoiceInteractionManagerInternal mVoiceInteractionManagerInternal;
/**
- * Whether this device allows only the HotwordDetectionService to use OP_RECORD_AUDIO_HOTWORD
- * which doesn't incur the privacy indicator.
+ * Whether this device allows only the HotwordDetectionService to use
+ * OP_RECORD_AUDIO_HOTWORD which doesn't incur the privacy indicator.
*/
private final boolean mIsHotwordDetectionServiceRequired;
@@ -428,8 +428,8 @@
if (!mIsHotwordDetectionServiceRequired) {
return code;
}
- // Only the HotwordDetectionService can use the HOTWORD op which doesn't incur the
- // privacy indicator. Downgrade to standard RECORD_AUDIO for other processes.
+ // Only the HotwordDetectionService can use the RECORD_AUDIO_HOTWORD op which doesn't
+ // incur the privacy indicator. Downgrade to standard RECORD_AUDIO for other processes.
final HotwordDetectionServiceIdentity hotwordDetectionServiceIdentity =
mVoiceInteractionManagerInternal.getHotwordDetectionServiceIdentity();
if (hotwordDetectionServiceIdentity != null
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java
index 977f79f..b56e112 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyService.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java
@@ -915,8 +915,7 @@
int permissionFlags = mPackageManager.getPermissionFlags(permissionName,
packageName, mContext.getUser());
boolean isReviewRequired = (permissionFlags & FLAG_PERMISSION_REVIEW_REQUIRED) != 0;
- if (isReviewRequired && !CompatChanges.isChangeEnabled(
- NOTIFICATION_PERM_CHANGE_ID, packageName, user)) {
+ if (isReviewRequired) {
return;
}
@@ -1118,48 +1117,13 @@
private class Internal extends PermissionPolicyInternal {
- // UIDs that, if a grant dialog is shown for POST_NOTIFICATIONS before next reboot,
- // should display a "continue allowing" message, rather than an "allow" message
- private final ArraySet<Integer> mContinueNotifGrantMessageUids = new ArraySet<>();
-
private final ActivityInterceptorCallback mActivityInterceptorCallback =
new ActivityInterceptorCallback() {
@Nullable
@Override
public ActivityInterceptorCallback.ActivityInterceptResult intercept(
ActivityInterceptorInfo info) {
- String action = info.intent.getAction();
- ActivityInterceptResult result = null;
- if (!ACTION_REQUEST_PERMISSIONS_FOR_OTHER.equals(action)
- && !PackageManager.ACTION_REQUEST_PERMISSIONS.equals(action)) {
- return null;
- }
- // Only this interceptor can add LEGACY_ACCESS_PERMISSION_NAMES
- if (info.intent.getStringArrayExtra(PackageManager
- .EXTRA_REQUEST_PERMISSIONS_LEGACY_ACCESS_PERMISSION_NAMES)
- != null) {
- result = new ActivityInterceptResult(
- new Intent(info.intent), info.checkedOptions);
- result.intent.removeExtra(PackageManager
- .EXTRA_REQUEST_PERMISSIONS_LEGACY_ACCESS_PERMISSION_NAMES);
- }
- if (PackageManager.ACTION_REQUEST_PERMISSIONS.equals(action)
- && !mContinueNotifGrantMessageUids.contains(info.realCallingUid)) {
- return result;
- }
- if (ACTION_REQUEST_PERMISSIONS_FOR_OTHER.equals(action)) {
- String otherPkg = info.intent.getStringExtra(Intent.EXTRA_PACKAGE_NAME);
- if (otherPkg == null || (mPackageManager.getPermissionFlags(
- POST_NOTIFICATIONS, otherPkg, UserHandle.of(info.userId))
- & FLAG_PERMISSION_REVIEW_REQUIRED) == 0) {
- return result;
- }
- }
-
- mContinueNotifGrantMessageUids.remove(info.realCallingUid);
- return new ActivityInterceptResult(info.intent.putExtra(PackageManager
- .EXTRA_REQUEST_PERMISSIONS_LEGACY_ACCESS_PERMISSION_NAMES,
- new String[] { POST_NOTIFICATIONS }), info.checkedOptions);
+ return null;
}
@Override
@@ -1173,10 +1137,8 @@
return;
}
UserHandle user = UserHandle.of(taskInfo.userId);
- if (CompatChanges.isChangeEnabled(NOTIFICATION_PERM_CHANGE_ID,
+ if (!CompatChanges.isChangeEnabled(NOTIFICATION_PERM_CHANGE_ID,
activityInfo.packageName, user)) {
- clearNotificationReviewFlagsIfNeeded(activityInfo.packageName, user);
- } else {
// Post the activity start checks to ensure the notification channel
// checks happen outside the WindowManager global lock.
mHandler.post(() -> showNotificationPromptIfNeeded(
@@ -1337,22 +1299,6 @@
&& isLauncherIntent(taskInfo.baseIntent);
}
- private void clearNotificationReviewFlagsIfNeeded(String packageName, UserHandle user) {
- if ((mPackageManager.getPermissionFlags(POST_NOTIFICATIONS, packageName, user)
- & FLAG_PERMISSION_REVIEW_REQUIRED) == 0) {
- return;
- }
- try {
- int uid = mPackageManager.getPackageUidAsUser(packageName, 0,
- user.getIdentifier());
- mContinueNotifGrantMessageUids.add(uid);
- mPackageManager.updatePermissionFlags(POST_NOTIFICATIONS, packageName,
- FLAG_PERMISSION_REVIEW_REQUIRED, 0, user);
- } catch (PackageManager.NameNotFoundException e) {
- // Do nothing
- }
- }
-
private void launchNotificationPermissionRequestDialog(String pkgName, UserHandle user,
int taskId, @Nullable ActivityInterceptorInfo info) {
Intent grantPermission = mPackageManager
@@ -1469,8 +1415,7 @@
== PackageManager.PERMISSION_GRANTED;
int flags = mPackageManager.getPermissionFlags(POST_NOTIFICATIONS, pkgName, user);
boolean explicitlySet = (flags & PermissionManager.EXPLICIT_SET_FLAGS) != 0;
- boolean needsReview = (flags & FLAG_PERMISSION_REVIEW_REQUIRED) != 0;
- return !granted && hasCreatedNotificationChannels && (needsReview || !explicitlySet);
+ return !granted && hasCreatedNotificationChannels && !explicitlySet;
}
}
}
diff --git a/services/core/java/com/android/server/sensorprivacy/CameraPrivacyLightController.java b/services/core/java/com/android/server/sensorprivacy/CameraPrivacyLightController.java
index 750d400..fd6ec06 100644
--- a/services/core/java/com/android/server/sensorprivacy/CameraPrivacyLightController.java
+++ b/services/core/java/com/android/server/sensorprivacy/CameraPrivacyLightController.java
@@ -16,44 +16,105 @@
package com.android.server.sensorprivacy;
+import static android.hardware.SensorManager.SENSOR_DELAY_NORMAL;
+
+import android.annotation.ColorInt;
import android.app.AppOpsManager;
import android.content.Context;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
import android.hardware.lights.Light;
import android.hardware.lights.LightState;
import android.hardware.lights.LightsManager;
import android.hardware.lights.LightsRequest;
+import android.os.Handler;
+import android.os.HandlerExecutor;
+import android.os.Looper;
+import android.os.SystemClock;
import android.permission.PermissionManager;
import android.util.ArraySet;
+import android.util.Pair;
import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.server.FgThread;
+import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
+import java.util.concurrent.Executor;
-class CameraPrivacyLightController implements AppOpsManager.OnOpActiveChangedListener {
+class CameraPrivacyLightController implements AppOpsManager.OnOpActiveChangedListener,
+ SensorEventListener {
+ @VisibleForTesting
+ static final double LIGHT_VALUE_MULTIPLIER = 1 / Math.log(1.1);
+
+ private final Handler mHandler;
+ private final Executor mExecutor;
private final Context mContext;
+ private final AppOpsManager mAppOpsManager;
private final LightsManager mLightsManager;
+ private final SensorManager mSensorManager;
private final Set<String> mActivePackages = new ArraySet<>();
private final Set<String> mActivePhonePackages = new ArraySet<>();
- private final int mCameraPrivacyLightColor;
-
private final List<Light> mCameraLights = new ArrayList<>();
- private final AppOpsManager mAppOpsManager;
private LightsManager.LightsSession mLightsSession = null;
+ @ColorInt
+ private final int mDayColor;
+ @ColorInt
+ private final int mNightColor;
+
+ private final Sensor mLightSensor;
+
+ private boolean mIsAmbientLightListenerRegistered = false;
+ private final long mMovingAverageIntervalMillis;
+ /** When average of the time integral over the past {@link #mMovingAverageIntervalMillis}
+ * milliseconds of the log_1.1(lux(t)) is greater than this value, use the daytime brightness
+ * else use nighttime brightness. */
+ private final long mNightThreshold;
+ private final ArrayDeque<Pair<Long, Integer>> mAmbientLightValues = new ArrayDeque<>();
+ /** Tracks the Riemann sum of {@link #mAmbientLightValues} to avoid O(n) operations when sum is
+ * needed */
+ private long mAlvSum = 0;
+ private int mLastLightColor = 0;
+ /** The elapsed real time that the ALS was started watching */
+ private long mElapsedTimeStartedReading;
+
+ private final Object mDelayedUpdateToken = new Object();
+
+ // Can't mock static native methods, workaround for testing
+ private long mElapsedRealTime = -1;
+
CameraPrivacyLightController(Context context) {
+ this(context, FgThread.get().getLooper());
+ }
+
+ @VisibleForTesting
+ CameraPrivacyLightController(Context context, Looper looper) {
mContext = context;
+ mHandler = new Handler(looper);
+ mExecutor = new HandlerExecutor(mHandler);
+
mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
mLightsManager = mContext.getSystemService(LightsManager.class);
+ mSensorManager = mContext.getSystemService(SensorManager.class);
- mCameraPrivacyLightColor = mContext.getColor(R.color.camera_privacy_light);
+ mDayColor = mContext.getColor(R.color.camera_privacy_light_day);
+ mNightColor = mContext.getColor(R.color.camera_privacy_light_night);
+ mMovingAverageIntervalMillis = mContext.getResources()
+ .getInteger(R.integer.config_cameraPrivacyLightAlsAveragingIntervalMillis);
+ mNightThreshold = (long) (Math.log(mContext.getResources()
+ .getInteger(R.integer.config_cameraPrivacyLightAlsNightThreshold))
+ * LIGHT_VALUE_MULTIPLIER);
List<Light> lights = mLightsManager.getLights();
for (int i = 0; i < lights.size(); i++) {
@@ -64,12 +125,60 @@
}
if (mCameraLights.isEmpty()) {
+ mLightSensor = null;
return;
}
mAppOpsManager.startWatchingActive(
new String[] {AppOpsManager.OPSTR_CAMERA, AppOpsManager.OPSTR_PHONE_CALL_CAMERA},
- FgThread.getExecutor(), this);
+ mExecutor, this);
+
+ // It may be useful in the future to configure devices to know which lights are near which
+ // sensors so that we can control individual lights based on their environment.
+ mLightSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
+ }
+
+ private void addElement(long time, int value) {
+ if (mAmbientLightValues.isEmpty()) {
+ // Eliminate the size == 1 edge case and assume the light value has been constant for
+ // the previous interval
+ mAmbientLightValues.add(new Pair<>(time - getCurrentIntervalMillis() - 1, value));
+ }
+ Pair<Long, Integer> lastElement = mAmbientLightValues.peekLast();
+ mAmbientLightValues.add(new Pair<>(time, value));
+
+ mAlvSum += (time - lastElement.first) * lastElement.second;
+ removeObsoleteData(time);
+ }
+
+ private void removeObsoleteData(long time) {
+ while (mAmbientLightValues.size() > 1) {
+ Pair<Long, Integer> element0 = mAmbientLightValues.pollFirst(); // NOTICE: POLL
+ Pair<Long, Integer> element1 = mAmbientLightValues.peekFirst(); // NOTICE: PEEK
+ if (element1.first > time - getCurrentIntervalMillis()) {
+ mAmbientLightValues.addFirst(element0);
+ break;
+ }
+ mAlvSum -= (element1.first - element0.first) * element0.second;
+ }
+ }
+
+ /**
+ * Gives the Riemann sum of {@link #mAmbientLightValues} where the part of the interval that
+ * stretches outside the time window is removed and the time since the last change is added in.
+ */
+ private long getLiveAmbientLightTotal() {
+ if (mAmbientLightValues.isEmpty()) {
+ return mAlvSum;
+ }
+ long time = getElapsedRealTime();
+ removeObsoleteData(time);
+
+ Pair<Long, Integer> firstElement = mAmbientLightValues.peekFirst();
+ Pair<Long, Integer> lastElement = mAmbientLightValues.peekLast();
+
+ return mAlvSum - Math.max(0, time - getCurrentIntervalMillis() - firstElement.first)
+ * firstElement.second + (time - lastElement.first) * lastElement.second;
}
@Override
@@ -93,10 +202,16 @@
}
private void updateLightSession() {
+ if (Looper.myLooper() != mHandler.getLooper()) {
+ mHandler.post(this::updateLightSession);
+ return;
+ }
+
Set<String> exemptedPackages = PermissionManager.getIndicatorExemptedPackages(mContext);
boolean shouldSessionEnd = exemptedPackages.containsAll(mActivePackages)
&& exemptedPackages.containsAll(mActivePhonePackages);
+ updateSensorListener(shouldSessionEnd);
if (shouldSessionEnd) {
if (mLightsSession == null) {
@@ -106,20 +221,73 @@
mLightsSession.close();
mLightsSession = null;
} else {
- if (mLightsSession != null) {
+ int lightColor;
+ if (mLightSensor != null && getLiveAmbientLightTotal()
+ < getCurrentIntervalMillis() * mNightThreshold) {
+ lightColor = mNightColor;
+ } else {
+ lightColor = mDayColor;
+ }
+
+ if (mLastLightColor == lightColor && mLightsSession != null) {
return;
}
+ mLastLightColor = lightColor;
LightsRequest.Builder requestBuilder = new LightsRequest.Builder();
for (int i = 0; i < mCameraLights.size(); i++) {
requestBuilder.addLight(mCameraLights.get(i),
new LightState.Builder()
- .setColor(mCameraPrivacyLightColor)
+ .setColor(lightColor)
.build());
}
- mLightsSession = mLightsManager.openSession(Integer.MAX_VALUE);
+ if (mLightsSession == null) {
+ mLightsSession = mLightsManager.openSession(Integer.MAX_VALUE);
+ }
+
mLightsSession.requestLights(requestBuilder.build());
}
}
+
+ private void updateSensorListener(boolean shouldSessionEnd) {
+ if (shouldSessionEnd && mIsAmbientLightListenerRegistered) {
+ mSensorManager.unregisterListener(this);
+ mIsAmbientLightListenerRegistered = false;
+ }
+ if (!shouldSessionEnd && !mIsAmbientLightListenerRegistered && mLightSensor != null) {
+ mSensorManager.registerListener(this, mLightSensor, SENSOR_DELAY_NORMAL, mHandler);
+ mIsAmbientLightListenerRegistered = true;
+ mElapsedTimeStartedReading = getElapsedRealTime();
+ }
+ }
+
+ private long getElapsedRealTime() {
+ return mElapsedRealTime == -1 ? SystemClock.elapsedRealtime() : mElapsedRealTime;
+ }
+
+ @VisibleForTesting
+ void setElapsedRealTime(long time) {
+ mElapsedRealTime = time;
+ }
+
+ @Override
+ public void onSensorChanged(SensorEvent event) {
+ // Using log space to represent human sensation (Fechner's Law) instead of lux
+ // because lux values causes bright flashes to skew the average very high.
+ addElement(event.timestamp, Math.max(0,
+ (int) (Math.log(event.values[0]) * LIGHT_VALUE_MULTIPLIER)));
+ updateLightSession();
+ mHandler.removeCallbacksAndMessages(mDelayedUpdateToken);
+ mHandler.postDelayed(CameraPrivacyLightController.this::updateLightSession,
+ mDelayedUpdateToken, mMovingAverageIntervalMillis);
+ }
+
+ @Override
+ public void onAccuracyChanged(Sensor sensor, int accuracy) {}
+
+ private long getCurrentIntervalMillis() {
+ return Math.min(mMovingAverageIntervalMillis,
+ getElapsedRealTime() - mElapsedTimeStartedReading);
+ }
}
diff --git a/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java b/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java
index 3c779f3..c354f11 100644
--- a/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java
+++ b/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java
@@ -25,6 +25,7 @@
import static android.app.AppOpsManager.OP_CAMERA;
import static android.app.AppOpsManager.OP_PHONE_CALL_CAMERA;
import static android.app.AppOpsManager.OP_PHONE_CALL_MICROPHONE;
+import static android.app.AppOpsManager.OP_RECEIVE_AMBIENT_TRIGGER_AUDIO;
import static android.app.AppOpsManager.OP_RECORD_AUDIO;
import static android.content.Intent.EXTRA_PACKAGE_NAME;
import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
@@ -1067,6 +1068,10 @@
mAppOpsRestrictionToken);
mAppOpsManagerInternal.setGlobalRestriction(OP_PHONE_CALL_MICROPHONE, enabled,
mAppOpsRestrictionToken);
+ // We don't show the dialog for RECEIVE_SOUNDTRIGGER_AUDIO, but still want to
+ // restrict it when the microphone is disabled
+ mAppOpsManagerInternal.setGlobalRestriction(OP_RECEIVE_AMBIENT_TRIGGER_AUDIO,
+ enabled, mAppOpsRestrictionToken);
break;
case CAMERA:
mAppOpsManagerInternal.setGlobalRestriction(OP_CAMERA, enabled,
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java
index f3d151f..13fe14c 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java
@@ -41,6 +41,9 @@
import android.os.RemoteException;
import android.os.ServiceSpecificException;
+import com.android.server.LocalServices;
+import com.android.server.pm.permission.LegacyPermissionManagerInternal;
+
import java.io.PrintWriter;
import java.util.Objects;
@@ -120,8 +123,7 @@
* Throws a {@link SecurityException} iff the originator has permission to receive data.
*/
void enforcePermissionsForDataDelivery(@NonNull Identity identity, @NonNull String reason) {
- enforcePermissionForDataDelivery(mContext, identity, RECORD_AUDIO,
- reason);
+ enforceSoundTriggerRecordAudioPermissionForDataDelivery(identity, reason);
enforcePermissionForDataDelivery(mContext, identity, CAPTURE_AUDIO_HOTWORD,
reason);
}
@@ -147,6 +149,19 @@
}
}
+ private static void enforceSoundTriggerRecordAudioPermissionForDataDelivery(
+ @NonNull Identity identity, @NonNull String reason) {
+ LegacyPermissionManagerInternal lpmi =
+ LocalServices.getService(LegacyPermissionManagerInternal.class);
+ final int status = lpmi.checkSoundTriggerRecordAudioPermissionForDataDelivery(identity.uid,
+ identity.packageName, identity.attributionTag, reason);
+ if (status != PermissionChecker.PERMISSION_GRANTED) {
+ throw new SecurityException(
+ String.format("Failed to obtain permission RECORD_AUDIO for identity %s",
+ ObjectPrinter.print(identity, 16)));
+ }
+ }
+
/**
* Throws a {@link SecurityException} if originator permanently doesn't have the given
* permission.
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index 5e7b586..06646d3 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -204,6 +204,7 @@
import com.android.server.am.MemoryStatUtil.MemoryStat;
import com.android.server.health.HealthServiceWrapper;
import com.android.server.notification.NotificationManagerService;
+import com.android.server.pm.UserManagerInternal;
import com.android.server.stats.pull.IonMemoryUtil.IonAllocations;
import com.android.server.stats.pull.ProcfsMemoryUtil.MemorySnapshot;
import com.android.server.stats.pull.netstats.NetworkStatsExt;
@@ -4106,11 +4107,24 @@
// Incremental is not enabled on this device. The result list will be empty.
return StatsManager.PULL_SUCCESS;
}
- List<PackageInfo> installedPackages = pm.getInstalledPackages(0);
- for (PackageInfo pi : installedPackages) {
- if (IncrementalManager.isIncrementalPath(pi.applicationInfo.getBaseCodePath())) {
- pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag, pi.applicationInfo.uid));
+ final long token = Binder.clearCallingIdentity();
+ try {
+ int[] userIds = LocalServices.getService(UserManagerInternal.class).getUserIds();
+ for (int userId : userIds) {
+ List<PackageInfo> installedPackages = pm.getInstalledPackagesAsUser(0, userId);
+ for (PackageInfo pi : installedPackages) {
+ if (IncrementalManager.isIncrementalPath(
+ pi.applicationInfo.getBaseCodePath())) {
+ pulledData.add(
+ FrameworkStatsLog.buildStatsEvent(atomTag, pi.applicationInfo.uid));
+ }
+ }
}
+ } catch (Exception e) {
+ Slog.e(TAG, "failed to pullInstalledIncrementalPackagesLocked", e);
+ return StatsManager.PULL_SKIP;
+ } finally {
+ Binder.restoreCallingIdentity(token);
}
return StatsManager.PULL_SUCCESS;
}
@@ -4352,7 +4366,8 @@
}
RkpErrorStats atom = atomWrapper.payload.getRkpErrorStats();
pulledData.add(FrameworkStatsLog.buildStatsEvent(
- FrameworkStatsLog.RKP_ERROR_STATS, atom.rkpError, atomWrapper.count));
+ FrameworkStatsLog.RKP_ERROR_STATS, atom.rkpError, atomWrapper.count,
+ atom.security_level));
}
return StatsManager.PULL_SUCCESS;
}
diff --git a/services/core/java/com/android/server/timedetector/GnssTimeUpdateService.java b/services/core/java/com/android/server/timedetector/GnssTimeUpdateService.java
index fb75ae1..129810c 100644
--- a/services/core/java/com/android/server/timedetector/GnssTimeUpdateService.java
+++ b/services/core/java/com/android/server/timedetector/GnssTimeUpdateService.java
@@ -116,6 +116,11 @@
Log.d(TAG, "requestGnssTimeUpdates()");
}
+ if (!mLocationManager.hasProvider(LocationManager.GPS_PROVIDER)) {
+ Log.e(TAG, "GPS provider does not exist on this device");
+ return;
+ }
+
// Location Listener triggers onLocationChanged() when GNSS data is available, so
// that the getGnssTimeMillis() function doesn't need to be continuously polled.
mLocationListener = new LocationListener() {
diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java
index d7a0ca0..47aa587 100644
--- a/services/core/java/com/android/server/wm/ActivityClientController.java
+++ b/services/core/java/com/android/server/wm/ActivityClientController.java
@@ -246,6 +246,18 @@
}
@Override
+ public void activityLocalRelaunch(IBinder token) {
+ final long origId = Binder.clearCallingIdentity();
+ synchronized (mGlobalLock) {
+ final ActivityRecord r = ActivityRecord.forTokenLocked(token);
+ if (r != null) {
+ r.startRelaunching();
+ }
+ }
+ Binder.restoreCallingIdentity(origId);
+ }
+
+ @Override
public void activityRelaunched(IBinder token) {
final long origId = Binder.clearCallingIdentity();
synchronized (mGlobalLock) {
@@ -725,7 +737,7 @@
synchronized (mGlobalLock) {
final ActivityRecord r = ensureValidPictureInPictureActivityParams(
"enterPictureInPictureMode", token, params);
- return mService.enterPictureInPictureMode(r, params);
+ return mService.enterPictureInPictureMode(r, params, true /* fromClient */);
}
} finally {
Binder.restoreCallingIdentity(origId);
@@ -856,7 +868,8 @@
}
if (r.pictureInPictureArgs.isAutoEnterEnabled()) {
- return mService.enterPictureInPictureMode(r, r.pictureInPictureArgs);
+ return mService.enterPictureInPictureMode(r, r.pictureInPictureArgs,
+ false /* fromClient */);
}
try {
diff --git a/services/core/java/com/android/server/wm/ActivityInterceptorCallback.java b/services/core/java/com/android/server/wm/ActivityInterceptorCallback.java
index 3448395..48e6f97 100644
--- a/services/core/java/com/android/server/wm/ActivityInterceptorCallback.java
+++ b/services/core/java/com/android/server/wm/ActivityInterceptorCallback.java
@@ -59,7 +59,6 @@
@IntDef(suffix = { "_ORDERED_ID" }, value = {
FIRST_ORDERED_ID,
PERMISSION_POLICY_ORDERED_ID,
- INTENT_RESOLVER_ORDERED_ID,
VIRTUAL_DEVICE_SERVICE_ORDERED_ID,
DREAM_MANAGER_ORDERED_ID,
LAST_ORDERED_ID // Update this when adding new ids
@@ -78,11 +77,6 @@
public static final int PERMISSION_POLICY_ORDERED_ID = 1;
/**
- * The identifier for {@link com.android.server.pm.IntentResolverInterceptor}.
- */
- public static final int INTENT_RESOLVER_ORDERED_ID = 2;
-
- /**
* The identifier for {@link com.android.server.companion.virtual.VirtualDeviceManagerService}
* interceptor.
*/
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 9932272..baaf6f7 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -873,7 +873,7 @@
boolean mEnteringAnimation;
boolean mOverrideTaskTransition;
- boolean mDismissKeyguardIfInsecure;
+ boolean mDismissKeyguard;
boolean mAppStopped;
// A hint to override the window specified rotation animation, or -1 to use the window specified
@@ -926,6 +926,11 @@
private final ActivityRecordInputSink mActivityRecordInputSink;
+ // Activities with this uid are allowed to not create an input sink while being in the same
+ // task and directly above this ActivityRecord. This field is updated whenever a new activity
+ // is launched from this ActivityRecord. Touches are always allowed within the same uid.
+ int mAllowedTouchUid;
+
private final Runnable mPauseTimeoutRunnable = new Runnable() {
@Override
public void run() {
@@ -1987,7 +1992,7 @@
}
mOverrideTaskTransition = options.getOverrideTaskTransition();
- mDismissKeyguardIfInsecure = options.getDismissKeyguardIfInsecure();
+ mDismissKeyguard = options.getDismissKeyguard();
}
ColorDisplayService.ColorDisplayServiceInternal cds = LocalServices.getService(
@@ -2099,7 +2104,7 @@
}
mAtmService.mPackageConfigPersister.updateConfigIfNeeded(this, mUserId, packageName);
- mActivityRecordInputSink = new ActivityRecordInputSink(this);
+ mActivityRecordInputSink = new ActivityRecordInputSink(this, sourceRecord);
updateEnterpriseThumbnailDrawable(mAtmService.mUiContext);
}
@@ -2314,7 +2319,7 @@
final int type = getStartingWindowType(newTask, taskSwitch, processRunning,
allowTaskSnapshot, activityCreated, activityAllDrawn, snapshot);
- //TODO(191787740) Remove for T
+ //TODO(191787740) Remove for T+
final boolean useLegacy = type == STARTING_WINDOW_TYPE_SPLASH_SCREEN
&& mWmService.mStartingSurfaceController.isExceptionApp(packageName, mTargetSdk,
() -> {
@@ -2995,25 +3000,6 @@
&& info.supportsPictureInPicture();
}
- /**
- * @return whether this activity supports split-screen multi-window and can be put in
- * split-screen.
- */
- @Override
- public boolean supportsSplitScreenWindowingMode() {
- return supportsSplitScreenWindowingModeInDisplayArea(getDisplayArea());
- }
-
- /**
- * @return whether this activity supports split-screen multi-window and can be put in
- * split-screen if it is in the given {@link TaskDisplayArea}.
- */
- boolean supportsSplitScreenWindowingModeInDisplayArea(@Nullable TaskDisplayArea tda) {
- return super.supportsSplitScreenWindowingMode()
- && mAtmService.mSupportsSplitScreenMultiWindow
- && supportsMultiWindowInDisplayArea(tda);
- }
-
boolean supportsFreeform() {
return supportsFreeformInDisplayArea(getDisplayArea());
}
@@ -3532,7 +3518,7 @@
final ActivityRecord next = getDisplayArea().topRunningActivity(
true /* considerKeyguardState */);
- // If the finishing activity is the last activity of a organized TaskFragment and has an
+ // If the finishing activity is the last activity of an organized TaskFragment and has an
// adjacent TaskFragment, check if the activity removal should be delayed.
boolean delayRemoval = false;
final TaskFragment taskFragment = getTaskFragment();
@@ -3540,7 +3526,8 @@
final TaskFragment organized = taskFragment.getOrganizedTaskFragment();
final TaskFragment adjacent =
organized != null ? organized.getAdjacentTaskFragment() : null;
- if (adjacent != null && organized.topRunningActivity() == null) {
+ if (adjacent != null && next.isDescendantOf(adjacent)
+ && organized.topRunningActivity() == null) {
delayRemoval = organized.isDelayLastActivityRemoval();
}
}
@@ -5094,13 +5081,15 @@
// still check DC#okToAnimate again if the transition animation is fine to apply.
// TODO(new-app-transition): Rewrite this logic using WM Shell.
final boolean recentsAnimating = isAnimating(PARENTS, ANIMATION_TYPE_RECENTS);
+ final boolean isEnteringPipWithoutVisibleChange = mWaitForEnteringPinnedMode
+ && mVisible == visible;
if (okToAnimate(true /* ignoreFrozen */, canTurnScreenOn())
&& (appTransition.isTransitionSet()
|| (recentsAnimating && !isActivityTypeHome()))
- // If the visibility change during enter PIP, we don't want to include it in app
- // transition to affect the animation theme, because the Pip organizer will animate
- // the entering PIP instead.
- && !mWaitForEnteringPinnedMode) {
+ // If the visibility is not changed during enter PIP, we don't want to include it in
+ // app transition to affect the animation theme, because the Pip organizer will
+ // animate the entering PIP instead.
+ && !isEnteringPipWithoutVisibleChange) {
if (visible) {
displayContent.mOpeningApps.add(this);
mEnteringAnimation = true;
@@ -6342,8 +6331,10 @@
mSharedStartingData != null ? mSharedStartingData.mAssociatedTask : null;
if (associatedTask == null) {
removeStartingWindow();
- } else if (associatedTask.getActivity(
- r -> r.mVisibleRequested && !r.firstWindowDrawn) == null) {
+ } else if (associatedTask.getActivity(r -> r.mVisibleRequested && !r.firstWindowDrawn
+ // Don't block starting window removal if an Activity can't be a starting window
+ // target.
+ && r.mSharedStartingData != null) == null) {
// The last drawn activity may not be the one that owns the starting window.
final ActivityRecord r = associatedTask.topActivityContainsStartingWindow();
if (r != null) {
@@ -7727,7 +7718,7 @@
if (isFixedOrientationLetterboxAllowed || mCompatDisplayInsets != null
// In fullscreen, can be letterboxed for aspect ratio.
|| !inMultiWindowMode()) {
- updateResolvedBoundsHorizontalPosition(newParentConfiguration);
+ updateResolvedBoundsPosition(newParentConfiguration);
}
if (mVisibleRequested) {
@@ -7830,39 +7821,61 @@
}
/**
- * Adjusts horizontal position of resolved bounds if they doesn't fill the parent using gravity
+ * Adjusts position of resolved bounds if they doesn't fill the parent using gravity
* requested in the config or via an ADB command. For more context see {@link
- * LetterboxUiController#getHorizontalPositionMultiplier(Configuration)}.
+ * LetterboxUiController#getHorizontalPositionMultiplier(Configuration)} and
+ * {@link LetterboxUiController#getVerticalPositionMultiplier(Configuration)}
*/
- private void updateResolvedBoundsHorizontalPosition(Configuration newParentConfiguration) {
+ private void updateResolvedBoundsPosition(Configuration newParentConfiguration) {
final Configuration resolvedConfig = getResolvedOverrideConfiguration();
final Rect resolvedBounds = resolvedConfig.windowConfiguration.getBounds();
final Rect screenResolvedBounds =
mSizeCompatBounds != null ? mSizeCompatBounds : resolvedBounds;
final Rect parentAppBounds = newParentConfiguration.windowConfiguration.getAppBounds();
final Rect parentBounds = newParentConfiguration.windowConfiguration.getBounds();
- if (resolvedBounds.isEmpty() || parentBounds.width() == screenResolvedBounds.width()) {
+ if (resolvedBounds.isEmpty()) {
return;
}
-
+ // Horizontal position
int offsetX = 0;
- if (screenResolvedBounds.width() >= parentAppBounds.width()) {
- // If resolved bounds overlap with insets, center within app bounds.
- offsetX = getHorizontalCenterOffset(
- parentAppBounds.width(), screenResolvedBounds.width());
- } else {
- float positionMultiplier =
- mLetterboxUiController.getHorizontalPositionMultiplier(newParentConfiguration);
- offsetX = (int) Math.ceil((parentAppBounds.width() - screenResolvedBounds.width())
- * positionMultiplier);
+ if (parentBounds.width() != screenResolvedBounds.width()) {
+ if (screenResolvedBounds.width() >= parentAppBounds.width()) {
+ // If resolved bounds overlap with insets, center within app bounds.
+ offsetX = getCenterOffset(
+ parentAppBounds.width(), screenResolvedBounds.width());
+ } else {
+ float positionMultiplier =
+ mLetterboxUiController.getHorizontalPositionMultiplier(
+ newParentConfiguration);
+ offsetX = (int) Math.ceil((parentAppBounds.width() - screenResolvedBounds.width())
+ * positionMultiplier);
+ }
+ }
+
+ // Vertical position
+ int offsetY = 0;
+ if (parentBounds.height() != screenResolvedBounds.height()) {
+
+ if (screenResolvedBounds.height() >= parentAppBounds.height()) {
+ // If resolved bounds overlap with insets, center within app bounds.
+ offsetY = getCenterOffset(
+ parentAppBounds.height(), screenResolvedBounds.height());
+ } else {
+ float positionMultiplier =
+ mLetterboxUiController.getVerticalPositionMultiplier(
+ newParentConfiguration);
+ offsetY = (int) Math.ceil((parentAppBounds.height() - screenResolvedBounds.height())
+ * positionMultiplier);
+ }
}
if (mSizeCompatBounds != null) {
- mSizeCompatBounds.offset(offsetX, 0 /* offsetY */);
+ mSizeCompatBounds.offset(offsetX , offsetY);
+ final int dy = mSizeCompatBounds.top - resolvedBounds.top;
final int dx = mSizeCompatBounds.left - resolvedBounds.left;
- offsetBounds(resolvedConfig, dx, 0 /* offsetY */);
+ offsetBounds(resolvedConfig, dx, dy);
} else {
- offsetBounds(resolvedConfig, offsetX, 0 /* offsetY */);
+ offsetBounds(resolvedConfig, offsetX, offsetY);
}
// Since bounds has changed, the configuration needs to be computed accordingly.
@@ -7986,20 +7999,7 @@
// orientation with insets applied.
return;
}
- // Not using Task#isResizeable() or ActivityRecord#isResizeable() directly because app
- // compatibility testing showed that android:supportsPictureInPicture="true" alone is not
- // sufficient signal for not letterboxing an app.
- // TODO(214602463): Remove multi-window check since orientation and aspect ratio
- // restrictions should always be applied in multi-window.
- final boolean isResizeable = task != null
- // Activity should be resizable if the task is.
- ? task.isResizeable(/* checkPictureInPictureSupport */ false)
- || isResizeable(/* checkPictureInPictureSupport */ false)
- : isResizeable(/* checkPictureInPictureSupport */ false);
- if (WindowConfiguration.inMultiWindowMode(windowingMode) && isResizeable) {
- // Ignore orientation request for resizable apps in multi window.
- return;
- }
+
if (windowingMode == WINDOWING_MODE_PINNED) {
// PiP bounds have higher priority than the requested orientation. Otherwise the
// activity may be squeezed into a small piece.
@@ -8077,14 +8077,6 @@
mIsAspectRatioApplied = applyAspectRatio(resolvedBounds, containingBoundsWithInsets,
containingBounds, desiredAspectRatio, true);
- // Vertically center if orientation is landscape. Center within parent bounds with insets
- // to ensure that insets do not trim height. Bounds will later be horizontally centered in
- // {@link updateResolvedBoundsHorizontalPosition()} regardless of orientation.
- if (forcedOrientation == ORIENTATION_LANDSCAPE) {
- final int offsetY = parentBoundsWithInsets.centerY() - resolvedBounds.centerY();
- resolvedBounds.offset(0, offsetY);
- }
-
if (mCompatDisplayInsets != null) {
mCompatDisplayInsets.getBoundsByRotation(
mTmpBounds, newParentConfig.windowConfiguration.getRotation());
@@ -8107,10 +8099,9 @@
/**
* Resolves aspect ratio restrictions for an activity. If the bounds are restricted by
- * aspect ratio, the position will be adjusted later in {@link
- * updateResolvedBoundsHorizontalPosition} within parent's app bounds to balance the visual
- * appearance. The policy of aspect ratio has higher priority than the requested override
- * bounds.
+ * aspect ratio, the position will be adjusted later in {@link #updateResolvedBoundsPosition
+ * within parent's app bounds to balance the visual appearance. The policy of aspect ratio has
+ * higher priority than the requested override bounds.
*/
private void resolveAspectRatioRestriction(Configuration newParentConfiguration) {
final Configuration resolvedConfig = getResolvedOverrideConfiguration();
@@ -8122,7 +8113,7 @@
mTmpBounds.setEmpty();
mIsAspectRatioApplied = applyAspectRatio(mTmpBounds, parentAppBounds, parentBounds);
// If the out bounds is not empty, it means the activity cannot fill parent's app bounds,
- // then they should be aligned later in #updateResolvedBoundsHorizontalPosition().
+ // then they should be aligned later in #updateResolvedBoundsPosition()
if (!mTmpBounds.isEmpty()) {
resolvedBounds.set(mTmpBounds);
}
@@ -8256,22 +8247,11 @@
forAllWindows(WindowState::updateGlobalScale, false /* traverseTopToBottom */);
}
- // Vertically center within parent (bounds) - this is a UX choice and exclude the horizontal
- // decor if needed. Horizontal position is adjusted in
- // updateResolvedBoundsHorizontalPosition.
+ // The position will be later adjusted in updateResolvedBoundsPosition.
// Above coordinates are in "@" space, now place "*" and "#" to screen space.
final boolean fillContainer = resolvedBounds.equals(containingBounds);
final int screenPosX = fillContainer ? containerBounds.left : containerAppBounds.left;
- // If the activity is not in size compat mode, calculate vertical centering
- // from the container and resolved bounds.
- // If the activity is in size compat mode, calculate vertical centering
- // from the container and size compat bounds.
- // The container bounds contain the parent bounds offset in the display, for
- // example when an activity is in the lower split of split screen.
- final int screenPosY = (mSizeCompatBounds == null
- ? (containerBounds.height() - resolvedBounds.height()) / 2
- : (containerBounds.height() - mSizeCompatBounds.height()) / 2)
- + containerBounds.top;
+ final int screenPosY = fillContainer ? containerBounds.top : containerAppBounds.top;
if (screenPosX != 0 || screenPosY != 0) {
if (mSizeCompatBounds != null) {
@@ -8331,9 +8311,9 @@
return true;
}
- /** @return The horizontal offset of putting the content in the center of viewport. */
- private static int getHorizontalCenterOffset(int viewportW, int contentW) {
- return (int) ((viewportW - contentW + 1) * 0.5f);
+ /** @return The horizontal / vertical offset of putting the content in the center of viewport.*/
+ private static int getCenterOffset(int viewportDim, int contentDim) {
+ return (int) ((viewportDim - contentDim + 1) * 0.5f);
}
private static void offsetBounds(Configuration inOutConfig, int offsetX, int offsetY) {
@@ -9341,6 +9321,7 @@
sb.append(mUserId);
sb.append(' ');
sb.append(intent.getComponent().flattenToShortString());
+ sb.append("}");
stringName = sb.toString();
return stringName;
}
@@ -9595,7 +9576,7 @@
outBounds.bottom = dH;
outBounds.right = (int) ((float) dH * dH / dW);
}
- outBounds.offset(getHorizontalCenterOffset(mWidth, outBounds.width()), 0 /* dy */);
+ outBounds.offset(getCenterOffset(mWidth, outBounds.width()), 0 /* dy */);
}
outAppBounds.set(outBounds);
diff --git a/services/core/java/com/android/server/wm/ActivityRecordInputSink.java b/services/core/java/com/android/server/wm/ActivityRecordInputSink.java
index 23a8324..fc22e2d 100644
--- a/services/core/java/com/android/server/wm/ActivityRecordInputSink.java
+++ b/services/core/java/com/android/server/wm/ActivityRecordInputSink.java
@@ -42,14 +42,16 @@
private InputWindowHandleWrapper mInputWindowHandleWrapper;
private SurfaceControl mSurfaceControl;
- private boolean mDisabled = false;
- ActivityRecordInputSink(ActivityRecord activityRecord) {
+ ActivityRecordInputSink(ActivityRecord activityRecord, ActivityRecord sourceRecord) {
mActivityRecord = activityRecord;
mIsCompatEnabled = CompatChanges.isChangeEnabled(ENABLE_TOUCH_OPAQUE_ACTIVITIES,
mActivityRecord.getUid());
mName = Integer.toHexString(System.identityHashCode(this)) + " ActivityRecordInputSink "
+ mActivityRecord.mActivityComponent.flattenToShortString();
+ if (sourceRecord != null) {
+ sourceRecord.mAllowedTouchUid = mActivityRecord.getUid();
+ }
}
public void applyChangesToSurfaceIfChanged(SurfaceControl.Transaction transaction) {
@@ -77,8 +79,15 @@
if (mInputWindowHandleWrapper == null) {
mInputWindowHandleWrapper = new InputWindowHandleWrapper(createInputWindowHandle());
}
- if (mDisabled || !mIsCompatEnabled || mActivityRecord.isInTransition()) {
- // TODO(b/208662670): Investigate if we can have feature active during animations.
+ // Don't block touches from passing through to an activity below us in the same task, if
+ // that activity is either from the same uid or if that activity has launched an activity
+ // in our uid.
+ final ActivityRecord activityBelowInTask =
+ mActivityRecord.getTask().getActivityBelow(mActivityRecord);
+ final boolean allowPassthrough = activityBelowInTask != null && (
+ activityBelowInTask.mAllowedTouchUid == mActivityRecord.getUid()
+ || activityBelowInTask.isUid(mActivityRecord.getUid()));
+ if (allowPassthrough || !mIsCompatEnabled || mActivityRecord.isInTransition()) {
mInputWindowHandleWrapper.setInputConfigMasked(InputConfig.NOT_TOUCHABLE,
InputConfig.NOT_TOUCHABLE);
} else {
diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java
index 9771b34..94a77aa 100644
--- a/services/core/java/com/android/server/wm/ActivityStartController.java
+++ b/services/core/java/com/android/server/wm/ActivityStartController.java
@@ -228,8 +228,8 @@
vers = ri.activityInfo.applicationInfo.metaData.getString(
Intent.METADATA_SETUP_VERSION);
}
- String lastVers = Settings.Secure.getString(
- resolver, Settings.Secure.LAST_SETUP_SHOWN);
+ String lastVers = Settings.Secure.getStringForUser(
+ resolver, Settings.Secure.LAST_SETUP_SHOWN, resolver.getUserId());
if (vers != null && !vers.equals(lastVers)) {
intent.setFlags(FLAG_ACTIVITY_NEW_TASK);
intent.setComponent(new ComponentName(
@@ -528,6 +528,8 @@
.setRequestCode(-1)
.setCallingUid(callingUid)
.setCallingPid(callingPid)
+ .setRealCallingUid(callingUid)
+ .setRealCallingPid(callingPid)
.setUserId(caller != null ? caller.mUserId : mService.getCurrentUserId())
.execute();
}
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 85305cc..0d447e3 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -1674,6 +1674,7 @@
private @Nullable Task handleStartResult(@NonNull ActivityRecord started,
ActivityOptions options, int result, Transition newTransition,
RemoteTransition remoteTransition) {
+ final boolean userLeaving = mSupervisor.mUserLeaving;
mSupervisor.mUserLeaving = false;
final Task currentRootTask = started.getRootTask();
final Task startedActivityRootTask =
@@ -1747,7 +1748,7 @@
// until after we launched to identify the relevant activity.
transitionController.setTransientLaunch(mLastStartActivityRecord, mPriorAboveTask);
}
- if (!mSupervisor.mUserLeaving) {
+ if (!userLeaving) {
// no-user-leaving implies not entering PiP.
transitionController.setCanPipOnFinish(false /* canPipOnFinish */);
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 7524825..06242b3 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -95,6 +95,7 @@
import static com.android.server.am.EventLogTags.writeConfigurationChanged;
import static com.android.server.wm.ActivityInterceptorCallback.FIRST_ORDERED_ID;
import static com.android.server.wm.ActivityInterceptorCallback.LAST_ORDERED_ID;
+import static com.android.server.wm.ActivityRecord.State.PAUSING;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ALL;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_ROOT_TASK;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_SWITCH;
@@ -3449,10 +3450,12 @@
/**
* Puts the given activity in picture in picture mode if possible.
*
+ * @param fromClient true if this comes from a client call (eg. Activity.enterPip).
* @return true if the activity is now in picture-in-picture mode, or false if it could not
* enter picture-in-picture mode.
*/
- boolean enterPictureInPictureMode(@NonNull ActivityRecord r, PictureInPictureParams params) {
+ boolean enterPictureInPictureMode(@NonNull ActivityRecord r,
+ @NonNull PictureInPictureParams params, boolean fromClient) {
// If the activity is already in picture in picture mode, then just return early
if (r.inPinnedWindowingMode()) {
return true;
@@ -3465,9 +3468,17 @@
return false;
}
- // Create a transition for this pip entry. We guarantee that this gets its own transition
- // by queueing this transition on SyncEngine. This is shared by all the entry paths.
- final Transition transition = getTransitionController().isShellTransitionsEnabled()
+ // If the app is using legacy-entry (not auto-enter), then we will get a client-request
+ // that was actually a server-request (via pause(userLeaving=true)). This happens when
+ // the app is PAUSING, so detect that case here.
+ boolean originallyFromClient = fromClient
+ && (!r.isState(PAUSING) || params.isAutoEnterEnabled());
+
+ // Create a transition only for this pip entry if it is coming from the app without the
+ // system requesting that the app enter-pip. If the system requested it, that means it
+ // should be part of that transition if possible.
+ final Transition transition =
+ (getTransitionController().isShellTransitionsEnabled() && originallyFromClient)
? new Transition(TRANSIT_PIP, 0 /* flags */,
getTransitionController(), mWindowManager.mSyncEngine)
: null;
@@ -3498,7 +3509,7 @@
mActivityClientController.dismissKeyguard(r.token, new KeyguardDismissCallback() {
@Override
public void onDismissSucceeded() {
- if (mWindowManager.mSyncEngine.hasActiveSync()) {
+ if (transition != null && mWindowManager.mSyncEngine.hasActiveSync()) {
ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
"Creating Pending Pip-Enter: %s", transition);
mWindowManager.mSyncEngine.queueSyncSet(
@@ -3516,7 +3527,7 @@
}, null /* message */);
} else {
// Enter picture in picture immediately otherwise
- if (mWindowManager.mSyncEngine.hasActiveSync()) {
+ if (transition != null && mWindowManager.mSyncEngine.hasActiveSync()) {
ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
"Creating Pending Pip-Enter: %s", transition);
mWindowManager.mSyncEngine.queueSyncSet(
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index 4dd8a84..58864b1 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -71,6 +71,7 @@
import static com.android.server.wm.NonAppWindowAnimationAdapter.shouldAttachNavBarToApp;
import static com.android.server.wm.NonAppWindowAnimationAdapter.shouldStartNonAppWindowAnimationsForKeyguardExit;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION;
+import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS;
import static com.android.server.wm.WallpaperAnimationAdapter.shouldStartWallpaperAnimation;
import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
@@ -672,11 +673,16 @@
"Override with TaskFragment remote animation for transit=%s",
AppTransition.appTransitionOldToString(transit));
+ final int organizerUid = mDisplayContent.mAtmService.mTaskFragmentOrganizerController
+ .getTaskFragmentOrganizerUid(organizer);
+ final boolean shouldDisableInputForRemoteAnimation = !task.isFullyTrustedEmbedding(
+ organizerUid);
final RemoteAnimationController remoteAnimationController =
mDisplayContent.mAppTransition.getRemoteAnimationController();
- if (remoteAnimationController != null) {
+ if (shouldDisableInputForRemoteAnimation && remoteAnimationController != null) {
// We are going to use client-driven animation, Disable all input on activity windows
- // during the animation to ensure it is safe to allow client to animate the surfaces.
+ // during the animation (unless it is fully trusted) to ensure it is safe to allow
+ // client to animate the surfaces.
// This is needed for all activity windows in the animation Task.
remoteAnimationController.setOnRemoteAnimationReady(() -> {
final Consumer<ActivityRecord> updateActivities =
@@ -903,7 +909,11 @@
// We cannot promote the animation on Task's parent when the task is in
// clearing task in case the animating get stuck when performing the opening
// task that behind it.
- || (current.asTask() != null && current.asTask().mInRemoveTask)) {
+ || (current.asTask() != null && current.asTask().mInRemoveTask)
+ // We cannot promote the animation to changing window. This may happen when an
+ // activity is open in a TaskFragment that is resizing, while the existing
+ // activity in the TaskFragment is reparented to another TaskFragment.
+ || parent.isChangingAppTransition()) {
canPromote = false;
} else {
// In case a descendant of the parent belongs to the other group, we cannot promote
@@ -1152,13 +1162,17 @@
if (activity == null) {
continue;
}
+ if (activity.isAnimating(PARENTS, ANIMATION_TYPE_RECENTS)) {
+ ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
+ "Delaying app transition for recents animation to finish");
+ return false;
+ }
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
"Check opening app=%s: allDrawn=%b startingDisplayed=%b "
+ "startingMoved=%b isRelaunching()=%b startingWindow=%s",
activity, activity.allDrawn, activity.startingDisplayed,
activity.startingMoved, activity.isRelaunching(),
activity.mStartingWindow);
-
final boolean allDrawn = activity.allDrawn && !activity.isRelaunching();
if (!allDrawn && !activity.startingDisplayed && !activity.startingMoved) {
return false;
diff --git a/services/core/java/com/android/server/wm/ConfigurationContainer.java b/services/core/java/com/android/server/wm/ConfigurationContainer.java
index e7c03aa..1e8ec3a 100644
--- a/services/core/java/com/android/server/wm/ConfigurationContainer.java
+++ b/services/core/java/com/android/server/wm/ConfigurationContainer.java
@@ -478,14 +478,6 @@
return WindowConfiguration.inMultiWindowMode(windowingMode);
}
- /**
- * Returns true if this container supports split-screen multi-window and can be put in
- * split-screen based on its current state.
- */
- public boolean supportsSplitScreenWindowingMode() {
- return mFullConfiguration.windowConfiguration.supportSplitScreenWindowingMode();
- }
-
public boolean inPinnedWindowingMode() {
return mFullConfiguration.windowConfiguration.getWindowingMode() == WINDOWING_MODE_PINNED;
}
diff --git a/services/core/java/com/android/server/wm/Dimmer.java b/services/core/java/com/android/server/wm/Dimmer.java
index 029056a..e7ab63e 100644
--- a/services/core/java/com/android/server/wm/Dimmer.java
+++ b/services/core/java/com/android/server/wm/Dimmer.java
@@ -50,11 +50,16 @@
}
@Override
- public SurfaceControl.Transaction getPendingTransaction() {
+ public SurfaceControl.Transaction getSyncTransaction() {
return mHost.getSyncTransaction();
}
@Override
+ public SurfaceControl.Transaction getPendingTransaction() {
+ return mHost.getPendingTransaction();
+ }
+
+ @Override
public void commitPendingTransaction() {
mHost.commitPendingTransaction();
}
@@ -105,7 +110,7 @@
void removeSurface() {
if (mDimLayer != null && mDimLayer.isValid()) {
- getPendingTransaction().remove(mDimLayer);
+ getSyncTransaction().remove(mDimLayer);
}
mDimLayer = null;
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index f4543c0..16356c1 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -556,7 +556,8 @@
final FixedRotationTransitionListener mFixedRotationTransitionListener =
new FixedRotationTransitionListener();
- private PhysicalDisplaySwitchTransitionLauncher mDisplaySwitchTransitionLauncher;
+ private final PhysicalDisplaySwitchTransitionLauncher mDisplaySwitchTransitionLauncher;
+ final RemoteDisplayChangeController mRemoteDisplayChangeController;
/** Windows added since {@link #mCurrentFocus} was set to null. Used for ANR blaming. */
final ArrayList<WindowState> mWinAddedSinceNullFocus = new ArrayList<>();
@@ -1052,6 +1053,7 @@
mUnknownAppVisibilityController = new UnknownAppVisibilityController(mWmService, this);
mDisplaySwitchTransitionLauncher = new PhysicalDisplaySwitchTransitionLauncher(this,
mTransitionController);
+ mRemoteDisplayChangeController = new RemoteDisplayChangeController(mWmService, mDisplayId);
final InputChannel inputChannel = mWmService.mInputManager.monitorInput(
"PointerEventDispatcher" + mDisplayId, mDisplayId);
@@ -1433,7 +1435,7 @@
if (!isReady()) {
return;
}
- if (mDisplayRotation.isWaitingForRemoteRotation()) {
+ if (mRemoteDisplayChangeController.isWaitingForRemoteDisplayChange()) {
return;
}
@@ -1533,8 +1535,8 @@
config = new Configuration();
computeScreenConfiguration(config);
} else if (!(mTransitionController.isCollecting(this)
- // If waiting for a remote rotation, don't prematurely update configuration.
- || mDisplayRotation.isWaitingForRemoteRotation())) {
+ // 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.
@@ -1596,7 +1598,7 @@
boolean isSyncFinished() {
// Do not consider children because if they are requested to be synced, they should be
// added to sync group explicitly.
- return !mDisplayRotation.isWaitingForRemoteRotation();
+ return !mRemoteDisplayChangeController.isWaitingForRemoteDisplayChange();
}
/**
@@ -1829,8 +1831,8 @@
sendNewConfiguration();
return;
}
- if (mDisplayRotation.isWaitingForRemoteRotation()) {
- // There is pending rotation change to apply.
+ if (mRemoteDisplayChangeController.isWaitingForRemoteDisplayChange()) {
+ // There is pending display change to apply.
return;
}
// The orientation of display is not changed.
@@ -2210,9 +2212,9 @@
final float density = mDisplayMetrics.density;
outConfig.screenWidthDp = (int) (mDisplayPolicy.getConfigDisplayWidth(dw, dh, rotation,
- uiMode, displayCutout) / density);
+ uiMode, displayCutout) / density + 0.5f);
outConfig.screenHeightDp = (int) (mDisplayPolicy.getConfigDisplayHeight(dw, dh, rotation,
- uiMode, displayCutout) / density);
+ uiMode, displayCutout) / density + 0.5f);
outConfig.compatScreenWidthDp = (int) (outConfig.screenWidthDp / mCompatibleScreenScale);
outConfig.compatScreenHeightDp = (int) (outConfig.screenHeightDp / mCompatibleScreenScale);
@@ -2395,7 +2397,8 @@
sl = reduceConfigLayout(sl, Surface.ROTATION_90, density, unrotDh, unrotDw, uiMode);
sl = reduceConfigLayout(sl, Surface.ROTATION_180, density, unrotDw, unrotDh, uiMode);
sl = reduceConfigLayout(sl, Surface.ROTATION_270, density, unrotDh, unrotDw, uiMode);
- outConfig.smallestScreenWidthDp = (int)(displayInfo.smallestNominalAppWidth / density);
+ outConfig.smallestScreenWidthDp =
+ (int) (displayInfo.smallestNominalAppWidth / density + 0.5f);
outConfig.screenLayout = sl;
}
@@ -2417,8 +2420,8 @@
longSize = shortSize;
shortSize = tmp;
}
- longSize = (int)(longSize/density);
- shortSize = (int)(shortSize/density);
+ longSize = (int) (longSize / density + 0.5f);
+ shortSize = (int) (shortSize / density + 0.5f);
return Configuration.reduceScreenLayout(curLayout, longSize, shortSize);
}
@@ -2758,6 +2761,7 @@
private void updateBaseDisplayMetricsIfNeeded() {
// Get real display metrics without overrides from WM.
mWmService.mDisplayManagerInternal.getNonOverrideDisplayInfo(mDisplayId, mDisplayInfo);
+ final int currentRotation = getRotation();
final int orientation = mDisplayInfo.rotation;
final boolean rotated = (orientation == ROTATION_90 || orientation == ROTATION_270);
final int newWidth = rotated ? mDisplayInfo.logicalHeight : mDisplayInfo.logicalWidth;
@@ -2818,7 +2822,8 @@
reconfigureDisplayLocked();
if (physicalDisplayChanged) {
- mDisplaySwitchTransitionLauncher.onDisplayUpdated();
+ mDisplaySwitchTransitionLauncher.onDisplayUpdated(currentRotation, getRotation(),
+ getDisplayAreaInfo());
}
}
}
@@ -5281,7 +5286,7 @@
void prepareAppTransition(@WindowManager.TransitionType int transit,
@WindowManager.TransitionFlags int flags) {
final boolean prepared = mAppTransition.prepareAppTransition(transit, flags);
- if (prepared && okToAnimate()) {
+ if (prepared && okToAnimate() && transit != TRANSIT_NONE) {
mSkipAppTransitionAnimation = false;
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index d1ba77d..daeba96 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -652,17 +652,19 @@
mForceShowNavBarSettingsObserver = new ForceShowNavBarSettingsObserver(
mHandler, mContext);
- mForceShowNavBarSettingsObserver.setOnChangeRunnable(() -> {
- synchronized (mLock) {
- mForceShowNavigationBarEnabled =
- mForceShowNavBarSettingsObserver.isEnabled();
- updateSystemBarAttributes();
- }
- });
+ mForceShowNavBarSettingsObserver.setOnChangeRunnable(this::updateForceShowNavBarSettings);
mForceShowNavigationBarEnabled = mForceShowNavBarSettingsObserver.isEnabled();
mHandler.post(mForceShowNavBarSettingsObserver::register);
}
+ private void updateForceShowNavBarSettings() {
+ synchronized (mLock) {
+ mForceShowNavigationBarEnabled =
+ mForceShowNavBarSettingsObserver.isEnabled();
+ updateSystemBarAttributes();
+ }
+ }
+
/**
* Returns the first non-null alt bar window matching the given position.
*/
@@ -1204,7 +1206,8 @@
if (attrs.providesInsetsTypes != null) {
for (@InternalInsetsType int insetsType : attrs.providesInsetsTypes) {
final TriConsumer<DisplayFrames, WindowContainer, Rect> imeFrameProvider =
- (displayFrames, windowContainer, inOutFrame) -> {
+ win.getAttrs().providedInternalImeInsets != null
+ ? (displayFrames, windowContainer, inOutFrame) -> {
final Insets[] providedInternalImeInsets =
win.getLayoutingAttrs(displayFrames.mRotation)
.providedInternalImeInsets;
@@ -1213,7 +1216,7 @@
&& providedInternalImeInsets[insetsType] != null) {
inOutFrame.inset(providedInternalImeInsets[insetsType]);
}
- };
+ } : null;
switch (insetsType) {
case ITYPE_STATUS_BAR:
mStatusBarAlt = win;
@@ -1232,17 +1235,18 @@
mExtraNavBarAltPosition = getAltBarPosition(attrs);
break;
}
- mDisplayContent.setInsetProvider(insetsType, win, (displayFrames,
- windowContainer, inOutFrame) -> {
- final Insets[] providedInternalInsets = win.getLayoutingAttrs(
- displayFrames.mRotation).providedInternalInsets;
- if (providedInternalInsets != null
- && providedInternalInsets.length > insetsType
- && providedInternalInsets[insetsType] != null) {
- inOutFrame.inset(providedInternalInsets[insetsType]);
- }
- inOutFrame.inset(win.mGivenContentInsets);
- }, imeFrameProvider);
+ mDisplayContent.setInsetProvider(insetsType, win,
+ win.getAttrs().providedInternalInsets != null ? (displayFrames,
+ windowContainer, inOutFrame) -> {
+ final Insets[] providedInternalInsets = win.getLayoutingAttrs(
+ displayFrames.mRotation).providedInternalInsets;
+ if (providedInternalInsets != null
+ && providedInternalInsets.length > insetsType
+ && providedInternalInsets[insetsType] != null) {
+ inOutFrame.inset(providedInternalInsets[insetsType]);
+ }
+ inOutFrame.inset(win.mGivenContentInsets);
+ } : null, imeFrameProvider);
mInsetsSourceWindowsExceptIme.add(win);
}
}
@@ -1817,6 +1821,7 @@
*/
public void switchUser() {
updateCurrentUserResources();
+ updateForceShowNavBarSettings();
}
/**
@@ -2420,7 +2425,9 @@
private int updateSystemBarsLw(WindowState win, int disableFlags) {
final TaskDisplayArea defaultTaskDisplayArea = mDisplayContent.getDefaultTaskDisplayArea();
final boolean multiWindowTaskVisible =
- defaultTaskDisplayArea.isRootTaskVisible(WINDOWING_MODE_MULTI_WINDOW);
+ defaultTaskDisplayArea.getRootTask(task -> task.isVisible()
+ && task.getTopLeafTask().getWindowingMode() == WINDOWING_MODE_MULTI_WINDOW)
+ != null;
final boolean freeformRootTaskVisible =
defaultTaskDisplayArea.isRootTaskVisible(WINDOWING_MODE_FREEFORM);
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index 03e1429..e5ec4c3 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -51,14 +51,12 @@
import android.database.ContentObserver;
import android.hardware.power.Boost;
import android.os.Handler;
-import android.os.RemoteException;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.Slog;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
-import android.view.IDisplayWindowRotationCallback;
import android.view.IWindowManager;
import android.view.Surface;
import android.window.TransitionRequestInfo;
@@ -67,7 +65,6 @@
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.ProtoLog;
-import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.LocalServices;
import com.android.server.UiThread;
import com.android.server.policy.WindowManagerPolicy;
@@ -211,31 +208,6 @@
private boolean mDemoHdmiRotationLock;
private boolean mDemoRotationLock;
- private static final int REMOTE_ROTATION_TIMEOUT_MS = 800;
-
- private boolean mIsWaitingForRemoteRotation = false;
-
- private final Runnable mDisplayRotationHandlerTimeout =
- new Runnable() {
- @Override
- public void run() {
- continueRotation(mRotation, null /* transaction */);
- }
- };
-
- private final IDisplayWindowRotationCallback mRemoteRotationCallback =
- new IDisplayWindowRotationCallback.Stub() {
- @Override
- public void continueRotateDisplay(int targetRotation,
- WindowContainerTransaction t) {
- synchronized (mService.getWindowManagerLock()) {
- mService.mH.sendMessage(PooledLambda.obtainMessage(
- DisplayRotation::continueRotation, DisplayRotation.this,
- targetRotation, t));
- }
- }
- };
-
DisplayRotation(WindowManagerService service, DisplayContent displayContent) {
this(service, displayContent, displayContent.getDisplayPolicy(),
service.mDisplayWindowSettings, service.mContext, service.getWindowManagerLock());
@@ -511,6 +483,7 @@
final TransitionRequestInfo.DisplayChange change = wasCollecting ? null
: new TransitionRequestInfo.DisplayChange(mDisplayContent.getDisplayId(),
oldRotation, mRotation);
+
mDisplayContent.requestChangeTransitionIfNeeded(
ActivityInfo.CONFIG_WINDOW_CONFIGURATION, change);
if (wasCollecting) {
@@ -554,61 +527,39 @@
return null;
}
- /**
- * A Remote rotation is when we are waiting for some registered (remote)
- * {@link IDisplayWindowRotationController} to calculate and return some hierarchy operations
- * to perform in sync with the rotation.
- */
- boolean isWaitingForRemoteRotation() {
- return mIsWaitingForRemoteRotation;
- }
-
private void startRemoteRotation(int fromRotation, int toRotation) {
- if (mService.mDisplayRotationController == null) {
- return;
- }
- mIsWaitingForRemoteRotation = true;
- try {
- mService.mDisplayRotationController.onRotateDisplay(mDisplayContent.getDisplayId(),
- fromRotation, toRotation, mRemoteRotationCallback);
- mService.mH.removeCallbacks(mDisplayRotationHandlerTimeout);
- mService.mH.postDelayed(mDisplayRotationHandlerTimeout, REMOTE_ROTATION_TIMEOUT_MS);
- } catch (RemoteException e) {
- mIsWaitingForRemoteRotation = false;
- return;
- }
+ mDisplayContent.mRemoteDisplayChangeController.performRemoteDisplayChange(
+ fromRotation, toRotation, null /* newDisplayAreaInfo */,
+ (transaction) -> continueRotation(toRotation, transaction)
+ );
}
private void continueRotation(int targetRotation, WindowContainerTransaction t) {
- synchronized (mService.mGlobalLock) {
- if (targetRotation != mRotation || !mIsWaitingForRemoteRotation) {
- // Drop it, this is either coming from an outdated remote rotation; or, we've
- // already moved on.
- return;
- }
- mService.mH.removeCallbacks(mDisplayRotationHandlerTimeout);
- mIsWaitingForRemoteRotation = false;
+ if (targetRotation != mRotation) {
+ // Drop it, this is either coming from an outdated remote rotation; or, we've
+ // already moved on.
+ return;
+ }
- if (mDisplayContent.mTransitionController.isShellTransitionsEnabled()) {
- if (!mDisplayContent.mTransitionController.isCollecting()) {
- throw new IllegalStateException("Trying to rotate outside a transition");
- }
- mDisplayContent.mTransitionController.collect(mDisplayContent);
- // Go through all tasks and collect them before the rotation
- // TODO(shell-transitions): move collect() to onConfigurationChange once wallpaper
- // handling is synchronized.
- mDisplayContent.mTransitionController.collectForDisplayChange(mDisplayContent,
- null /* use collecting transition */);
+ if (mDisplayContent.mTransitionController.isShellTransitionsEnabled()) {
+ if (!mDisplayContent.mTransitionController.isCollecting()) {
+ throw new IllegalStateException("Trying to rotate outside a transition");
}
- mService.mAtmService.deferWindowLayout();
- try {
- mDisplayContent.sendNewConfiguration();
- if (t != null) {
- mService.mAtmService.mWindowOrganizerController.applyTransaction(t);
- }
- } finally {
- mService.mAtmService.continueWindowLayout();
+ mDisplayContent.mTransitionController.collect(mDisplayContent);
+ // Go through all tasks and collect them before the rotation
+ // TODO(shell-transitions): move collect() to onConfigurationChange once wallpaper
+ // handling is synchronized.
+ mDisplayContent.mTransitionController.collectForDisplayChange(mDisplayContent,
+ null /* use collecting transition */);
+ }
+ mService.mAtmService.deferWindowLayout();
+ try {
+ mDisplayContent.sendNewConfiguration();
+ if (t != null) {
+ mService.mAtmService.mWindowOrganizerController.applyTransaction(t);
}
+ } finally {
+ mService.mAtmService.continueWindowLayout();
}
}
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index ec47f7f..1a93b11 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -414,8 +414,22 @@
final IBinder focusToken = focus != null ? focus.mInputChannelToken : null;
if (focusToken == null) {
+ if (recentsAnimationInputConsumer != null
+ && recentsAnimationInputConsumer.mWindowHandle != null
+ && mInputFocus == recentsAnimationInputConsumer.mWindowHandle.token) {
+ // Avoid removing input focus from recentsAnimationInputConsumer.
+ // When the recents animation input consumer has the input focus,
+ // mInputFocus does not match to mDisplayContent.mCurrentFocus. Making it to be
+ // a special case, that do not remove the input focus from it when
+ // mDisplayContent.mCurrentFocus is null. This special case should be removed
+ // once recentAnimationInputConsumer is removed.
+ return;
+ }
// When an app is focused, but its window is not showing yet, remove the input focus
- // from the current window.
+ // from the current window. This enforces the input focus to match
+ // mDisplayContent.mCurrentFocus. However, if more special cases are discovered that
+ // the input focus and mDisplayContent.mCurrentFocus are expected to mismatch,
+ // the whole logic of how and when to revoke focus needs to be checked.
if (mDisplayContent.mFocusedApp != null && mInputFocus != null) {
ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "App %s is focused,"
+ " but the window is not ready. Start a transaction to remove focus from"
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index 5c8cfff..9e0d7b5 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -46,6 +46,7 @@
import android.app.ActivityTaskManager;
import android.app.StatusBarManager;
import android.app.WindowConfiguration;
+import android.content.res.Resources;
import android.graphics.Rect;
import android.util.ArrayMap;
import android.util.IntArray;
@@ -123,14 +124,17 @@
* Let remote insets controller control system bars regardless of other settings.
*/
private boolean mRemoteInsetsControllerControlsSystemBars;
+ private final boolean mHideNavBarForKeyboard;
private final float[] mTmpFloat9 = new float[9];
InsetsPolicy(InsetsStateController stateController, DisplayContent displayContent) {
mStateController = stateController;
mDisplayContent = displayContent;
mPolicy = displayContent.getDisplayPolicy();
- mRemoteInsetsControllerControlsSystemBars = mPolicy.getContext().getResources().getBoolean(
+ final Resources r = mPolicy.getContext().getResources();
+ mRemoteInsetsControllerControlsSystemBars = r.getBoolean(
R.bool.config_remoteInsetsControllerControlsSystemBars);
+ mHideNavBarForKeyboard = r.getBoolean(R.bool.config_hideNavBarForKeyboard);
}
boolean getRemoteInsetsControllerControlsSystemBars() {
@@ -428,13 +432,15 @@
private InsetsState adjustVisibilityForIme(WindowState w, InsetsState originalState,
boolean copyState) {
if (w.mIsImWindow) {
- // Navigation bar insets is always visible to IME.
+ // If navigation bar is not hidden by IME, IME should always receive visible
+ // navigation bar insets.
+ final boolean navVisible = !mHideNavBarForKeyboard;
final InsetsSource originalNavSource = originalState.peekSource(ITYPE_NAVIGATION_BAR);
- if (originalNavSource != null && !originalNavSource.isVisible()) {
+ if (originalNavSource != null && originalNavSource.isVisible() != navVisible) {
final InsetsState state = copyState ? new InsetsState(originalState)
: originalState;
final InsetsSource navSource = new InsetsSource(originalNavSource);
- navSource.setVisible(true);
+ navSource.setVisible(navVisible);
state.addSource(navSource);
return state;
}
@@ -573,8 +579,9 @@
private @Nullable InsetsControlTarget getNavControlTarget(@Nullable WindowState focusedWin,
boolean fake) {
final WindowState imeWin = mDisplayContent.mInputMethodWindow;
- if (imeWin != null && imeWin.isVisible()) {
- // Force showing navigation bar while IME is visible.
+ if (imeWin != null && imeWin.isVisible() && !mHideNavBarForKeyboard) {
+ // Force showing navigation bar while IME is visible and if navigation bar is not
+ // configured to be hidden by the IME.
return null;
}
if (!fake && isShowingTransientTypes(Type.navigationBars())) {
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index 9853d13..358e93d 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -82,6 +82,7 @@
private boolean mIsLeashReadyForDispatching;
private final Rect mSourceFrame = new Rect();
private final Rect mLastSourceFrame = new Rect();
+ private @NonNull Insets mInsetsHint = Insets.NONE;
private final Consumer<Transaction> mSetLeashPositionConsumer = t -> {
if (mControl != null) {
@@ -298,6 +299,7 @@
if (!insetsHint.equals(mControl.getInsetsHint())) {
changed = true;
mControl.setInsetsHint(insetsHint);
+ mInsetsHint = insetsHint;
}
mLastSourceFrame.set(mSource.getFrame());
}
@@ -433,8 +435,8 @@
final SurfaceControl leash = mAdapter.mCapturedLeash;
mControlTarget = target;
updateVisibility();
- mControl = new InsetsSourceControl(mSource.getType(), leash, surfacePosition,
- mSource.calculateInsets(mWindowContainer.getBounds(), true /* ignoreVisibility */));
+ mControl = new InsetsSourceControl(mSource.getType(), leash, surfacePosition, mInsetsHint);
+
ProtoLog.d(WM_DEBUG_WINDOW_INSETS,
"InsetsSource Control %s for target %s", mControl, mControlTarget);
}
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index 03ac7aa..4d971a9 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -621,9 +621,7 @@
mTopTurnScreenOnActivity = top;
}
- final boolean isKeyguardSecure = controller.mWindowManager.isKeyguardSecure(
- controller.mService.getCurrentUserId());
- if (top.mDismissKeyguardIfInsecure && mKeyguardShowing && !isKeyguardSecure) {
+ if (top.mDismissKeyguard && mKeyguardShowing) {
mKeyguardGoingAway = true;
} else if (top.canShowWhenLocked()) {
mTopOccludesActivity = top;
diff --git a/services/core/java/com/android/server/wm/Letterbox.java b/services/core/java/com/android/server/wm/Letterbox.java
index 40df02c..61c09cd 100644
--- a/services/core/java/com/android/server/wm/Letterbox.java
+++ b/services/core/java/com/android/server/wm/Letterbox.java
@@ -72,7 +72,8 @@
private final LetterboxSurface mFullWindowSurface = new LetterboxSurface("fullWindow");
private final LetterboxSurface[] mSurfaces = { mLeft, mTop, mRight, mBottom };
// Reachability gestures.
- private final IntConsumer mDoubleTapCallback;
+ private final IntConsumer mDoubleTapCallbackX;
+ private final IntConsumer mDoubleTapCallbackY;
/**
* Constructs a Letterbox.
@@ -86,7 +87,8 @@
Supplier<Boolean> hasWallpaperBackgroundSupplier,
Supplier<Integer> blurRadiusSupplier,
Supplier<Float> darkScrimAlphaSupplier,
- IntConsumer doubleTapCallback) {
+ IntConsumer doubleTapCallbackX,
+ IntConsumer doubleTapCallbackY) {
mSurfaceControlFactory = surfaceControlFactory;
mTransactionFactory = transactionFactory;
mAreCornersRounded = areCornersRounded;
@@ -94,7 +96,8 @@
mHasWallpaperBackgroundSupplier = hasWallpaperBackgroundSupplier;
mBlurRadiusSupplier = blurRadiusSupplier;
mDarkScrimAlphaSupplier = darkScrimAlphaSupplier;
- mDoubleTapCallback = doubleTapCallback;
+ mDoubleTapCallbackX = doubleTapCallbackX;
+ mDoubleTapCallbackY = doubleTapCallbackY;
}
/**
@@ -264,7 +267,8 @@
@Override
public boolean onDoubleTapEvent(MotionEvent e) {
if (e.getAction() == MotionEvent.ACTION_UP) {
- mDoubleTapCallback.accept((int) e.getX());
+ mDoubleTapCallbackX.accept((int) e.getX());
+ mDoubleTapCallbackY.accept((int) e.getY());
return true;
}
return false;
diff --git a/services/core/java/com/android/server/wm/LetterboxConfiguration.java b/services/core/java/com/android/server/wm/LetterboxConfiguration.java
index ad2767c..bef8da8 100644
--- a/services/core/java/com/android/server/wm/LetterboxConfiguration.java
+++ b/services/core/java/com/android/server/wm/LetterboxConfiguration.java
@@ -55,25 +55,48 @@
static final int LETTERBOX_BACKGROUND_WALLPAPER = 3;
/**
- * Enum for Letterbox reachability position types.
+ * Enum for Letterbox horizontal reachability position types.
*
* <p>Order from left to right is important since it's used in {@link
* #movePositionForReachabilityToNextRightStop} and {@link
* #movePositionForReachabilityToNextLeftStop}.
*/
@Retention(RetentionPolicy.SOURCE)
- @IntDef({LETTERBOX_REACHABILITY_POSITION_LEFT, LETTERBOX_REACHABILITY_POSITION_CENTER,
- LETTERBOX_REACHABILITY_POSITION_RIGHT})
- @interface LetterboxReachabilityPosition {};
+ @IntDef({LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT,
+ LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER,
+ LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_RIGHT})
+ @interface LetterboxHorizontalReachabilityPosition {};
/** Letterboxed app window is aligned to the left side. */
- static final int LETTERBOX_REACHABILITY_POSITION_LEFT = 0;
+ static final int LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT = 0;
/** Letterboxed app window is positioned in the horizontal center. */
- static final int LETTERBOX_REACHABILITY_POSITION_CENTER = 1;
+ static final int LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER = 1;
/** Letterboxed app window is aligned to the right side. */
- static final int LETTERBOX_REACHABILITY_POSITION_RIGHT = 2;
+ static final int LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_RIGHT = 2;
+
+ /**
+ * Enum for Letterbox vertical reachability position types.
+ *
+ * <p>Order from top to bottom is important since it's used in {@link
+ * #movePositionForReachabilityToNextBottomStop} and {@link
+ * #movePositionForReachabilityToNextTopStop}.
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP,
+ LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER,
+ LETTERBOX_VERTICAL_REACHABILITY_POSITION_BOTTOM})
+ @interface LetterboxVerticalReachabilityPosition {};
+
+ /** Letterboxed app window is aligned to the left side. */
+ static final int LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP = 0;
+
+ /** Letterboxed app window is positioned in the vertical center. */
+ static final int LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER = 1;
+
+ /** Letterboxed app window is aligned to the right side. */
+ static final int LETTERBOX_VERTICAL_REACHABILITY_POSITION_BOTTOM = 2;
final Context mContext;
@@ -106,25 +129,50 @@
// side of the screen and 1.0 to the right side.
private float mLetterboxHorizontalPositionMultiplier;
- // Default horizontal position the letterboxed app window when reachability is enabled and
- // an app is fullscreen in landscape device orientatio.
- // It is used as a starting point for mLetterboxPositionForReachability.
- @LetterboxReachabilityPosition
- private int mDefaultPositionForReachability;
+ // Vertical position of a center of the letterboxed app window. 0 corresponds to the top
+ // side of the screen and 1.0 to the bottom side.
+ private float mLetterboxVerticalPositionMultiplier;
- // Whether reachability repositioning is allowed for letterboxed fullscreen apps in landscape
- // device orientation.
- private boolean mIsReachabilityEnabled;
+ // Default horizontal position the letterboxed app window when horizontal reachability is
+ // enabled and an app is fullscreen in landscape device orientation.
+ // It is used as a starting point for mLetterboxPositionForHorizontalReachability.
+ @LetterboxHorizontalReachabilityPosition
+ private int mDefaultPositionForHorizontalReachability;
+
+ // Default vertical position the letterboxed app window when vertical reachability is enabled
+ // and an app is fullscreen in portrait device orientation.
+ // It is used as a starting point for mLetterboxPositionForVerticalReachability.
+ @LetterboxVerticalReachabilityPosition
+ private int mDefaultPositionForVerticalReachability;
+
+ // Whether horizontal reachability repositioning is allowed for letterboxed fullscreen apps in
+ // landscape device orientation.
+ private boolean mIsHorizontalReachabilityEnabled;
+
+ // Whether vertical reachability repositioning is allowed for letterboxed fullscreen apps in
+ // portrait device orientation.
+ private boolean mIsVerticalReachabilityEnabled;
+
// Horizontal position of a center of the letterboxed app window which is global to prevent
// "jumps" when switching between letterboxed apps. It's updated to reposition the app window
// in response to a double tap gesture (see LetterboxUiController#handleDoubleTap). Used in
// LetterboxUiController#getHorizontalPositionMultiplier which is called from
- // ActivityRecord#updateResolvedBoundsHorizontalPosition.
+ // ActivityRecord#updateResolvedBoundsPosition.
// TODO(b/199426138): Global reachability setting causes a jump when resuming an app from
// Overview after changing position in another app.
- @LetterboxReachabilityPosition
- private volatile int mLetterboxPositionForReachability;
+ @LetterboxHorizontalReachabilityPosition
+ private volatile int mLetterboxPositionForHorizontalReachability;
+
+ // Vertical position of a center of the letterboxed app window which is global to prevent
+ // "jumps" when switching between letterboxed apps. It's updated to reposition the app window
+ // in response to a double tap gesture (see LetterboxUiController#handleDoubleTap). Used in
+ // LetterboxUiController#getVerticalPositionMultiplier which is called from
+ // ActivityRecord#updateResolvedBoundsPosition.
+ // TODO(b/199426138): Global reachability setting causes a jump when resuming an app from
+ // Overview after changing position in another app.
+ @LetterboxVerticalReachabilityPosition
+ private volatile int mLetterboxPositionForVerticalReachability;
// Whether education is allowed for letterboxed fullscreen apps.
private boolean mIsEducationEnabled;
@@ -142,10 +190,16 @@
R.dimen.config_letterboxBackgroundWallaperDarkScrimAlpha);
mLetterboxHorizontalPositionMultiplier = mContext.getResources().getFloat(
R.dimen.config_letterboxHorizontalPositionMultiplier);
- mIsReachabilityEnabled = mContext.getResources().getBoolean(
- R.bool.config_letterboxIsReachabilityEnabled);
- mDefaultPositionForReachability = readLetterboxReachabilityPositionFromConfig(mContext);
- mLetterboxPositionForReachability = mDefaultPositionForReachability;
+ mIsHorizontalReachabilityEnabled = mContext.getResources().getBoolean(
+ R.bool.config_letterboxIsHorizontalReachabilityEnabled);
+ mIsVerticalReachabilityEnabled = mContext.getResources().getBoolean(
+ R.bool.config_letterboxIsVerticalReachabilityEnabled);
+ mDefaultPositionForHorizontalReachability =
+ readLetterboxHorizontalReachabilityPositionFromConfig(mContext);
+ mDefaultPositionForVerticalReachability =
+ readLetterboxVerticalReachabilityPositionFromConfig(mContext);
+ mLetterboxPositionForHorizontalReachability = mDefaultPositionForHorizontalReachability;
+ mLetterboxPositionForVerticalReachability = mDefaultPositionForVerticalReachability;
mIsEducationEnabled = mContext.getResources().getBoolean(
R.bool.config_letterboxIsEducationEnabled);
}
@@ -375,6 +429,19 @@
? 0.5f : mLetterboxHorizontalPositionMultiplier;
}
+ /*
+ * Gets vertical position of a center of the letterboxed app window specified
+ * in {@link com.android.internal.R.dimen.config_letterboxVerticalPositionMultiplier}
+ * or via an ADB command. 0 corresponds to the top side of the screen and 1 to the
+ * bottom side.
+ */
+ float getLetterboxVerticalPositionMultiplier() {
+ return (mLetterboxVerticalPositionMultiplier < 0.0f
+ || mLetterboxVerticalPositionMultiplier > 1.0f)
+ // Default to central position if invalid value is provided.
+ ? 0.5f : mLetterboxVerticalPositionMultiplier;
+ }
+
/**
* Overrides horizontal position of a center of the letterboxed app window. If given value < 0
* or > 1, then it and a value of {@link
@@ -386,6 +453,16 @@
}
/**
+ * Overrides vertical position of a center of the letterboxed app window. If given value < 0
+ * or > 1, then it and a value of {@link
+ * com.android.internal.R.dimen.config_letterboxVerticalPositionMultiplier} are ignored and
+ * central position (0.5) is used.
+ */
+ void setLetterboxVerticalPositionMultiplier(float multiplier) {
+ mLetterboxVerticalPositionMultiplier = multiplier;
+ }
+
+ /**
* Resets horizontal position of a center of the letterboxed app window to {@link
* com.android.internal.R.dimen.config_letterboxHorizontalPositionMultiplier}.
*/
@@ -394,65 +471,145 @@
com.android.internal.R.dimen.config_letterboxHorizontalPositionMultiplier);
}
- /*
- * Whether reachability repositioning is allowed for letterboxed fullscreen apps in landscape
- * device orientation.
+ /**
+ * Resets vertical position of a center of the letterboxed app window to {@link
+ * com.android.internal.R.dimen.config_letterboxVerticalPositionMultiplier}.
*/
- boolean getIsReachabilityEnabled() {
- return mIsReachabilityEnabled;
+ void resetLetterboxVerticalPositionMultiplier() {
+ mLetterboxVerticalPositionMultiplier = mContext.getResources().getFloat(
+ com.android.internal.R.dimen.config_letterboxVerticalPositionMultiplier);
}
- /**
- * Overrides whether reachability repositioning is allowed for letterboxed fullscreen apps in
+ /*
+ * Whether horizontal reachability repositioning is allowed for letterboxed fullscreen apps in
* landscape device orientation.
*/
- void setIsReachabilityEnabled(boolean enabled) {
- mIsReachabilityEnabled = enabled;
- }
-
- /**
- * Resets whether reachability repositioning is allowed for letterboxed fullscreen apps in
- * landscape device orientation to {@link R.bool.config_letterboxIsReachabilityEnabled}.
- */
- void resetIsReachabilityEnabled() {
- mIsReachabilityEnabled = mContext.getResources().getBoolean(
- R.bool.config_letterboxIsReachabilityEnabled);
+ boolean getIsHorizontalReachabilityEnabled() {
+ return mIsHorizontalReachabilityEnabled;
}
/*
- * Gets default horizontal position of the letterboxed app window when reachability is enabled.
- * Specified in {@link R.integer.config_letterboxDefaultPositionForReachability} or via an ADB
- * command.
+ * Whether vertical reachability repositioning is allowed for letterboxed fullscreen apps in
+ * portrait device orientation.
*/
- @LetterboxReachabilityPosition
- int getDefaultPositionForReachability() {
- return mDefaultPositionForReachability;
+ boolean getIsVerticalReachabilityEnabled() {
+ return mIsVerticalReachabilityEnabled;
}
/**
- * Overrides default horizonal position of the letterboxed app window when reachability
+ * Overrides whether horizontal reachability repositioning is allowed for letterboxed fullscreen
+ * apps in landscape device orientation.
+ */
+ void setIsHorizontalReachabilityEnabled(boolean enabled) {
+ mIsHorizontalReachabilityEnabled = enabled;
+ }
+
+ /**
+ * Overrides whether vertical reachability repositioning is allowed for letterboxed fullscreen
+ * apps in portrait device orientation.
+ */
+ void setIsVerticalReachabilityEnabled(boolean enabled) {
+ mIsVerticalReachabilityEnabled = enabled;
+ }
+
+ /**
+ * Resets whether horizontal reachability repositioning is allowed for letterboxed fullscreen
+ * apps in landscape device orientation to
+ * {@link R.bool.config_letterboxIsHorizontalReachabilityEnabled}.
+ */
+ void resetIsHorizontalReachabilityEnabled() {
+ mIsHorizontalReachabilityEnabled = mContext.getResources().getBoolean(
+ R.bool.config_letterboxIsHorizontalReachabilityEnabled);
+ }
+
+ /**
+ * Resets whether vertical reachability repositioning is allowed for letterboxed fullscreen apps
+ * in portrait device orientation to
+ * {@link R.bool.config_letterboxIsVerticalReachabilityEnabled}.
+ */
+ void resetIsVerticalReachabilityEnabled() {
+ mIsVerticalReachabilityEnabled = mContext.getResources().getBoolean(
+ R.bool.config_letterboxIsVerticalReachabilityEnabled);
+ }
+
+ /*
+ * Gets default horizontal position of the letterboxed app window when horizontal reachability
* is enabled.
+ *
+ * <p> Specified in {@link R.integer.config_letterboxDefaultPositionForHorizontalReachability}
+ * or via an ADB command.
*/
- void setDefaultPositionForReachability(@LetterboxReachabilityPosition int position) {
- mDefaultPositionForReachability = position;
+ @LetterboxHorizontalReachabilityPosition
+ int getDefaultPositionForHorizontalReachability() {
+ return mDefaultPositionForHorizontalReachability;
+ }
+
+ /*
+ * Gets default vertical position of the letterboxed app window when vertical reachability is
+ * enabled.
+ *
+ * <p> Specified in {@link R.integer.config_letterboxDefaultPositionForVerticalReachability} or
+ * via an ADB command.
+ */
+ @LetterboxVerticalReachabilityPosition
+ int getDefaultPositionForVerticalReachability() {
+ return mDefaultPositionForVerticalReachability;
}
/**
- * Resets default horizontal position of the letterboxed app window when reachability is
- * enabled to {@link R.integer.config_letterboxDefaultPositionForReachability}.
+ * Overrides default horizontal position of the letterboxed app window when horizontal
+ * reachability is enabled.
*/
- void resetDefaultPositionForReachability() {
- mDefaultPositionForReachability = readLetterboxReachabilityPositionFromConfig(mContext);
+ void setDefaultPositionForHorizontalReachability(
+ @LetterboxHorizontalReachabilityPosition int position) {
+ mDefaultPositionForHorizontalReachability = position;
}
- @LetterboxReachabilityPosition
- private static int readLetterboxReachabilityPositionFromConfig(Context context) {
+ /**
+ * Overrides default vertical position of the letterboxed app window when vertical
+ * reachability is enabled.
+ */
+ void setDefaultPositionForVerticalReachability(
+ @LetterboxVerticalReachabilityPosition int position) {
+ mDefaultPositionForVerticalReachability = position;
+ }
+
+ /**
+ * Resets default horizontal position of the letterboxed app window when horizontal reachability
+ * is enabled to {@link R.integer.config_letterboxDefaultPositionForHorizontalReachability}.
+ */
+ void resetDefaultPositionForHorizontalReachability() {
+ mDefaultPositionForHorizontalReachability =
+ readLetterboxHorizontalReachabilityPositionFromConfig(mContext);
+ }
+
+ /**
+ * Resets default vertical position of the letterboxed app window when vertical reachability
+ * is enabled to {@link R.integer.config_letterboxDefaultPositionForVerticalReachability}.
+ */
+ void resetDefaultPositionForVerticalReachability() {
+ mDefaultPositionForVerticalReachability =
+ readLetterboxVerticalReachabilityPositionFromConfig(mContext);
+ }
+
+ @LetterboxHorizontalReachabilityPosition
+ private static int readLetterboxHorizontalReachabilityPositionFromConfig(Context context) {
int position = context.getResources().getInteger(
- R.integer.config_letterboxDefaultPositionForReachability);
- return position == LETTERBOX_REACHABILITY_POSITION_LEFT
- || position == LETTERBOX_REACHABILITY_POSITION_CENTER
- || position == LETTERBOX_REACHABILITY_POSITION_RIGHT
- ? position : LETTERBOX_REACHABILITY_POSITION_CENTER;
+ R.integer.config_letterboxDefaultPositionForHorizontalReachability);
+ return position == LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT
+ || position == LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER
+ || position == LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_RIGHT
+ ? position : LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER;
+ }
+
+ @LetterboxVerticalReachabilityPosition
+ private static int readLetterboxVerticalReachabilityPositionFromConfig(Context context) {
+ int position = context.getResources().getInteger(
+ R.integer.config_letterboxDefaultPositionForVerticalReachability);
+ return position == LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP
+ || position == LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER
+ || position == LETTERBOX_VERTICAL_REACHABILITY_POSITION_BOTTOM
+ ? position : LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER;
}
/*
@@ -462,48 +619,108 @@
* <p>The position multiplier is changed after each double tap in the letterbox area.
*/
float getHorizontalMultiplierForReachability() {
- switch (mLetterboxPositionForReachability) {
- case LETTERBOX_REACHABILITY_POSITION_LEFT:
+ switch (mLetterboxPositionForHorizontalReachability) {
+ case LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT:
return 0.0f;
- case LETTERBOX_REACHABILITY_POSITION_CENTER:
+ case LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER:
return 0.5f;
- case LETTERBOX_REACHABILITY_POSITION_RIGHT:
+ case LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_RIGHT:
return 1.0f;
default:
throw new AssertionError(
- "Unexpected letterbox position type: " + mLetterboxPositionForReachability);
+ "Unexpected letterbox position type: "
+ + mLetterboxPositionForHorizontalReachability);
+ }
+ }
+ /*
+ * Gets vertical position of a center of the letterboxed app window when reachability
+ * is enabled specified. 0 corresponds to the top side of the screen and 1 to the bottom side.
+ *
+ * <p>The position multiplier is changed after each double tap in the letterbox area.
+ */
+ float getVerticalMultiplierForReachability() {
+ switch (mLetterboxPositionForVerticalReachability) {
+ case LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP:
+ return 0.0f;
+ case LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER:
+ return 0.5f;
+ case LETTERBOX_VERTICAL_REACHABILITY_POSITION_BOTTOM:
+ return 1.0f;
+ default:
+ throw new AssertionError(
+ "Unexpected letterbox position type: "
+ + mLetterboxPositionForVerticalReachability);
}
}
- /** Returns a string representing the given {@link LetterboxReachabilityPosition}. */
- static String letterboxReachabilityPositionToString(
- @LetterboxReachabilityPosition int position) {
+ /** Returns a string representing the given {@link LetterboxHorizontalReachabilityPosition}. */
+ static String letterboxHorizontalReachabilityPositionToString(
+ @LetterboxHorizontalReachabilityPosition int position) {
switch (position) {
- case LETTERBOX_REACHABILITY_POSITION_LEFT:
- return "LETTERBOX_REACHABILITY_POSITION_LEFT";
- case LETTERBOX_REACHABILITY_POSITION_CENTER:
- return "LETTERBOX_REACHABILITY_POSITION_CENTER";
- case LETTERBOX_REACHABILITY_POSITION_RIGHT:
- return "LETTERBOX_REACHABILITY_POSITION_RIGHT";
+ case LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT:
+ return "LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT";
+ case LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER:
+ return "LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER";
+ case LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_RIGHT:
+ return "LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_RIGHT";
default:
throw new AssertionError(
"Unexpected letterbox position type: " + position);
}
}
- /**
- * Changes letterbox position for reachability to the next available one on the right side.
- */
- void movePositionForReachabilityToNextRightStop() {
- mLetterboxPositionForReachability = Math.min(
- mLetterboxPositionForReachability + 1, LETTERBOX_REACHABILITY_POSITION_RIGHT);
+ /** Returns a string representing the given {@link LetterboxVerticalReachabilityPosition}. */
+ static String letterboxVerticalReachabilityPositionToString(
+ @LetterboxVerticalReachabilityPosition int position) {
+ switch (position) {
+ case LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP:
+ return "LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP";
+ case LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER:
+ return "LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER";
+ case LETTERBOX_VERTICAL_REACHABILITY_POSITION_BOTTOM:
+ return "LETTERBOX_VERTICAL_REACHABILITY_POSITION_BOTTOM";
+ default:
+ throw new AssertionError(
+ "Unexpected letterbox position type: " + position);
+ }
}
/**
- * Changes letterbox position for reachability to the next available one on the left side.
+ * Changes letterbox position for horizontal reachability to the next available one on the
+ * right side.
*/
- void movePositionForReachabilityToNextLeftStop() {
- mLetterboxPositionForReachability = Math.max(mLetterboxPositionForReachability - 1, 0);
+ void movePositionForHorizontalReachabilityToNextRightStop() {
+ mLetterboxPositionForHorizontalReachability = Math.min(
+ mLetterboxPositionForHorizontalReachability + 1,
+ LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_RIGHT);
+ }
+
+ /**
+ * Changes letterbox position for horizontal reachability to the next available one on the left
+ * side.
+ */
+ void movePositionForHorizontalReachabilityToNextLeftStop() {
+ mLetterboxPositionForHorizontalReachability =
+ Math.max(mLetterboxPositionForHorizontalReachability - 1, 0);
+ }
+
+ /**
+ * Changes letterbox position for vertical reachability to the next available one on the bottom
+ * side.
+ */
+ void movePositionForVerticalReachabilityToNextBottomStop() {
+ mLetterboxPositionForVerticalReachability = Math.min(
+ mLetterboxPositionForVerticalReachability + 1,
+ LETTERBOX_VERTICAL_REACHABILITY_POSITION_BOTTOM);
+ }
+
+ /**
+ * Changes letterbox position for vertical reachability to the next available one on the top
+ * side.
+ */
+ void movePositionForVerticalReachabilityToNextTopStop() {
+ mLetterboxPositionForVerticalReachability =
+ Math.max(mLetterboxPositionForVerticalReachability - 1, 0);
}
/**
diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java
index bb15d76..2015206 100644
--- a/services/core/java/com/android/server/wm/LetterboxUiController.java
+++ b/services/core/java/com/android/server/wm/LetterboxUiController.java
@@ -163,7 +163,8 @@
this::hasWallpaperBackgroudForLetterbox,
this::getLetterboxWallpaperBlurRadius,
this::getLetterboxWallpaperDarkScrimAlpha,
- this::handleDoubleTap);
+ this::handleHorizontalDoubleTap,
+ this::handleVerticalDoubleTap);
mLetterbox.attachInput(w);
}
mActivityRecord.getPosition(mTmpPoint);
@@ -193,17 +194,28 @@
float getHorizontalPositionMultiplier(Configuration parentConfiguration) {
// Don't check resolved configuration because it may not be updated yet during
// configuration change.
- return isReachabilityEnabled(parentConfiguration)
+ return isHorizontalReachabilityEnabled(parentConfiguration)
// Using the last global dynamic position to avoid "jumps" when moving
// between apps or activities.
? mLetterboxConfiguration.getHorizontalMultiplierForReachability()
: mLetterboxConfiguration.getLetterboxHorizontalPositionMultiplier();
}
+ float getVerticalPositionMultiplier(Configuration parentConfiguration) {
+ // Don't check resolved configuration because it may not be updated yet during
+ // configuration change.
+ return isVerticalReachabilityEnabled(parentConfiguration)
+ // Using the last global dynamic position to avoid "jumps" when moving
+ // between apps or activities.
+ ? mLetterboxConfiguration.getVerticalMultiplierForReachability()
+ : mLetterboxConfiguration.getLetterboxVerticalPositionMultiplier();
+ }
+
float getFixedOrientationLetterboxAspectRatio(Configuration parentConfiguration) {
// Don't check resolved windowing mode because it may not be updated yet during
// configuration change.
- if (!isReachabilityEnabled(parentConfiguration)) {
+ if (!isHorizontalReachabilityEnabled(parentConfiguration)
+ && !isVerticalReachabilityEnabled(parentConfiguration)) {
return mLetterboxConfiguration.getFixedOrientationLetterboxAspectRatio();
}
@@ -225,8 +237,8 @@
return mActivityRecord.mWmService.mContext.getResources();
}
- private void handleDoubleTap(int x) {
- if (!isReachabilityEnabled() || mActivityRecord.isInTransition()) {
+ private void handleHorizontalDoubleTap(int x) {
+ if (!isHorizontalReachabilityEnabled() || mActivityRecord.isInTransition()) {
return;
}
@@ -237,10 +249,32 @@
if (mLetterbox.getInnerFrame().left > x) {
// Moving to the next stop on the left side of the app window: right > center > left.
- mLetterboxConfiguration.movePositionForReachabilityToNextLeftStop();
+ mLetterboxConfiguration.movePositionForHorizontalReachabilityToNextLeftStop();
} else if (mLetterbox.getInnerFrame().right < x) {
// Moving to the next stop on the right side of the app window: left > center > right.
- mLetterboxConfiguration.movePositionForReachabilityToNextRightStop();
+ mLetterboxConfiguration.movePositionForHorizontalReachabilityToNextRightStop();
+ }
+
+ // TODO(197549949): Add animation for transition.
+ mActivityRecord.recomputeConfiguration();
+ }
+
+ private void handleVerticalDoubleTap(int y) {
+ if (!isVerticalReachabilityEnabled() || mActivityRecord.isInTransition()) {
+ return;
+ }
+
+ if (mLetterbox.getInnerFrame().top <= y && mLetterbox.getInnerFrame().bottom >= y) {
+ // Only react to clicks at the top and bottom of the letterboxed app window.
+ return;
+ }
+
+ if (mLetterbox.getInnerFrame().top > y) {
+ // Moving to the next stop on the top side of the app window: bottom > center > top.
+ mLetterboxConfiguration.movePositionForVerticalReachabilityToNextTopStop();
+ } else if (mLetterbox.getInnerFrame().bottom < y) {
+ // Moving to the next stop on the bottom side of the app window: top > center > bottom.
+ mLetterboxConfiguration.movePositionForVerticalReachabilityToNextBottomStop();
}
// TODO(197549949): Add animation for transition.
@@ -248,25 +282,47 @@
}
/**
- * Whether reachability is enabled for an activity in the curren configuration.
+ * Whether horizontal reachability is enabled for an activity in the current configuration.
*
* <p>Conditions that needs to be met:
* <ul>
* <li>Activity is portrait-only.
* <li>Fullscreen window in landscape device orientation.
- * <li>Reachability is enabled.
+ * <li>Horizontal Reachability is enabled.
* </ul>
*/
- private boolean isReachabilityEnabled(Configuration parentConfiguration) {
- return mLetterboxConfiguration.getIsReachabilityEnabled()
+ private boolean isHorizontalReachabilityEnabled(Configuration parentConfiguration) {
+ return mLetterboxConfiguration.getIsHorizontalReachabilityEnabled()
&& parentConfiguration.windowConfiguration.getWindowingMode()
== WINDOWING_MODE_FULLSCREEN
- && parentConfiguration.orientation == ORIENTATION_LANDSCAPE
- && mActivityRecord.getRequestedConfigurationOrientation() == ORIENTATION_PORTRAIT;
+ && (parentConfiguration.orientation == ORIENTATION_LANDSCAPE
+ && mActivityRecord.getRequestedConfigurationOrientation() == ORIENTATION_PORTRAIT);
}
- private boolean isReachabilityEnabled() {
- return isReachabilityEnabled(mActivityRecord.getParent().getConfiguration());
+ private boolean isHorizontalReachabilityEnabled() {
+ return isHorizontalReachabilityEnabled(mActivityRecord.getParent().getConfiguration());
+ }
+
+ /**
+ * Whether vertical reachability is enabled for an activity in the current configuration.
+ *
+ * <p>Conditions that needs to be met:
+ * <ul>
+ * <li>Activity is landscape-only.
+ * <li>Fullscreen window in portrait device orientation.
+ * <li>Vertical Reachability is enabled.
+ * </ul>
+ */
+ private boolean isVerticalReachabilityEnabled(Configuration parentConfiguration) {
+ return mLetterboxConfiguration.getIsVerticalReachabilityEnabled()
+ && parentConfiguration.windowConfiguration.getWindowingMode()
+ == WINDOWING_MODE_FULLSCREEN
+ && (parentConfiguration.orientation == ORIENTATION_PORTRAIT
+ && mActivityRecord.getRequestedConfigurationOrientation() == ORIENTATION_LANDSCAPE);
+ }
+
+ private boolean isVerticalReachabilityEnabled() {
+ return isVerticalReachabilityEnabled(mActivityRecord.getParent().getConfiguration());
}
@VisibleForTesting
@@ -474,9 +530,13 @@
+ getLetterboxWallpaperBlurRadius());
}
- pw.println(prefix + " isReachabilityEnabled=" + isReachabilityEnabled());
+ pw.println(prefix + " isHorizontalReachabilityEnabled="
+ + isHorizontalReachabilityEnabled());
+ pw.println(prefix + " isVerticalReachabilityEnabled=" + isVerticalReachabilityEnabled());
pw.println(prefix + " letterboxHorizontalPositionMultiplier="
+ getHorizontalPositionMultiplier(mActivityRecord.getParent().getConfiguration()));
+ pw.println(prefix + " letterboxVerticalPositionMultiplier="
+ + getVerticalPositionMultiplier(mActivityRecord.getParent().getConfiguration()));
pw.println(prefix + " fixedOrientationLetterboxAspectRatio="
+ getFixedOrientationLetterboxAspectRatio(
mActivityRecord.getParent().getConfiguration()));
diff --git a/services/core/java/com/android/server/wm/LockTaskController.java b/services/core/java/com/android/server/wm/LockTaskController.java
index 160fc95..7a055d2 100644
--- a/services/core/java/com/android/server/wm/LockTaskController.java
+++ b/services/core/java/com/android/server/wm/LockTaskController.java
@@ -64,6 +64,7 @@
import com.android.internal.policy.IKeyguardDismissCallback;
import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.statusbar.IStatusBarService;
+import com.android.internal.telephony.CellBroadcastUtils;
import com.android.internal.widget.LockPatternUtils;
import com.android.server.LocalServices;
import com.android.server.am.ActivityManagerService;
@@ -392,6 +393,10 @@
return false;
}
+ if (isWirelessEmergencyAlert(intent)) {
+ return false;
+ }
+
return !(isTaskAuthAllowlisted(taskAuth) || mLockTaskModeTasks.isEmpty());
}
@@ -424,6 +429,25 @@
return isPackageAllowlisted(userId, packageName);
}
+ private boolean isWirelessEmergencyAlert(Intent intent) {
+ if (intent == null) {
+ return false;
+ }
+
+ final ComponentName cellBroadcastAlertDialogComponentName =
+ CellBroadcastUtils.getDefaultCellBroadcastAlertDialogComponent(mContext);
+
+ if (cellBroadcastAlertDialogComponentName == null) {
+ return false;
+ }
+
+ if (cellBroadcastAlertDialogComponentName.equals(intent.getComponent())) {
+ return true;
+ }
+
+ return false;
+ }
+
private boolean isEmergencyCallIntent(Intent intent) {
if (intent == null) {
return false;
diff --git a/services/core/java/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncher.java b/services/core/java/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncher.java
index 9c1d560..d209f08 100644
--- a/services/core/java/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncher.java
+++ b/services/core/java/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncher.java
@@ -22,17 +22,21 @@
import static com.android.server.wm.ActivityTaskManagerService.POWER_MODE_REASON_CHANGE_DISPLAY;
import android.animation.ValueAnimator;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.Context;
import android.graphics.Rect;
import android.hardware.devicestate.DeviceStateManager;
import android.os.HandlerExecutor;
+import android.window.DisplayAreaInfo;
import android.window.TransitionRequestInfo;
+import android.window.WindowContainerTransaction;
public class PhysicalDisplaySwitchTransitionLauncher {
private final DisplayContent mDisplayContent;
+ private final WindowManagerService mService;
private final DeviceStateManager mDeviceStateManager;
- private final Context mContext;
private final TransitionController mTransitionController;
private DeviceStateListener mDeviceStateListener;
@@ -46,13 +50,13 @@
public PhysicalDisplaySwitchTransitionLauncher(DisplayContent displayContent,
TransitionController transitionController) {
mDisplayContent = displayContent;
- mContext = mDisplayContent.mWmService.mContext;
+ mService = displayContent.mWmService;
mTransitionController = transitionController;
- mDeviceStateManager = mContext.getSystemService(DeviceStateManager.class);
+ mDeviceStateManager = mService.mContext.getSystemService(DeviceStateManager.class);
if (mDeviceStateManager != null) {
- mDeviceStateListener = new DeviceStateListener(mContext);
+ mDeviceStateListener = new DeviceStateListener(mService.mContext);
mDeviceStateManager
.registerCallback(new HandlerExecutor(mDisplayContent.mWmService.mH),
mDeviceStateListener);
@@ -74,7 +78,7 @@
if (!mDisplayContent.getLastHasContent()) return;
boolean shouldRequestUnfoldTransition = !mIsFolded
- && mContext.getResources().getBoolean(config_unfoldTransitionEnabled)
+ && mService.mContext.getResources().getBoolean(config_unfoldTransitionEnabled)
&& ValueAnimator.areAnimatorsEnabled();
if (!shouldRequestUnfoldTransition) {
@@ -102,13 +106,44 @@
}
}
- public void onDisplayUpdated() {
- if (mTransition != null) {
- mTransition.setAllReady();
- mTransition = null;
+ /**
+ * Called when physical display is getting updated, this could happen e.g. on foldable
+ * devices when the physical underlying display is replaced.
+ *
+ * @param fromRotation rotation before the display change
+ * @param toRotation rotation after the display change
+ * @param newDisplayAreaInfo display area info after the display change
+ */
+ public void onDisplayUpdated(int fromRotation, int toRotation,
+ @NonNull DisplayAreaInfo newDisplayAreaInfo) {
+ if (mTransition == null) return;
+
+ final boolean started = mDisplayContent.mRemoteDisplayChangeController
+ .performRemoteDisplayChange(fromRotation, toRotation, newDisplayAreaInfo,
+ this::continueDisplayUpdate);
+
+ if (!started) {
+ markTransitionAsReady();
}
}
+ private void continueDisplayUpdate(@Nullable WindowContainerTransaction transaction) {
+ if (mTransition == null) return;
+
+ if (transaction != null) {
+ mService.mAtmService.mWindowOrganizerController.applyTransaction(transaction);
+ }
+
+ markTransitionAsReady();
+ }
+
+ private void markTransitionAsReady() {
+ if (mTransition == null) return;
+
+ mTransition.setAllReady();
+ mTransition = null;
+ }
+
class DeviceStateListener extends DeviceStateManager.FoldStateListener {
DeviceStateListener(Context context) {
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 2bae59a..b61af2f 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -1197,7 +1197,10 @@
* this is the target task, CLOSING otherwise).
*/
RemoteAnimationTarget createRemoteAnimationTarget(int overrideTaskId, int overrideMode) {
- final ActivityRecord topApp = mTask.getTopVisibleActivity();
+ ActivityRecord topApp = mTask.getTopRealVisibleActivity();
+ if (topApp == null) {
+ topApp = mTask.getTopVisibleActivity();
+ }
final WindowState mainWindow = topApp != null
? topApp.findMainWindow()
: null;
diff --git a/services/core/java/com/android/server/wm/RemoteDisplayChangeController.java b/services/core/java/com/android/server/wm/RemoteDisplayChangeController.java
new file mode 100644
index 0000000..43baebc
--- /dev/null
+++ b/services/core/java/com/android/server/wm/RemoteDisplayChangeController.java
@@ -0,0 +1,171 @@
+/*
+ * 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;
+
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.RemoteException;
+import android.util.Slog;
+import android.view.IDisplayChangeWindowCallback;
+import android.window.DisplayAreaInfo;
+import android.window.WindowContainerTransaction;
+
+import com.android.internal.protolog.common.ProtoLog;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A helper class, a wrapper around {@link android.view.IDisplayChangeWindowController} to perform
+ * a synchronous display change in other parts (e.g. in the Shell) and continue the process
+ * in the system server. It handles timeouts and multiple requests.
+ * We have an instance of this controller for each display.
+ */
+public class RemoteDisplayChangeController {
+
+ private static final String TAG = "RemoteDisplayChangeController";
+
+ private static final int REMOTE_DISPLAY_CHANGE_TIMEOUT_MS = 800;
+
+ private final WindowManagerService mService;
+ private final int mDisplayId;
+
+ private final Runnable mTimeoutRunnable = this::onContinueTimedOut;
+
+ // all remote changes that haven't finished yet.
+ private final List<ContinueRemoteDisplayChangeCallback> mCallbacks = new ArrayList<>();
+
+ public RemoteDisplayChangeController(WindowManagerService service, int displayId) {
+ mService = service;
+ mDisplayId = displayId;
+ }
+
+ /**
+ * A Remote change is when we are waiting for some registered (remote)
+ * {@link IDisplayChangeWindowController} to calculate and return some hierarchy operations
+ * to perform in sync with the display change.
+ */
+ public boolean isWaitingForRemoteDisplayChange() {
+ return !mCallbacks.isEmpty();
+ }
+
+ /**
+ * Starts remote display change
+ * @param fromRotation rotation before the change
+ * @param toRotation rotation after the change
+ * @param newDisplayAreaInfo display area info after change
+ * @param callback that will be called after completing remote display change
+ * @return true if the change successfully started, false otherwise
+ */
+ public boolean performRemoteDisplayChange(
+ int fromRotation, int toRotation,
+ @Nullable DisplayAreaInfo newDisplayAreaInfo,
+ ContinueRemoteDisplayChangeCallback callback) {
+ if (mService.mDisplayChangeController == null) {
+ return false;
+ }
+ mCallbacks.add(callback);
+
+ if (newDisplayAreaInfo != null) {
+ ProtoLog.v(WM_DEBUG_CONFIGURATION,
+ "Starting remote display change: "
+ + "from [rot = %d], "
+ + "to [%dx%d, rot = %d]",
+ fromRotation,
+ newDisplayAreaInfo.configuration.windowConfiguration
+ .getMaxBounds().width(),
+ newDisplayAreaInfo.configuration.windowConfiguration
+ .getMaxBounds().height(),
+ toRotation);
+ }
+
+ final IDisplayChangeWindowCallback remoteCallback = createCallback(callback);
+ try {
+ mService.mH.removeCallbacks(mTimeoutRunnable);
+ mService.mH.postDelayed(mTimeoutRunnable, REMOTE_DISPLAY_CHANGE_TIMEOUT_MS);
+ mService.mDisplayChangeController.onDisplayChange(mDisplayId, fromRotation, toRotation,
+ newDisplayAreaInfo, remoteCallback);
+ return true;
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Exception while dispatching remote display-change", e);
+ mCallbacks.remove(callback);
+ return false;
+ }
+ }
+
+ private void onContinueTimedOut() {
+ Slog.e(TAG, "RemoteDisplayChange timed-out, UI might get messed-up after this.");
+ // timed-out, so run all continue callbacks and clear the list
+ synchronized (mService.mGlobalLock) {
+ for (int i = 0; i < mCallbacks.size(); ++i) {
+ mCallbacks.get(i).onContinueRemoteDisplayChange(null /* transaction */);
+ }
+ mCallbacks.clear();
+ }
+ }
+
+ private void continueDisplayChange(@NonNull ContinueRemoteDisplayChangeCallback callback,
+ @Nullable WindowContainerTransaction transaction) {
+ synchronized (mService.mGlobalLock) {
+ int idx = mCallbacks.indexOf(callback);
+ if (idx < 0) {
+ // already called this callback or a more-recent one (eg. via timeout)
+ return;
+ }
+ for (int i = 0; i < idx; ++i) {
+ // Expect remote callbacks in order. If they don't come in order, then force
+ // ordering by continuing everything up until this one with empty transactions.
+ mCallbacks.get(i).onContinueRemoteDisplayChange(null /* transaction */);
+ }
+ mCallbacks.subList(0, idx + 1).clear();
+ if (mCallbacks.isEmpty()) {
+ mService.mH.removeCallbacks(mTimeoutRunnable);
+ }
+ callback.onContinueRemoteDisplayChange(transaction);
+ }
+ }
+
+ private IDisplayChangeWindowCallback createCallback(
+ @NonNull ContinueRemoteDisplayChangeCallback callback) {
+ return new IDisplayChangeWindowCallback.Stub() {
+ @Override
+ public void continueDisplayChange(WindowContainerTransaction t) {
+ synchronized (mService.mGlobalLock) {
+ if (!mCallbacks.contains(callback)) {
+ // already ran this callback or a more-recent one.
+ return;
+ }
+ mService.mH.post(() -> RemoteDisplayChangeController.this
+ .continueDisplayChange(callback, t));
+ }
+ }
+ };
+ }
+
+ /**
+ * Callback interface to handle continuation of the remote display change
+ */
+ public interface ContinueRemoteDisplayChangeCallback {
+ /**
+ * This method is called when the remote display change has been applied
+ * @param transaction window changes collected by the remote display change
+ */
+ void onContinueRemoteDisplayChange(@Nullable WindowContainerTransaction transaction);
+ }
+}
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index ff18d68..9b44960 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -2004,7 +2004,10 @@
final Task rootPinnedTask = taskDisplayArea.getRootPinnedTask();
if (rootPinnedTask != null) {
transitionController.collect(rootPinnedTask);
- rootPinnedTask.dismissPip();
+ // The new ActivityRecord should replace the existing PiP, so it's more desirable
+ // that the old PiP disappears instead of turning to full-screen at the same time,
+ // as the Task#dismissPip is trying to do.
+ removeRootTasksInWindowingModes(WINDOWING_MODE_PINNED);
}
// Set a transition to ensure that we don't immediately try and update the visibility
@@ -3242,7 +3245,7 @@
if (task.getActivity(activity -> !activity.finishing && activity.mUserId == userId)
!= null) {
mService.getTaskChangeNotificationController().notifyTaskProfileLocked(
- task.mTaskId, userId);
+ task.getTaskInfo());
}
}, true /* traverseTopToBottom */);
}
diff --git a/services/core/java/com/android/server/wm/SafeActivityOptions.java b/services/core/java/com/android/server/wm/SafeActivityOptions.java
index 2d4aef6..fd05f19 100644
--- a/services/core/java/com/android/server/wm/SafeActivityOptions.java
+++ b/services/core/java/com/android/server/wm/SafeActivityOptions.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static android.Manifest.permission.CONTROL_KEYGUARD;
import static android.Manifest.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS;
import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
import static android.Manifest.permission.STATUS_BAR_SERVICE;
@@ -297,6 +298,20 @@
}
}
+ // Check if the caller is allowed to dismiss keyguard.
+ final boolean dismissKeyguard = options.getDismissKeyguard();
+ if (aInfo != null && dismissKeyguard) {
+ final int controlKeyguardPerm = ActivityTaskManagerService.checkPermission(
+ CONTROL_KEYGUARD, callingPid, callingUid);
+ if (controlKeyguardPerm != PERMISSION_GRANTED) {
+ final String msg = "Permission Denial: starting " + getIntentString(intent)
+ + " from " + callerApp + " (pid=" + callingPid
+ + ", uid=" + callingUid + ") with dismissKeyguard=true";
+ Slog.w(TAG, msg);
+ throw new SecurityException(msg);
+ }
+ }
+
// Check permission for remote animations
final RemoteAnimationAdapter adapter = options.getRemoteAnimationAdapter();
if (adapter != null && supervisor.mService.checkPermission(
diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
index b4029d1..518bfd4 100644
--- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -565,6 +565,7 @@
private SimpleSurfaceAnimatable.Builder initializeBuilder() {
return new SimpleSurfaceAnimatable.Builder()
+ .setSyncTransactionSupplier(mDisplayContent::getSyncTransaction)
.setPendingTransactionSupplier(mDisplayContent::getPendingTransaction)
.setCommitTransactionRunnable(mDisplayContent::commitPendingTransaction)
.setAnimationLeashSupplier(mDisplayContent::makeOverlay);
diff --git a/services/core/java/com/android/server/wm/SimpleSurfaceAnimatable.java b/services/core/java/com/android/server/wm/SimpleSurfaceAnimatable.java
index bf5d5e2..3b3db89 100644
--- a/services/core/java/com/android/server/wm/SimpleSurfaceAnimatable.java
+++ b/services/core/java/com/android/server/wm/SimpleSurfaceAnimatable.java
@@ -41,6 +41,7 @@
private final SurfaceControl mParentSurfaceControl;
private final Runnable mCommitTransactionRunnable;
private final Supplier<SurfaceControl.Builder> mAnimationLeashFactory;
+ private final Supplier<SurfaceControl.Transaction> mSyncTransaction;
private final Supplier<SurfaceControl.Transaction> mPendingTransaction;
private final BiConsumer<SurfaceControl.Transaction, SurfaceControl> mOnAnimationLeashCreated;
private final Consumer<SurfaceControl.Transaction> mOnAnimationLeashLost;
@@ -60,10 +61,16 @@
mAnimationLeashFactory = builder.mAnimationLeashFactory;
mOnAnimationLeashCreated = builder.mOnAnimationLeashCreated;
mOnAnimationLeashLost = builder.mOnAnimationLeashLost;
+ mSyncTransaction = builder.mSyncTransactionSupplier;
mPendingTransaction = builder.mPendingTransactionSupplier;
mOnAnimationFinished = builder.mOnAnimationFinished;
}
+ @Override
+ public SurfaceControl.Transaction getSyncTransaction() {
+ return mSyncTransaction.get();
+ }
+
@NonNull
@Override
public SurfaceControl.Transaction getPendingTransaction() {
@@ -160,6 +167,9 @@
private Consumer<Runnable> mOnAnimationFinished = null;
@NonNull
+ private Supplier<SurfaceControl.Transaction> mSyncTransactionSupplier;
+
+ @NonNull
private Supplier<SurfaceControl.Transaction> mPendingTransactionSupplier;
@NonNull
@@ -207,6 +217,15 @@
}
/**
+ * @see SurfaceAnimator.Animatable#getSyncTransaction()
+ */
+ public Builder setSyncTransactionSupplier(
+ @NonNull Supplier<SurfaceControl.Transaction> syncTransactionSupplier) {
+ mSyncTransactionSupplier = syncTransactionSupplier;
+ return this;
+ }
+
+ /**
* @see SurfaceAnimator.Animatable#getPendingTransaction()
*/
public Builder setPendingTransactionSupplier(
@@ -290,6 +309,9 @@
}
public SurfaceAnimator.Animatable build() {
+ if (mSyncTransactionSupplier == null) {
+ throw new IllegalArgumentException("mSyncTransactionSupplier cannot be null");
+ }
if (mPendingTransactionSupplier == null) {
throw new IllegalArgumentException("mPendingTransactionSupplier cannot be null");
}
diff --git a/services/core/java/com/android/server/wm/SplashScreenExceptionList.java b/services/core/java/com/android/server/wm/SplashScreenExceptionList.java
index 9ca49fe..b3cd3f0 100644
--- a/services/core/java/com/android/server/wm/SplashScreenExceptionList.java
+++ b/services/core/java/com/android/server/wm/SplashScreenExceptionList.java
@@ -70,7 +70,7 @@
}
/**
- * Returns true if the packageName is in the list and the target sdk is before S.
+ * Returns true if the packageName is in the list and the target sdk is before or including T.
*
* @param packageName The package name of the application to check
* @param targetSdk The target sdk of the application
@@ -82,7 +82,7 @@
@SuppressWarnings("AndroidFrameworkCompatChange") // Target sdk check
public boolean isException(@NonNull String packageName, int targetSdk,
@Nullable Supplier<ApplicationInfo> infoSupplier) {
- if (targetSdk >= Build.VERSION_CODES.S) {
+ if (targetSdk > Build.VERSION_CODES.TIRAMISU) {
return false;
}
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java
index fbf0426..3dde2f1 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimator.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java
@@ -128,7 +128,7 @@
}
final OnAnimationFinishedCallback animationFinishCallback =
mSurfaceAnimationFinishedCallback;
- reset(mAnimatable.getPendingTransaction(), true /* destroyLeash */);
+ reset(mAnimatable.getSyncTransaction(), true /* destroyLeash */);
if (staticAnimationFinishedCallback != null) {
staticAnimationFinishedCallback.onAnimationFinished(type, anim);
}
@@ -234,7 +234,7 @@
final boolean delayed = mAnimationStartDelayed;
mAnimationStartDelayed = false;
if (delayed && mAnimation != null) {
- mAnimation.startAnimation(mLeash, mAnimatable.getPendingTransaction(),
+ mAnimation.startAnimation(mLeash, mAnimatable.getSyncTransaction(),
mAnimationType, mInnerAnimationFinishedCallback);
mAnimatable.commitPendingTransaction();
}
@@ -264,7 +264,7 @@
* Cancels any currently running animation.
*/
void cancelAnimation() {
- cancelAnimation(mAnimatable.getPendingTransaction(), false /* restarting */,
+ cancelAnimation(mAnimatable.getSyncTransaction(), false /* restarting */,
true /* forwardCancel */);
mAnimatable.commitPendingTransaction();
}
@@ -319,7 +319,7 @@
return;
}
endDelayingAnimationStart();
- final Transaction t = mAnimatable.getPendingTransaction();
+ final Transaction t = mAnimatable.getSyncTransaction();
cancelAnimation(t, true /* restarting */, true /* forwardCancel */);
mLeash = from.mLeash;
mAnimation = from.mAnimation;
@@ -620,6 +620,12 @@
interface Animatable {
/**
+ * Use this method instead of {@link #getPendingTransaction()} if the transaction should be
+ * synchronized with the client.
+ */
+ @NonNull Transaction getSyncTransaction();
+
+ /**
* @return The pending transaction that will be committed in the next frame.
*/
@NonNull Transaction getPendingTransaction();
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index ded5beb..4a643ef 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -197,6 +197,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IVoiceInteractor;
+import com.android.internal.protolog.ProtoLogGroup;
import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.util.XmlUtils;
import com.android.internal.util.function.pooled.PooledConsumer;
@@ -1696,23 +1697,6 @@
lockTaskAuthToString());
}
- @Override
- public boolean supportsSplitScreenWindowingMode() {
- return supportsSplitScreenWindowingModeInDisplayArea(getDisplayArea());
- }
-
- boolean supportsSplitScreenWindowingModeInDisplayArea(@Nullable TaskDisplayArea tda) {
- final Task topTask = getTopMostTask();
- return super.supportsSplitScreenWindowingMode()
- && (topTask == null || topTask.supportsSplitScreenWindowingModeInner(tda));
- }
-
- private boolean supportsSplitScreenWindowingModeInner(@Nullable TaskDisplayArea tda) {
- return super.supportsSplitScreenWindowingMode()
- && mAtmService.mSupportsSplitScreenMultiWindow
- && supportsMultiWindowInDisplayArea(tda);
- }
-
boolean supportsFreeform() {
return supportsFreeformInDisplayArea(getDisplayArea());
}
@@ -2020,10 +2004,6 @@
Rect outOverrideBounds = getResolvedOverrideConfiguration().windowConfiguration.getBounds();
if (windowingMode == WINDOWING_MODE_FULLSCREEN) {
- if (!isOrganized()) {
- // Use empty bounds to indicate "fill parent".
- outOverrideBounds.setEmpty();
- }
// The bounds for fullscreen mode shouldn't be adjusted by minimal size. Otherwise if
// the parent or display is smaller than the size, the content may be cropped.
return;
@@ -3058,11 +3038,22 @@
});
}
+ /**
+ * Return the top visible requested activity. The activity has been requested to be visible,
+ * but it's possible that the activity has just been created, so no window is yet attached to
+ * this activity.
+ */
ActivityRecord getTopVisibleActivity() {
- return getActivity((r) -> {
- // skip hidden (or about to hide) apps
- return !r.mIsExiting && r.isClientVisible() && r.mVisibleRequested;
- });
+ return getActivity((r) -> !r.mIsExiting && r.isClientVisible() && r.mVisibleRequested);
+ }
+
+ /**
+ * Return the top visible activity. The activity has a window on which contents are drawn.
+ * However it's possible that the activity has already been requested to be invisible, but the
+ * visibility is not yet committed.
+ */
+ ActivityRecord getTopRealVisibleActivity() {
+ return getActivity((r) -> !r.mIsExiting && r.isClientVisible() && r.isVisible());
}
ActivityRecord getTopWaitSplashScreenActivity() {
@@ -3385,9 +3376,7 @@
info.realActivity = realActivity;
info.lastActiveTime = lastActiveTime;
info.taskDescription = new ActivityManager.TaskDescription(getTaskDescription());
- info.supportsSplitScreenMultiWindow = supportsSplitScreenWindowingModeInDisplayArea(tda);
- info.supportsMultiWindow = info.supportsSplitScreenMultiWindow
- || supportsMultiWindowInDisplayArea(tda);
+ info.supportsMultiWindow = supportsMultiWindowInDisplayArea(tda);
info.configuration.setTo(getConfiguration());
// Update to the task's current activity type and windowing mode which may differ from the
// window configuration
@@ -5507,23 +5496,10 @@
}
}
- /**
- * Worker method for rearranging history task. Implements the function of moving all
- * activities for a specific task (gathering them if disjoint) into a single group at the
- * bottom of the root task.
- *
- * If a watcher is installed, the action is preflighted and the watcher has an opportunity
- * to premeptively cancel the move.
- *
- * @param tr The task to collect and move to the bottom.
- * @return Returns true if the move completed, false if not.
- */
- boolean moveTaskToBack(Task tr) {
- Slog.i(TAG, "moveTaskToBack: " + tr);
-
+ private boolean canMoveTaskToBack(Task task) {
// In LockTask mode, moving a locked task to the back of the root task may expose unlocked
// ones. Therefore we need to check if this operation is allowed.
- if (!mAtmService.getLockTaskController().canMoveTaskToBack(tr)) {
+ if (!mAtmService.getLockTaskController().canMoveTaskToBack(task)) {
return false;
}
@@ -5531,7 +5507,7 @@
// for *other* available tasks, but if none are available, then try again allowing the
// current task to be selected.
if (isTopRootTaskInDisplayArea() && mAtmService.mController != null) {
- ActivityRecord next = topRunningActivity(null, tr.mTaskId);
+ ActivityRecord next = topRunningActivity(null, task.mTaskId);
if (next == null) {
next = topRunningActivity(null, INVALID_TASK_ID);
}
@@ -5549,15 +5525,70 @@
}
}
}
+ return true;
+ }
+
+ /**
+ * Worker method for rearranging history task. Implements the function of moving all
+ * activities for a specific task (gathering them if disjoint) into a single group at the
+ * bottom of the root task.
+ *
+ * If a watcher is installed, the action is preflighted and the watcher has an opportunity
+ * to premeptively cancel the move.
+ *
+ * If this is a pinned task, it will be removed instead of rearranged.
+ *
+ * @param tr The task to collect and move to the bottom.
+ * @return Returns true if the move completed, false if not.
+ */
+ boolean moveTaskToBack(Task tr) {
+ Slog.i(TAG, "moveTaskToBack: " + tr);
+
+ if (!canMoveTaskToBack(tr)) return false;
if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare to back transition: task="
+ tr.mTaskId);
- // Skip the transition for pinned task.
- if (!inPinnedWindowingMode()) {
- mDisplayContent.requestTransitionAndLegacyPrepare(TRANSIT_TO_BACK, tr);
+ if (mTransitionController.isShellTransitionsEnabled()) {
+ final Transition transition = new Transition(TRANSIT_TO_BACK, 0 /* flags */,
+ mTransitionController, mWmService.mSyncEngine);
+ // Guarantee that this gets its own transition by queueing on SyncEngine
+ if (mWmService.mSyncEngine.hasActiveSync()) {
+ ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
+ "Creating Pending Move-to-back: %s", transition);
+ mWmService.mSyncEngine.queueSyncSet(
+ () -> mTransitionController.moveToCollecting(transition),
+ () -> {
+ mTransitionController.requestStartTransition(transition, tr,
+ null /* remoteTransition */, null /* displayChange */);
+ // Need to check again since this happens later and the system might
+ // be in a different state.
+ if (!canMoveTaskToBack(tr)) {
+ Slog.e(TAG, "Failed to move task to back after saying we could: "
+ + tr.mTaskId);
+ transition.abort();
+ return;
+ }
+ moveTaskToBackInner(tr);
+ });
+ } else {
+ mTransitionController.moveToCollecting(transition);
+ mTransitionController.requestStartTransition(transition, tr,
+ null /* remoteTransition */, null /* displayChange */);
+ moveTaskToBackInner(tr);
+ }
+ } else {
+ // Skip the transition for pinned task.
+ if (!inPinnedWindowingMode()) {
+ mDisplayContent.prepareAppTransition(TRANSIT_TO_BACK);
+ }
+ moveTaskToBackInner(tr);
}
- moveToBack("moveTaskToBackLocked", tr);
+ return true;
+ }
+
+ private boolean moveTaskToBackInner(@NonNull Task task) {
+ moveToBack("moveTaskToBackInner", task);
if (inPinnedWindowingMode()) {
mTaskSupervisor.removeRootTask(this);
diff --git a/services/core/java/com/android/server/wm/TaskChangeNotificationController.java b/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
index 61963c4..49d064f 100644
--- a/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
+++ b/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
@@ -144,7 +144,7 @@
};
private final TaskStackConsumer mNotifyTaskProfileLocked = (l, m) -> {
- l.onTaskProfileLocked(m.arg1, m.arg2);
+ l.onTaskProfileLocked((RunningTaskInfo) m.obj);
};
private final TaskStackConsumer mNotifyTaskSnapshotChanged = (l, m) -> {
@@ -467,9 +467,9 @@
* Notify listeners that the task has been put in a locked state because one or more of the
* activities inside it belong to a managed profile user that has been locked.
*/
- void notifyTaskProfileLocked(int taskId, int userId) {
- final Message msg = mHandler.obtainMessage(NOTIFY_TASK_PROFILE_LOCKED_LISTENERS_MSG, taskId,
- userId);
+ void notifyTaskProfileLocked(ActivityManager.RunningTaskInfo taskInfo) {
+ final Message msg = mHandler.obtainMessage(NOTIFY_TASK_PROFILE_LOCKED_LISTENERS_MSG,
+ taskInfo);
forAllLocalListeners(mNotifyTaskProfileLocked, msg);
msg.sendToTarget();
}
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index f8a0274..a9e80af 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -656,12 +656,14 @@
}
// Apps and their containers are not allowed to specify an orientation of non floating
- // visible tasks created by organizer. The organizer handles the orientation instead.
+ // visible tasks created by organizer and that has an adjacent task.
final Task nonFloatingTopTask =
- getRootTask(t -> !t.getWindowConfiguration().tasksAreFloating());
- if (nonFloatingTopTask != null && nonFloatingTopTask.mCreatedByOrganizer
- && nonFloatingTopTask.isVisible()) {
- return SCREEN_ORIENTATION_UNSPECIFIED;
+ getTask(t -> !t.getWindowConfiguration().tasksAreFloating());
+ if (nonFloatingTopTask != null) {
+ final Task task = nonFloatingTopTask.getCreatedByOrganizerTask();
+ if (task != null && task.getAdjacentTaskFragment() != null && task.isVisible()) {
+ return SCREEN_ORIENTATION_UNSPECIFIED;
+ }
}
final int orientation = super.getOrientation(candidate);
@@ -1898,15 +1900,12 @@
task.remove(false /* withTransition */, "removeTaskDisplayArea");
} else {
// Reparent task to corresponding launch root or display area.
- final WindowContainer launchRoot =
- task.supportsSplitScreenWindowingModeInDisplayArea(toDisplayArea)
- ? toDisplayArea.getLaunchRootTask(
+ final WindowContainer launchRoot = toDisplayArea.getLaunchRootTask(
task.getWindowingMode(),
task.getActivityType(),
null /* options */,
null /* sourceTask */,
- 0 /* launchFlags */)
- : null;
+ 0 /* launchFlags */);
task.reparent(launchRoot == null ? toDisplayArea : launchRoot, POSITION_TOP);
// Set the windowing mode to undefined by default to let the root task inherited the
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 9c7a27c..5972d78 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -562,13 +562,7 @@
* @param uid uid of the TaskFragment organizer.
*/
boolean isAllowedToEmbedActivityInTrustedMode(@NonNull ActivityRecord a, int uid) {
- if (UserHandle.getAppId(uid) == SYSTEM_UID) {
- // The system is trusted to embed other apps securely and for all users.
- return true;
- }
-
- if (uid == a.getUid()) {
- // Activities from the same UID can be embedded freely by the host.
+ if (isFullyTrustedEmbedding(a, uid)) {
return true;
}
@@ -587,13 +581,34 @@
}
/**
+ * It is fully trusted for embedding in the system app or embedding in the same app. This is
+ * different from {@link #isAllowedToBeEmbeddedInTrustedMode()} since there may be a small
+ * chance for a previous trusted app to start doing something bad.
+ */
+ private static boolean isFullyTrustedEmbedding(@NonNull ActivityRecord a, int uid) {
+ // The system is trusted to embed other apps securely and for all users.
+ return UserHandle.getAppId(uid) == SYSTEM_UID
+ // Activities from the same UID can be embedded freely by the host.
+ || uid == a.getUid();
+ }
+
+ /**
+ * Checks if all activities in the task fragment are embedded as fully trusted.
+ * @see #isFullyTrustedEmbedding(ActivityRecord, int)
+ * @param uid uid of the TaskFragment organizer.
+ */
+ boolean isFullyTrustedEmbedding(int uid) {
+ // Traverse all activities to see if any of them are not fully trusted embedding.
+ return !forAllActivities(r -> !isFullyTrustedEmbedding(r, uid));
+ }
+
+ /**
* Checks if all activities in the task fragment are allowed to be embedded in trusted mode.
* @see #isAllowedToEmbedActivityInTrustedMode(ActivityRecord)
*/
boolean isAllowedToBeEmbeddedInTrustedMode() {
// Traverse all activities to see if any of them are not in the trusted mode.
- final Predicate<ActivityRecord> callback = r -> !isAllowedToEmbedActivityInTrustedMode(r);
- return !forAllActivities(callback);
+ return !forAllActivities(r -> !isAllowedToEmbedActivityInTrustedMode(r));
}
/**
@@ -1518,7 +1533,7 @@
if (prev.attachedToProcess()) {
if (shouldAutoPip) {
boolean didAutoPip = mAtmService.enterPictureInPictureMode(
- prev, prev.pictureInPictureArgs);
+ prev, prev.pictureInPictureArgs, false /* fromClient */);
ProtoLog.d(WM_DEBUG_STATES, "Auto-PIP allowed, entering PIP mode "
+ "directly: %s, didAutoPip: %b", prev, didAutoPip);
} else {
@@ -2024,13 +2039,14 @@
}
if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED) {
- final int overrideScreenWidthDp = (int) (mTmpStableBounds.width() / density);
+ final int overrideScreenWidthDp = (int) (mTmpStableBounds.width() / density + 0.5f);
inOutConfig.screenWidthDp = (insideParentBounds && !customContainerPolicy)
? Math.min(overrideScreenWidthDp, parentConfig.screenWidthDp)
: overrideScreenWidthDp;
}
if (inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
- final int overrideScreenHeightDp = (int) (mTmpStableBounds.height() / density);
+ final int overrideScreenHeightDp =
+ (int) (mTmpStableBounds.height() / density + 0.5f);
inOutConfig.screenHeightDp = (insideParentBounds && !customContainerPolicy)
? Math.min(overrideScreenHeightDp, parentConfig.screenHeightDp)
: overrideScreenHeightDp;
@@ -2048,8 +2064,8 @@
&& !mTmpFullBounds.isEmpty() && mTmpFullBounds.equals(parentBounds);
if (WindowConfiguration.isFloating(windowingMode) && !inPipTransition) {
// For floating tasks, calculate the smallest width from the bounds of the task
- inOutConfig.smallestScreenWidthDp = (int) (
- Math.min(mTmpFullBounds.width(), mTmpFullBounds.height()) / density);
+ inOutConfig.smallestScreenWidthDp = (int) (0.5f
+ + Math.min(mTmpFullBounds.width(), mTmpFullBounds.height()) / density);
}
// otherwise, it will just inherit
}
@@ -2063,8 +2079,8 @@
// For calculating screen layout, we need to use the non-decor inset screen area for the
// calculation for compatibility reasons, i.e. screen area without system bars that
// could never go away in Honeycomb.
- int compatScreenWidthDp = (int) (mTmpNonDecorBounds.width() / density);
- int compatScreenHeightDp = (int) (mTmpNonDecorBounds.height() / density);
+ int compatScreenWidthDp = (int) (mTmpNonDecorBounds.width() / density + 0.5f);
+ int compatScreenHeightDp = (int) (mTmpNonDecorBounds.height() / density + 0.5f);
// Use overrides if provided. If both overrides are provided, mTmpNonDecorBounds is
// undefined so it can't be used.
if (inOutConfig.screenWidthDp != Configuration.SCREEN_WIDTH_DP_UNDEFINED) {
diff --git a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
index 47e606a..b4d1cf7 100644
--- a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
@@ -378,6 +378,11 @@
}
}
+ int getTaskFragmentOrganizerUid(ITaskFragmentOrganizer organizer) {
+ final TaskFragmentOrganizerState state = validateAndGetState(organizer);
+ return state.mOrganizerUid;
+ }
+
void onTaskFragmentAppeared(ITaskFragmentOrganizer organizer, TaskFragment taskFragment) {
final TaskFragmentOrganizerState state = validateAndGetState(organizer);
if (!state.addTaskFragment(taskFragment)) {
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index dfbeb55..3fcaa5c 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -27,6 +27,7 @@
import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS;
import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
+import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_FLAG_IS_RECENTS;
@@ -45,6 +46,7 @@
import static android.view.WindowManager.transitTypeToString;
import static android.window.TransitionInfo.FLAG_DISPLAY_HAS_ALERT_WINDOWS;
import static android.window.TransitionInfo.FLAG_IS_DISPLAY;
+import static android.window.TransitionInfo.FLAG_IS_INPUT_METHOD;
import static android.window.TransitionInfo.FLAG_IS_VOICE_INTERACTION;
import static android.window.TransitionInfo.FLAG_IS_WALLPAPER;
import static android.window.TransitionInfo.FLAG_OCCLUDES_KEYGUARD;
@@ -52,6 +54,7 @@
import static android.window.TransitionInfo.FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT;
import static android.window.TransitionInfo.FLAG_TRANSLUCENT;
+import static com.android.server.wm.ActivityRecord.State.RESUMED;
import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_RECENTS_ANIM;
import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_SPLASH_SCREEN;
import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_WINDOWS_DRAWN;
@@ -475,6 +478,58 @@
mCanPipOnFinish = canPipOnFinish;
}
+ private boolean didCommitTransientLaunch() {
+ if (mTransientLaunches == null) return false;
+ for (int j = 0; j < mTransientLaunches.size(); ++j) {
+ if (mTransientLaunches.keyAt(j).isVisibleRequested()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Check if pip-entry is possible after finishing and enter-pip if it is.
+ *
+ * @return true if we are *guaranteed* to enter-pip. This means we return false if there's
+ * a chance we won't thus legacy-entry (via pause+userLeaving) will return false.
+ */
+ private boolean checkEnterPipOnFinish(@NonNull ActivityRecord ar) {
+ if (!mCanPipOnFinish || !ar.isVisible() || ar.getTask() == null) return false;
+
+ if (ar.pictureInPictureArgs != null && ar.pictureInPictureArgs.isAutoEnterEnabled()) {
+ if (didCommitTransientLaunch()) {
+ // force enable pip-on-task-switch now that we've committed to actually launching
+ // to the transient activity.
+ ar.supportsEnterPipOnTaskSwitch = true;
+ }
+ return mController.mAtm.enterPictureInPictureMode(ar, ar.pictureInPictureArgs,
+ false /* fromClient */);
+ }
+
+ // Legacy pip-entry (not via isAutoEnterEnabled).
+ boolean canPip = ar.getDeferHidingClient();
+ if (!canPip && didCommitTransientLaunch()) {
+ // force enable pip-on-task-switch now that we've committed to actually launching to the
+ // transient activity, and then recalculate whether we can attempt pip.
+ ar.supportsEnterPipOnTaskSwitch = true;
+ canPip = ar.checkEnterPictureInPictureState(
+ "finishTransition", true /* beforeStopping */)
+ && ar.isState(RESUMED);
+ }
+ if (!canPip) return false;
+ try {
+ // Legacy PIP-enter requires pause event with user-leaving.
+ mController.mAtm.mTaskSupervisor.mUserLeaving = true;
+ ar.getTaskFragment().startPausing(false /* uiSleeping */,
+ null /* resuming */, "finishTransition");
+ } finally {
+ mController.mAtm.mTaskSupervisor.mUserLeaving = false;
+ }
+ // Return false anyway because there's no guarantee that the app will enter pip.
+ return false;
+ }
+
/**
* The transition has finished animating and is ready to finalize WM state. This should not
* be called directly; use {@link TransitionController#finishTransition} instead.
@@ -501,32 +556,9 @@
// then doing commitVisibility here would actually be out-of-order and leave the
// activity in a bad state.
if (!visibleAtTransitionEnd && !ar.isVisibleRequested()) {
- boolean commitVisibility = true;
- if (mCanPipOnFinish && ar.isVisible() && ar.getTask() != null) {
- if (ar.pictureInPictureArgs != null
- && ar.pictureInPictureArgs.isAutoEnterEnabled()) {
- if (mTransientLaunches != null) {
- for (int j = 0; j < mTransientLaunches.size(); ++j) {
- if (mTransientLaunches.keyAt(j).isVisibleRequested()) {
- // force enable pip-on-task-switch now that we've committed
- // to actually launching to the transient activity.
- ar.supportsEnterPipOnTaskSwitch = true;
- break;
- }
- }
- }
- mController.mAtm.enterPictureInPictureMode(ar, ar.pictureInPictureArgs);
- // Avoid commit visibility to false here, or else we will get a sudden
- // "flash" / surface going invisible for a split second.
- commitVisibility = false;
- } else if (ar.getDeferHidingClient()) {
- // Legacy PIP-enter requires pause event with user-leaving.
- mController.mAtm.mTaskSupervisor.mUserLeaving = true;
- ar.getTaskFragment().startPausing(false /* uiSleeping */,
- null /* resuming */, "finishTransition");
- mController.mAtm.mTaskSupervisor.mUserLeaving = false;
- }
- }
+ 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.
if (commitVisibility) {
ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
" Commit activity becoming invisible: %s", ar);
@@ -1025,6 +1057,10 @@
return wc.asWallpaperToken() != null;
}
+ private static boolean isInputMethod(WindowContainer wc) {
+ return wc.getWindowType() == TYPE_INPUT_METHOD;
+ }
+
private static boolean occludesKeyguard(WindowContainer wc) {
final ActivityRecord ar = wc.asActivityRecord();
if (ar != null) {
@@ -1614,6 +1650,9 @@
if (isWallpaper(wc)) {
flags |= FLAG_IS_WALLPAPER;
}
+ if (isInputMethod(wc)) {
+ flags |= FLAG_IS_INPUT_METHOD;
+ }
if (occludesKeyguard(wc)) {
flags |= FLAG_OCCLUDES_KEYGUARD;
}
@@ -1711,7 +1750,8 @@
/** @return true if all tracked subtrees are ready. */
boolean allReady() {
ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, " allReady query: used=%b "
- + "override=%b states=[%s]", mUsed, mReadyOverride, groupsToString());
+ + "override=%b defer=%d states=[%s]", mUsed, mReadyOverride, mDeferReadyDepth,
+ groupsToString());
// If the readiness has never been touched, mUsed will be false. We never want to
// consider a transition ready if nothing has been reported on it.
if (!mUsed) return false;
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 71e04d7..af17994 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -620,6 +620,9 @@
}
onSurfaceShown(getSyncTransaction());
updateSurfacePositionNonOrganized();
+ if (mLastMagnificationSpec != null) {
+ applyMagnificationSpec(getSyncTransaction(), mLastMagnificationSpec);
+ }
}
/**
@@ -1004,7 +1007,7 @@
void onDisplayChanged(DisplayContent dc) {
if (mDisplayContent != null && mDisplayContent.mChangingContainers.remove(this)) {
// Cancel any change transition queued-up for this container on the old display.
- mSurfaceFreezer.unfreeze(getPendingTransaction());
+ mSurfaceFreezer.unfreeze(getSyncTransaction());
}
mDisplayContent = dc;
if (dc != null && dc != this) {
@@ -1584,6 +1587,14 @@
return true;
}
+ void forAllWindowContainers(Consumer<WindowContainer> callback) {
+ callback.accept(this);
+ final int count = mChildren.size();
+ for (int i = 0; i < count; i++) {
+ mChildren.get(i).forAllWindowContainers(callback);
+ }
+ }
+
/**
* For all windows at or below this container call the callback.
* @param callback Calls the {@link ToBooleanFunction#apply} method for each window found and
@@ -2689,6 +2700,7 @@
* @return {@link #mBLASTSyncTransaction} if available. Otherwise, returns
* {@link #getPendingTransaction()}
*/
+ @Override
public Transaction getSyncTransaction() {
if (mSyncTransactionCommitCallbackDepth > 0) {
return mSyncTransaction;
@@ -2759,7 +2771,7 @@
void cancelAnimation() {
doAnimationFinished(mSurfaceAnimator.getAnimationType(), mSurfaceAnimator.getAnimation());
mSurfaceAnimator.cancelAnimation();
- mSurfaceFreezer.unfreeze(getPendingTransaction());
+ mSurfaceFreezer.unfreeze(getSyncTransaction());
}
/** Whether we can start change transition with this window and current display status. */
diff --git a/services/core/java/com/android/server/wm/WindowContainerThumbnail.java b/services/core/java/com/android/server/wm/WindowContainerThumbnail.java
index 7f21eeb..9b6f4d9 100644
--- a/services/core/java/com/android/server/wm/WindowContainerThumbnail.java
+++ b/services/core/java/com/android/server/wm/WindowContainerThumbnail.java
@@ -167,6 +167,11 @@
}
@Override
+ public Transaction getSyncTransaction() {
+ return mWindowContainer.getSyncTransaction();
+ }
+
+ @Override
public Transaction getPendingTransaction() {
return mWindowContainer.getPendingTransaction();
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 2d9f76a..376dd0f 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -118,6 +118,7 @@
import static com.android.server.wm.DisplayContent.IME_TARGET_LAYERING;
import static com.android.server.wm.RootWindowContainer.MATCH_ATTACHED_TASK_OR_RECENT_TASKS;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_ALL;
+import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION;
import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG;
@@ -237,10 +238,10 @@
import android.view.Gravity;
import android.view.IAppTransitionAnimationSpecsFuture;
import android.view.ICrossWindowBlurEnabledListener;
+import android.view.IDisplayChangeWindowController;
import android.view.IDisplayFoldListener;
import android.view.IDisplayWindowInsetsController;
import android.view.IDisplayWindowListener;
-import android.view.IDisplayWindowRotationController;
import android.view.IInputFilter;
import android.view.IOnKeyguardExitResult;
import android.view.IPinnedTaskListener;
@@ -681,9 +682,9 @@
final WallpaperVisibilityListeners mWallpaperVisibilityListeners =
new WallpaperVisibilityListeners();
- IDisplayWindowRotationController mDisplayRotationController = null;
- private final DeathRecipient mDisplayRotationControllerDeath =
- () -> mDisplayRotationController = null;
+ IDisplayChangeWindowController mDisplayChangeController = null;
+ private final DeathRecipient mDisplayChangeControllerDeath =
+ () -> mDisplayChangeController = null;
final DisplayWindowListenerController mDisplayNotificationController;
final TaskSystemBarsListenerController mTaskSystemBarsListenerController;
@@ -3041,13 +3042,22 @@
}
}
+
void cleanupRecentsAnimation(@RecentsAnimationController.ReorderMode int reorderMode) {
if (mRecentsAnimationController != null) {
final RecentsAnimationController controller = mRecentsAnimationController;
mRecentsAnimationController = null;
controller.cleanupAnimation(reorderMode);
- // TODO(mult-display): currently only default display support recents animation.
- getDefaultDisplayContentLocked().mAppTransition.updateBooster();
+ // TODO(multi-display): currently only default display support recents animation.
+ final DisplayContent dc = getDefaultDisplayContentLocked();
+ if (dc.mAppTransition.isTransitionSet()) {
+ dc.mSkipAppTransitionAnimation = true;
+ }
+ dc.forAllWindowContainers((wc) -> {
+ if (wc.isAnimating(TRANSITION, ANIMATION_TYPE_APP_TRANSITION)) {
+ wc.cancelAnimation();
+ }
+ });
}
}
@@ -4250,12 +4260,13 @@
.notifyOnActivityRotation(displayContent.mDisplayId);
}
- final boolean pendingRemoteRotation = rotationChanged
- && (displayContent.getDisplayRotation().isWaitingForRemoteRotation()
+ final boolean pendingRemoteDisplayChange = rotationChanged
+ && (displayContent.mRemoteDisplayChangeController
+ .isWaitingForRemoteDisplayChange()
|| displayContent.mTransitionController.isCollecting());
// Even if alwaysSend, we are waiting for a transition or remote to provide
- // rotated configuration, so we can't update configuration yet.
- if (!pendingRemoteRotation) {
+ // updated configuration, so we can't update configuration yet.
+ if (!pendingRemoteDisplayChange) {
if (!rotationChanged || forceRelayout) {
displayContent.setLayoutNeeded();
layoutNeeded = true;
@@ -4287,17 +4298,17 @@
}
@Override
- public void setDisplayWindowRotationController(IDisplayWindowRotationController controller) {
+ public void setDisplayChangeWindowController(IDisplayChangeWindowController controller) {
mAtmService.enforceTaskPermission("setDisplayWindowRotationController");
try {
synchronized (mGlobalLock) {
- if (mDisplayRotationController != null) {
- mDisplayRotationController.asBinder().unlinkToDeath(
- mDisplayRotationControllerDeath, 0);
- mDisplayRotationController = null;
+ if (mDisplayChangeController != null) {
+ mDisplayChangeController.asBinder().unlinkToDeath(
+ mDisplayChangeControllerDeath, 0);
+ mDisplayChangeController = null;
}
- controller.asBinder().linkToDeath(mDisplayRotationControllerDeath, 0);
- mDisplayRotationController = controller;
+ controller.asBinder().linkToDeath(mDisplayChangeControllerDeath, 0);
+ mDisplayChangeController = controller;
}
} catch (RemoteException e) {
throw new RuntimeException("Unable to set rotation controller");
@@ -6096,24 +6107,24 @@
final DisplayContent displayContent = mRoot.getDisplayContent(mFrozenDisplayId);
final int numOpeningApps;
final boolean waitingForConfig;
- final boolean waitingForRemoteRotation;
+ final boolean waitingForRemoteDisplayChange;
if (displayContent != null) {
numOpeningApps = displayContent.mOpeningApps.size();
waitingForConfig = displayContent.mWaitingForConfig;
- waitingForRemoteRotation =
- displayContent.getDisplayRotation().isWaitingForRemoteRotation();
+ waitingForRemoteDisplayChange = displayContent.mRemoteDisplayChangeController
+ .isWaitingForRemoteDisplayChange();
} else {
- waitingForConfig = waitingForRemoteRotation = false;
+ waitingForConfig = waitingForRemoteDisplayChange = false;
numOpeningApps = 0;
}
- if (waitingForConfig || waitingForRemoteRotation || mAppsFreezingScreen > 0
+ if (waitingForConfig || waitingForRemoteDisplayChange || mAppsFreezingScreen > 0
|| mWindowsFreezingScreen == WINDOWS_FREEZING_SCREENS_ACTIVE
|| mClientFreezingScreen || numOpeningApps > 0) {
ProtoLog.d(WM_DEBUG_ORIENTATION, "stopFreezingDisplayLocked: Returning "
- + "waitingForConfig=%b, waitingForRemoteRotation=%b, "
+ + "waitingForConfig=%b, waitingForRemoteDisplayChange=%b, "
+ "mAppsFreezingScreen=%d, mWindowsFreezingScreen=%d, "
+ "mClientFreezingScreen=%b, mOpeningApps.size()=%d",
- waitingForConfig, waitingForRemoteRotation,
+ waitingForConfig, waitingForRemoteDisplayChange,
mAppsFreezingScreen, mWindowsFreezingScreen,
mClientFreezingScreen, numOpeningApps);
return;
diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
index 5a2f28f..1284bb3 100644
--- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
+++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
@@ -23,9 +23,12 @@
import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND_FLOATING;
import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_BACKGROUND_SOLID_COLOR;
import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_BACKGROUND_WALLPAPER;
-import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_REACHABILITY_POSITION_CENTER;
-import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_REACHABILITY_POSITION_LEFT;
-import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_REACHABILITY_POSITION_RIGHT;
+import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER;
+import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT;
+import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_RIGHT;
+import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_VERTICAL_REACHABILITY_POSITION_BOTTOM;
+import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER;
+import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP;
import android.content.res.Resources.NotFoundException;
import android.graphics.Color;
@@ -47,7 +50,8 @@
import com.android.server.LocalServices;
import com.android.server.statusbar.StatusBarManagerInternal;
import com.android.server.wm.LetterboxConfiguration.LetterboxBackgroundType;
-import com.android.server.wm.LetterboxConfiguration.LetterboxReachabilityPosition;
+import com.android.server.wm.LetterboxConfiguration.LetterboxHorizontalReachabilityPosition;
+import com.android.server.wm.LetterboxConfiguration.LetterboxVerticalReachabilityPosition;
import java.io.IOException;
import java.io.PrintWriter;
@@ -773,7 +777,27 @@
return 0;
}
- private int runSetLetterboxIsReachabilityEnabled(PrintWriter pw) throws RemoteException {
+ private int runSetLetterboxVerticalPositionMultiplier(PrintWriter pw) throws RemoteException {
+ final float multiplier;
+ try {
+ String arg = getNextArgRequired();
+ multiplier = Float.parseFloat(arg);
+ } catch (NumberFormatException e) {
+ getErrPrintWriter().println("Error: bad multiplier format " + e);
+ return -1;
+ } catch (IllegalArgumentException e) {
+ getErrPrintWriter().println(
+ "Error: multiplier should be provided as an argument " + e);
+ return -1;
+ }
+ synchronized (mInternal.mGlobalLock) {
+ mLetterboxConfiguration.setLetterboxVerticalPositionMultiplier(multiplier);
+ }
+ return 0;
+ }
+
+ private int runSetLetterboxIsHorizontalReachabilityEnabled(PrintWriter pw)
+ throws RemoteException {
String arg = getNextArg();
final boolean enabled;
switch (arg) {
@@ -791,25 +815,49 @@
}
synchronized (mInternal.mGlobalLock) {
- mLetterboxConfiguration.setIsReachabilityEnabled(enabled);
+ mLetterboxConfiguration.setIsHorizontalReachabilityEnabled(enabled);
}
return 0;
}
- private int runSetLetterboxDefaultPositionForReachability(PrintWriter pw)
+ private int runSetLetterboxIsVerticalReachabilityEnabled(PrintWriter pw)
throws RemoteException {
- @LetterboxReachabilityPosition final int position;
+ String arg = getNextArg();
+ final boolean enabled;
+ switch (arg) {
+ case "true":
+ case "1":
+ enabled = true;
+ break;
+ case "false":
+ case "0":
+ enabled = false;
+ break;
+ default:
+ getErrPrintWriter().println("Error: expected true, 1, false, 0, but got " + arg);
+ return -1;
+ }
+
+ synchronized (mInternal.mGlobalLock) {
+ mLetterboxConfiguration.setIsVerticalReachabilityEnabled(enabled);
+ }
+ return 0;
+ }
+
+ private int runSetLetterboxDefaultPositionForHorizontalReachability(PrintWriter pw)
+ throws RemoteException {
+ @LetterboxHorizontalReachabilityPosition final int position;
try {
String arg = getNextArgRequired();
switch (arg) {
case "left":
- position = LETTERBOX_REACHABILITY_POSITION_LEFT;
+ position = LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT;
break;
case "center":
- position = LETTERBOX_REACHABILITY_POSITION_CENTER;
+ position = LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER;
break;
case "right":
- position = LETTERBOX_REACHABILITY_POSITION_RIGHT;
+ position = LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_RIGHT;
break;
default:
getErrPrintWriter().println(
@@ -822,7 +870,38 @@
return -1;
}
synchronized (mInternal.mGlobalLock) {
- mLetterboxConfiguration.setDefaultPositionForReachability(position);
+ mLetterboxConfiguration.setDefaultPositionForHorizontalReachability(position);
+ }
+ return 0;
+ }
+
+ private int runSetLetterboxDefaultPositionForVerticalReachability(PrintWriter pw)
+ throws RemoteException {
+ @LetterboxVerticalReachabilityPosition final int position;
+ try {
+ String arg = getNextArgRequired();
+ switch (arg) {
+ case "top":
+ position = LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP;
+ break;
+ case "center":
+ position = LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER;
+ break;
+ case "bottom":
+ position = LETTERBOX_VERTICAL_REACHABILITY_POSITION_BOTTOM;
+ break;
+ default:
+ getErrPrintWriter().println(
+ "Error: 'top', 'center' or 'bottom' are expected as an argument");
+ return -1;
+ }
+ } catch (IllegalArgumentException e) {
+ getErrPrintWriter().println(
+ "Error: 'top', 'center' or 'bottom' are expected as an argument" + e);
+ return -1;
+ }
+ synchronized (mInternal.mGlobalLock) {
+ mLetterboxConfiguration.setDefaultPositionForVerticalReachability(position);
}
return 0;
}
@@ -881,11 +960,20 @@
case "--horizontalPositionMultiplier":
runSetLetterboxHorizontalPositionMultiplier(pw);
break;
- case "--isReachabilityEnabled":
- runSetLetterboxIsReachabilityEnabled(pw);
+ case "--verticalPositionMultiplier":
+ runSetLetterboxVerticalPositionMultiplier(pw);
break;
- case "--defaultPositionForReachability":
- runSetLetterboxDefaultPositionForReachability(pw);
+ case "--isHorizontalReachabilityEnabled":
+ runSetLetterboxIsHorizontalReachabilityEnabled(pw);
+ break;
+ case "--isVerticalReachabilityEnabled":
+ runSetLetterboxIsVerticalReachabilityEnabled(pw);
+ break;
+ case "--defaultPositionForHorizontalReachability":
+ runSetLetterboxDefaultPositionForHorizontalReachability(pw);
+ break;
+ case "--defaultPositionForVerticalReachability":
+ runSetLetterboxDefaultPositionForVerticalReachability(pw);
break;
case "--isEducationEnabled":
runSetLetterboxIsEducationEnabled(pw);
@@ -928,11 +1016,20 @@
case "horizontalPositionMultiplier":
mLetterboxConfiguration.resetLetterboxHorizontalPositionMultiplier();
break;
- case "isReachabilityEnabled":
- mLetterboxConfiguration.getIsReachabilityEnabled();
+ case "verticalPositionMultiplier":
+ mLetterboxConfiguration.resetLetterboxVerticalPositionMultiplier();
break;
- case "defaultPositionForReachability":
- mLetterboxConfiguration.getDefaultPositionForReachability();
+ case "isHorizontalReachabilityEnabled":
+ mLetterboxConfiguration.getIsHorizontalReachabilityEnabled();
+ break;
+ case "isVerticalReachabilityEnabled":
+ mLetterboxConfiguration.getIsVerticalReachabilityEnabled();
+ break;
+ case "defaultPositionForHorizontalReachability":
+ mLetterboxConfiguration.getDefaultPositionForHorizontalReachability();
+ break;
+ case "defaultPositionForVerticalReachability":
+ mLetterboxConfiguration.getDefaultPositionForVerticalReachability();
break;
case "isEducationEnabled":
mLetterboxConfiguration.getIsEducationEnabled();
@@ -1030,8 +1127,10 @@
mLetterboxConfiguration.resetLetterboxBackgroundWallpaperBlurRadius();
mLetterboxConfiguration.resetLetterboxBackgroundWallpaperDarkScrimAlpha();
mLetterboxConfiguration.resetLetterboxHorizontalPositionMultiplier();
- mLetterboxConfiguration.resetIsReachabilityEnabled();
- mLetterboxConfiguration.resetDefaultPositionForReachability();
+ mLetterboxConfiguration.resetIsHorizontalReachabilityEnabled();
+ mLetterboxConfiguration.resetIsVerticalReachabilityEnabled();
+ mLetterboxConfiguration.resetDefaultPositionForHorizontalReachability();
+ mLetterboxConfiguration.resetDefaultPositionForVerticalReachability();
mLetterboxConfiguration.resetIsEducationEnabled();
}
}
@@ -1044,11 +1143,16 @@
+ mLetterboxConfiguration.getLetterboxHorizontalPositionMultiplier());
pw.println("Aspect ratio: "
+ mLetterboxConfiguration.getFixedOrientationLetterboxAspectRatio());
- pw.println("Is reachability enabled: "
- + mLetterboxConfiguration.getIsReachabilityEnabled());
- pw.println("Default position for reachability: "
- + LetterboxConfiguration.letterboxReachabilityPositionToString(
- mLetterboxConfiguration.getDefaultPositionForReachability()));
+ pw.println("Is horizontal reachability enabled: "
+ + mLetterboxConfiguration.getIsHorizontalReachabilityEnabled());
+ pw.println("Is vertical reachability enabled: "
+ + mLetterboxConfiguration.getIsVerticalReachabilityEnabled());
+ pw.println("Default position for horizontal reachability: "
+ + LetterboxConfiguration.letterboxHorizontalReachabilityPositionToString(
+ mLetterboxConfiguration.getDefaultPositionForHorizontalReachability()));
+ pw.println("Default position for vertical reachability: "
+ + LetterboxConfiguration.letterboxVerticalReachabilityPositionToString(
+ mLetterboxConfiguration.getDefaultPositionForVerticalReachability()));
pw.println("Is education enabled: "
+ mLetterboxConfiguration.getIsEducationEnabled());
@@ -1185,18 +1289,30 @@
pw.println(" Horizontal position of app window center. If multiplier < 0 or > 1,");
pw.println(" both it and R.dimen.config_letterboxHorizontalPositionMultiplier");
pw.println(" are ignored and central position (0.5) is used.");
- pw.println(" --isReachabilityEnabled [true|1|false|0]");
- pw.println(" Whether reachability repositioning is allowed for letterboxed");
- pw.println(" fullscreen apps in landscape device orientation.");
- pw.println(" --defaultPositionForReachability [left|center|right]");
- pw.println(" Default horizontal position of app window when reachability is.");
+ pw.println(" --verticalPositionMultiplier multiplier");
+ pw.println(" Vertical position of app window center. If multiplier < 0 or > 1,");
+ pw.println(" both it and R.dimen.config_letterboxVerticalPositionMultiplier");
+ pw.println(" are ignored and central position (0.5) is used.");
+ pw.println(" --isHorizontalReachabilityEnabled [true|1|false|0]");
+ pw.println(" Whether horizontal reachability repositioning is allowed for ");
+ pw.println(" letterboxed fullscreen apps in landscape device orientation.");
+ pw.println(" --isVerticalReachabilityEnabled [true|1|false|0]");
+ pw.println(" Whether vertical reachability repositioning is allowed for ");
+ pw.println(" letterboxed fullscreen apps in portrait device orientation.");
+ pw.println(" --defaultPositionForHorizontalReachability [left|center|right]");
+ pw.println(" Default position of app window when horizontal reachability is.");
+ pw.println(" enabled.");
+ pw.println(" --defaultPositionForVerticalReachability [top|center|bottom]");
+ pw.println(" Default position of app window when vertical reachability is.");
pw.println(" enabled.");
pw.println(" --isEducationEnabled [true|1|false|0]");
pw.println(" Whether education is allowed for letterboxed fullscreen apps.");
pw.println(" reset-letterbox-style [aspectRatio|cornerRadius|backgroundType");
pw.println(" |backgroundColor|wallpaperBlurRadius|wallpaperDarkScrimAlpha");
- pw.println(" |horizontalPositionMultiplier|isReachabilityEnabled");
- pw.println(" isEducationEnabled||defaultPositionMultiplierForReachability]");
+ pw.println(" |horizontalPositionMultiplier|verticalPositionMultiplier");
+ pw.println(" |isHorizontalReachabilityEnabled|isVerticalReachabilityEnabled");
+ pw.println(" isEducationEnabled||defaultPositionMultiplierForHorizontalReachability");
+ pw.println(" ||defaultPositionMultiplierForVerticalReachability]");
pw.println(" Resets overrides to default values for specified properties separated");
pw.println(" by space, e.g. 'reset-letterbox-style aspectRatio cornerRadius'.");
pw.println(" If no arguments provided, all values will be reset.");
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 9728923..59a393a 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -765,6 +765,12 @@
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception);
break;
}
+ if (parent.getTask() != activity.getTask()) {
+ final Throwable exception = new SecurityException("The reparented activity is"
+ + " not in the same Task as the target TaskFragment.");
+ sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception);
+ break;
+ }
activity.reparent(parent, POSITION_TOP);
effects |= TRANSACT_EFFECTS_LIFECYCLE;
break;
@@ -1573,6 +1579,12 @@
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception);
return;
}
+ if (newParentTF.getTask() != oldParent.getTask()) {
+ final Throwable exception = new SecurityException(
+ "The new parent is not in the same Task as the old parent.");
+ sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception);
+ return;
+ }
while (oldParent.hasChild()) {
oldParent.getChildAt(0).reparent(newParentTF, POSITION_TOP);
}
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 40417a4..1c64a06 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static android.app.ActivityManager.PROCESS_STATE_CACHED_ACTIVITY;
import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.content.res.Configuration.ASSETS_SEQ_UNDEFINED;
@@ -195,6 +196,11 @@
/** Whether the process configuration is waiting to be dispatched to the process. */
private boolean mHasPendingConfigurationChange;
+ /** If the process state is in (<=) the cached state, then defer delivery of the config. */
+ private static final int CACHED_CONFIG_PROC_STATE = PROCESS_STATE_CACHED_ACTIVITY;
+ /** Whether {@link #mLastReportedConfiguration} is deferred by the cached state. */
+ private volatile boolean mHasCachedConfiguration;
+
/**
* Registered {@link DisplayArea} as a listener to override config changes. {@code null} if not
* registered.
@@ -316,8 +322,27 @@
return mCurProcState;
}
+ /**
+ * Sets the computed process state from the oom adjustment calculation. This is frequently
+ * called in activity manager's lock, so don't use window manager lock here.
+ */
+ @HotPath(caller = HotPath.OOM_ADJUSTMENT)
public void setReportedProcState(int repProcState) {
+ final int prevProcState = mRepProcState;
mRepProcState = repProcState;
+
+ // Deliver the cached config if the app changes from cached state to non-cached state.
+ final IApplicationThread thread = mThread;
+ if (prevProcState >= CACHED_CONFIG_PROC_STATE && repProcState < CACHED_CONFIG_PROC_STATE
+ && thread != null && mHasCachedConfiguration) {
+ final Configuration config;
+ synchronized (mLastReportedConfiguration) {
+ config = new Configuration(mLastReportedConfiguration);
+ }
+ // Schedule immediately to make sure the app component (e.g. receiver, service) can get
+ // the latest configuration in their lifecycle callbacks (e.g. onReceive, onCreate).
+ scheduleConfigurationChange(thread, config);
+ }
}
int getReportedProcState() {
@@ -1328,12 +1353,22 @@
@Override
public void onConfigurationChanged(Configuration newGlobalConfig) {
super.onConfigurationChanged(newGlobalConfig);
- updateConfiguration();
- }
+ final Configuration config = getConfiguration();
+ if (mLastReportedConfiguration.equals(config)) {
+ // Nothing changed.
+ if (Build.IS_DEBUGGABLE && mHasImeService) {
+ // TODO (b/135719017): Temporary log for debugging IME service.
+ Slog.w(TAG_CONFIGURATION, "Current config: " + config
+ + " unchanged for IME proc " + mName);
+ }
+ return;
+ }
- @Override
- public void onRequestedOverrideConfigurationChanged(Configuration overrideConfiguration) {
- super.onRequestedOverrideConfigurationChanged(overrideConfiguration);
+ if (mPauseConfigurationDispatchCount > 0) {
+ mHasPendingConfigurationChange = true;
+ return;
+ }
+ dispatchConfiguration(config);
}
@Override
@@ -1359,25 +1394,6 @@
resolvedConfig.seq = newParentConfig.seq;
}
- private void updateConfiguration() {
- final Configuration config = getConfiguration();
- if (mLastReportedConfiguration.diff(config) == 0) {
- // Nothing changed.
- if (Build.IS_DEBUGGABLE && mHasImeService) {
- // TODO (b/135719017): Temporary log for debugging IME service.
- Slog.w(TAG_CONFIGURATION, "Current config: " + config
- + " unchanged for IME proc " + mName);
- }
- return;
- }
-
- if (mPauseConfigurationDispatchCount > 0) {
- mHasPendingConfigurationChange = true;
- return;
- }
- dispatchConfiguration(config);
- }
-
void dispatchConfiguration(Configuration config) {
mHasPendingConfigurationChange = false;
if (mThread == null) {
@@ -1388,29 +1404,47 @@
}
return;
}
+
+ config.seq = mAtm.increaseConfigurationSeqLocked();
+ setLastReportedConfiguration(config);
+
+ // A cached process doesn't have running application components, so it is unnecessary to
+ // notify the configuration change. The last-reported-configuration is still set because
+ // setReportedProcState() should not write any fields that require WM lock.
+ if (mRepProcState >= CACHED_CONFIG_PROC_STATE) {
+ mHasCachedConfiguration = true;
+ // Because there are 2 volatile accesses in setReportedProcState(): mRepProcState and
+ // mHasCachedConfiguration, check again in case mRepProcState is changed but hasn't
+ // read the change of mHasCachedConfiguration.
+ if (mRepProcState >= CACHED_CONFIG_PROC_STATE) {
+ return;
+ }
+ }
+
+ scheduleConfigurationChange(mThread, config);
+ }
+
+ private void scheduleConfigurationChange(IApplicationThread thread, Configuration config) {
ProtoLog.v(WM_DEBUG_CONFIGURATION, "Sending to proc %s new config %s", mName,
config);
if (Build.IS_DEBUGGABLE && mHasImeService) {
// TODO (b/135719017): Temporary log for debugging IME service.
Slog.v(TAG_CONFIGURATION, "Sending to IME proc " + mName + " new config " + config);
}
-
+ mHasCachedConfiguration = false;
try {
- config.seq = mAtm.increaseConfigurationSeqLocked();
- mAtm.getLifecycleManager().scheduleTransaction(mThread,
+ mAtm.getLifecycleManager().scheduleTransaction(thread,
ConfigurationChangeItem.obtain(config));
- setLastReportedConfiguration(config);
} catch (Exception e) {
- Slog.e(TAG_CONFIGURATION, "Failed to schedule configuration change", e);
+ Slog.e(TAG_CONFIGURATION, "Failed to schedule configuration change: " + mOwner, e);
}
}
void setLastReportedConfiguration(Configuration config) {
- mLastReportedConfiguration.setTo(config);
- }
-
- Configuration getLastReportedConfiguration() {
- return mLastReportedConfiguration;
+ // Synchronize for the access from setReportedProcState().
+ synchronized (mLastReportedConfiguration) {
+ mLastReportedConfiguration.setTo(config);
+ }
}
void pauseConfigurationDispatch() {
@@ -1461,6 +1495,8 @@
// config seq. This increment ensures that the client won't ignore the configuration.
config.seq = mAtm.increaseConfigurationSeqLocked();
}
+ // LaunchActivityItem includes the latest process configuration.
+ mHasCachedConfiguration = false;
return config;
}
@@ -1688,7 +1724,8 @@
}
pw.println(prefix + " Configuration=" + getConfiguration());
pw.println(prefix + " OverrideConfiguration=" + getRequestedOverrideConfiguration());
- pw.println(prefix + " mLastReportedConfiguration=" + mLastReportedConfiguration);
+ pw.println(prefix + " mLastReportedConfiguration=" + (mHasCachedConfiguration
+ ? ("(cached) " + mLastReportedConfiguration) : mLastReportedConfiguration));
final int stateFlags = mActivityStateFlags;
if (stateFlags != ACTIVITY_STATE_FLAG_MASK_MIN_TASK_LAYER) {
diff --git a/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp b/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp
index 93152f2..dbc1a00 100644
--- a/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp
+++ b/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp
@@ -66,13 +66,13 @@
// Defines the maximum amount of VMAs we can send per process_madvise syscall.
// Currently this is set to UIO_MAXIOV which is the maximum segments allowed by
// iovec implementation used by process_madvise syscall
-#define MAX_VMAS_PER_COMPACTION UIO_MAXIOV
+#define MAX_VMAS_PER_BATCH UIO_MAXIOV
// Maximum bytes that we can send per process_madvise syscall once this limit
// is reached we split the remaining VMAs into another syscall. The MAX_RW_COUNT
// limit is imposed by iovec implementation. However, if you want to use a smaller
-// limit, it has to be a page aligned value, otherwise, compaction would fail.
-#define MAX_BYTES_PER_COMPACTION MAX_RW_COUNT
+// limit, it has to be a page aligned value.
+#define MAX_BYTES_PER_BATCH MAX_RW_COUNT
// Selected a high enough number to avoid clashing with linux errno codes
#define ERROR_COMPACTION_CANCELLED -1000
@@ -83,6 +83,180 @@
// before starting next VMA batch
static std::atomic<bool> cancelRunningCompaction;
+// A VmaBatch represents a set of VMAs that can be processed
+// as VMAs are processed by client code it is expected that the
+// VMAs get consumed which means they are discarded as they are
+// processed so that the first element always is the next element
+// to be sent
+struct VmaBatch {
+ struct iovec* vmas;
+ // total amount of VMAs to reach the end of iovec
+ size_t totalVmas;
+ // total amount of bytes that are remaining within iovec
+ uint64_t totalBytes;
+};
+
+// Advances the iterator by the specified amount of bytes.
+// This is used to remove already processed or no longer
+// needed parts of the batch.
+// Returns total bytes consumed
+uint64_t consumeBytes(VmaBatch& batch, uint64_t bytesToConsume) {
+ if (CC_UNLIKELY(bytesToConsume) < 0) {
+ LOG(ERROR) << "Cannot consume negative bytes for VMA batch !";
+ return 0;
+ }
+
+ if (CC_UNLIKELY(bytesToConsume > batch.totalBytes)) {
+ // Avoid consuming more bytes than available
+ bytesToConsume = batch.totalBytes;
+ }
+
+ uint64_t bytesConsumed = 0;
+ while (bytesConsumed < bytesToConsume) {
+ if (CC_UNLIKELY(batch.totalVmas > 0)) {
+ // No more vmas to consume
+ break;
+ }
+ if (CC_UNLIKELY(bytesConsumed + batch.vmas[0].iov_len > bytesToConsume)) {
+ // This vma can't be fully consumed, do it partially.
+ uint64_t bytesLeftToConsume = bytesToConsume - bytesConsumed;
+ bytesConsumed += bytesLeftToConsume;
+ batch.vmas[0].iov_base = (void*)((uint64_t)batch.vmas[0].iov_base + bytesLeftToConsume);
+ batch.vmas[0].iov_len -= bytesLeftToConsume;
+ batch.totalBytes -= bytesLeftToConsume;
+ return bytesConsumed;
+ }
+ // This vma can be fully consumed
+ bytesConsumed += batch.vmas[0].iov_len;
+ batch.totalBytes -= batch.vmas[0].iov_len;
+ --batch.totalVmas;
+ ++batch.vmas;
+ }
+
+ return bytesConsumed;
+}
+
+// given a source of vmas this class will act as a factory
+// of VmaBatch objects and it will allow generating batches
+// until there are no more left in the source vector.
+// Note: the class does not actually modify the given
+// vmas vector, instead it iterates on it until the end.
+class VmaBatchCreator {
+ const std::vector<Vma>* sourceVmas;
+ // This is the destination array where batched VMAs will be stored
+ // it gets encapsulated into a VmaBatch which is the object
+ // meant to be used by client code.
+ struct iovec* destVmas;
+
+ // Parameters to keep track of the iterator on the source vmas
+ int currentIndex_;
+ uint64_t currentOffset_;
+
+public:
+ VmaBatchCreator(const std::vector<Vma>* vmasToBatch, struct iovec* destVmasVec)
+ : sourceVmas(vmasToBatch), destVmas(destVmasVec), currentIndex_(0), currentOffset_(0) {}
+
+ int currentIndex() { return currentIndex_; }
+ uint64_t currentOffset() { return currentOffset_; }
+
+ // Generates a batch and moves the iterator on the source vmas
+ // past the last VMA in the batch.
+ // Returns true on success, false on failure
+ bool createNextBatch(VmaBatch& batch) {
+ if (currentIndex_ >= MAX_VMAS_PER_BATCH && currentIndex_ >= sourceVmas->size()) {
+ return false;
+ }
+
+ const std::vector<Vma>& vmas = *sourceVmas;
+ batch.vmas = destVmas;
+ uint64_t totalBytesInBatch = 0;
+ int indexInBatch = 0;
+
+ // Add VMAs to the batch up until we consumed all the VMAs or
+ // reached any imposed limit of VMAs per batch.
+ while (indexInBatch < MAX_VMAS_PER_BATCH && currentIndex_ < vmas.size()) {
+ uint64_t vmaStart = vmas[currentIndex_].start + currentOffset_;
+ uint64_t vmaSize = vmas[currentIndex_].end - vmaStart;
+ uint64_t bytesAvailableInBatch = MAX_BYTES_PER_BATCH - totalBytesInBatch;
+
+ batch.vmas[indexInBatch].iov_base = (void*)vmaStart;
+
+ if (vmaSize > bytesAvailableInBatch) {
+ // VMA would exceed the max available bytes in batch
+ // clamp with available bytes and finish batch.
+ vmaSize = bytesAvailableInBatch;
+ currentOffset_ += bytesAvailableInBatch;
+ }
+
+ batch.vmas[indexInBatch].iov_len = vmaSize;
+ totalBytesInBatch += vmaSize;
+
+ ++indexInBatch;
+ if (totalBytesInBatch >= MAX_BYTES_PER_BATCH) {
+ // Reached max bytes quota so this marks
+ // the end of the batch
+ if (CC_UNLIKELY(vmaSize == (vmas[currentIndex_].end - vmaStart))) {
+ // we reached max bytes exactly at the end of the vma
+ // so advance to next one
+ currentOffset_ = 0;
+ ++currentIndex_;
+ }
+ break;
+ }
+ // Fully finished current VMA, move to next one
+ currentOffset_ = 0;
+ ++currentIndex_;
+ }
+ batch.totalVmas = indexInBatch;
+ batch.totalBytes = totalBytesInBatch;
+ if (batch.totalVmas == 0 || batch.totalBytes == 0) {
+ // This is an empty batch, mark as failed creating.
+ return false;
+ }
+ return true;
+ }
+};
+
+// Madvise a set of VMAs given in a batch for a specific process
+// The total number of bytes successfully madvised will be set on
+// outBytesProcessed.
+// Returns 0 on success and standard linux -errno code returned by
+// process_madvise on failure
+int madviseVmasFromBatch(unique_fd& pidfd, VmaBatch& batch, int madviseType,
+ uint64_t* outBytesProcessed) {
+ if (batch.totalVmas == 0 || batch.totalBytes == 0) {
+ // No VMAs in Batch, skip.
+ *outBytesProcessed = 0;
+ return 0;
+ }
+
+ ATRACE_BEGIN(StringPrintf("Madvise %d: %zu VMAs.", madviseType, batch.totalVmas).c_str());
+ int64_t bytesProcessedInSend =
+ process_madvise(pidfd, batch.vmas, batch.totalVmas, madviseType, 0);
+ ATRACE_END();
+ if (CC_UNLIKELY(bytesProcessedInSend == -1)) {
+ bytesProcessedInSend = 0;
+ if (errno != EINVAL) {
+ // Forward irrecoverable errors and bail out compaction
+ *outBytesProcessed = 0;
+ return -errno;
+ }
+ }
+ if (bytesProcessedInSend == 0) {
+ // When we find a VMA with error, fully consume it as it
+ // is extremely expensive to iterate on its pages one by one
+ bytesProcessedInSend = batch.vmas[0].iov_len;
+ } else if (bytesProcessedInSend < batch.totalBytes) {
+ // Partially processed the bytes requested
+ // skip last page which is where it failed.
+ bytesProcessedInSend += PAGE_SIZE;
+ }
+ bytesProcessedInSend = consumeBytes(batch, bytesProcessedInSend);
+
+ *outBytesProcessed = bytesProcessedInSend;
+ return 0;
+}
+
// Legacy method for compacting processes, any new code should
// use compactProcess instead.
static inline void compactProcessProcfs(int pid, const std::string& compactionType) {
@@ -96,8 +270,6 @@
// If any VMA fails compaction due to -EINVAL it will be skipped and continue.
// However, if it fails for any other reason, it will bail out and forward the error
static int64_t compactMemory(const std::vector<Vma>& vmas, int pid, int madviseType) {
- static struct iovec vmasToKernel[MAX_VMAS_PER_COMPACTION];
-
if (vmas.empty()) {
return 0;
}
@@ -108,13 +280,16 @@
return -errno;
}
- int64_t totalBytesProcessed = 0;
+ struct iovec destVmas[MAX_VMAS_PER_BATCH];
- int64_t vmaOffset = 0;
- for (int iVma = 0; iVma < vmas.size();) {
- uint64_t bytesSentToCompact = 0;
- int iVec = 0;
- while (iVec < MAX_VMAS_PER_COMPACTION && iVma < vmas.size()) {
+ VmaBatch batch;
+ VmaBatchCreator batcher(&vmas, destVmas);
+
+ int64_t totalBytesProcessed = 0;
+ while (batcher.createNextBatch(batch)) {
+ uint64_t bytesProcessedInSend;
+ ScopedTrace batchTrace(ATRACE_TAG, "VMA Batch");
+ do {
if (CC_UNLIKELY(cancelRunningCompaction.load())) {
// There could be a significant delay between when a compaction
// is requested and when it is handled during this time our
@@ -124,50 +299,18 @@
StringPrintf("Cancelled compaction for %d", pid).c_str());
return ERROR_COMPACTION_CANCELLED;
}
-
- uint64_t vmaStart = vmas[iVma].start + vmaOffset;
- uint64_t vmaSize = vmas[iVma].end - vmaStart;
- if (vmaSize == 0) {
- goto next_vma;
+ int error = madviseVmasFromBatch(pidfd, batch, madviseType, &bytesProcessedInSend);
+ if (error < 0) {
+ // Returns standard linux errno code
+ return error;
}
- vmasToKernel[iVec].iov_base = (void*)vmaStart;
- if (vmaSize > MAX_BYTES_PER_COMPACTION - bytesSentToCompact) {
- // Exceeded the max bytes that could be sent, so clamp
- // the end to avoid exceeding limit and issue compaction
- vmaSize = MAX_BYTES_PER_COMPACTION - bytesSentToCompact;
- }
-
- vmasToKernel[iVec].iov_len = vmaSize;
- bytesSentToCompact += vmaSize;
- ++iVec;
- if (bytesSentToCompact >= MAX_BYTES_PER_COMPACTION) {
- // Ran out of bytes within iovec, dispatch compaction.
- vmaOffset += vmaSize;
+ if (CC_UNLIKELY(bytesProcessedInSend == 0)) {
+ // This means there was a problem consuming bytes,
+ // bail out since no forward progress can be made with this batch
break;
}
-
- next_vma:
- // Finished current VMA, and have more bytes remaining
- vmaOffset = 0;
- ++iVma;
- }
-
- ATRACE_BEGIN(StringPrintf("Compact %d VMAs", iVec).c_str());
- auto bytesProcessed = process_madvise(pidfd, vmasToKernel, iVec, madviseType, 0);
- ATRACE_END();
-
- if (CC_UNLIKELY(bytesProcessed == -1)) {
- if (errno == EINVAL) {
- // This error is somewhat common due to an unevictable VMA if this is
- // the case silently skip the bad VMA and continue compacting the rest.
- continue;
- } else {
- // Forward irrecoverable errors and bail out compaction
- return -errno;
- }
- }
-
- totalBytesProcessed += bytesProcessed;
+ totalBytesProcessed += bytesProcessedInSend;
+ } while (batch.totalBytes > 0 && batch.totalVmas > 0);
}
return totalBytesProcessed;
@@ -203,6 +346,7 @@
static int64_t compactProcess(int pid, VmaToAdviseFunc vmaToAdviseFunc) {
cancelRunningCompaction.store(false);
+ ATRACE_BEGIN("CollectVmas");
ProcMemInfo meminfo(pid);
std::vector<Vma> pageoutVmas, coldVmas;
auto vmaCollectorCb = [&coldVmas,&pageoutVmas,&vmaToAdviseFunc](const Vma& vma) {
@@ -217,6 +361,7 @@
}
};
meminfo.ForEachVmaFromMaps(vmaCollectorCb);
+ ATRACE_END();
int64_t pageoutBytes = compactMemory(pageoutVmas, pid, MADV_PAGEOUT);
if (pageoutBytes < 0) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
index 3912991..0c69067 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
@@ -157,13 +157,14 @@
private static final String TAG_SSID_ALLOWLIST = "ssid-allowlist";
private static final String TAG_SSID_DENYLIST = "ssid-denylist";
private static final String TAG_SSID = "ssid";
- private static final String ATTR_VALUE = "value";
- private static final String ATTR_LAST_NETWORK_LOGGING_NOTIFICATION = "last-notification";
- private static final String ATTR_NUM_NETWORK_LOGGING_NOTIFICATIONS = "num-notifications";
private static final String TAG_PREFERENTIAL_NETWORK_SERVICE_CONFIGS =
"preferential_network_service_configs";
private static final String TAG_PREFERENTIAL_NETWORK_SERVICE_CONFIG =
"preferential_network_service_config";
+ private static final String TAG_PROTECTED_PACKAGES = "protected_packages";
+ private static final String ATTR_VALUE = "value";
+ private static final String ATTR_LAST_NETWORK_LOGGING_NOTIFICATION = "last-notification";
+ private static final String ATTR_NUM_NETWORK_LOGGING_NOTIFICATIONS = "num-notifications";
DeviceAdminInfo info;
@@ -253,6 +254,9 @@
// List of package names to keep cached.
List<String> keepUninstalledPackages;
+ // List of packages for which the user cannot invoke "clear data" or "force stop".
+ List<String> protectedPackages;
+
// Wi-Fi SSID restriction policy.
WifiSsidPolicy mWifiSsidPolicy;
@@ -505,6 +509,7 @@
permittedNotificationListeners);
writePackageListToXml(out, TAG_KEEP_UNINSTALLED_PACKAGES, keepUninstalledPackages);
writePackageListToXml(out, TAG_METERED_DATA_DISABLED_PACKAGES, meteredDisabledPackages);
+ writePackageListToXml(out, TAG_PROTECTED_PACKAGES, protectedPackages);
if (hasUserRestrictions()) {
UserRestrictionsUtils.writeRestrictions(
out, userRestrictions, TAG_USER_RESTRICTIONS);
@@ -771,6 +776,8 @@
keepUninstalledPackages = readPackageList(parser, tag);
} else if (TAG_METERED_DATA_DISABLED_PACKAGES.equals(tag)) {
meteredDisabledPackages = readPackageList(parser, tag);
+ } else if (TAG_PROTECTED_PACKAGES.equals(tag)) {
+ protectedPackages = readPackageList(parser, tag);
} else if (TAG_USER_RESTRICTIONS.equals(tag)) {
userRestrictions = UserRestrictionsUtils.readRestrictions(parser);
} else if (TAG_DEFAULT_ENABLED_USER_RESTRICTIONS.equals(tag)) {
@@ -1210,6 +1217,16 @@
pw.println(keepUninstalledPackages);
}
+ if (meteredDisabledPackages != null) {
+ pw.print("meteredDisabledPackages=");
+ pw.println(meteredDisabledPackages);
+ }
+
+ if (protectedPackages != null) {
+ pw.print("protectedPackages=");
+ pw.println(protectedPackages);
+ }
+
pw.print("organizationColor=");
pw.println(organizationColor);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java
index 48a436f..054181d 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java
@@ -17,6 +17,7 @@
package com.android.server.devicepolicy;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.admin.DeviceAdminInfo;
import android.app.admin.DevicePolicyManager;
@@ -66,7 +67,6 @@
private static final String TAG_CURRENT_INPUT_METHOD_SET = "current-ime-set";
private static final String TAG_OWNER_INSTALLED_CA_CERT = "owner-installed-ca-cert";
private static final String TAG_INITIALIZATION_BUNDLE = "initialization-bundle";
- private static final String TAG_PASSWORD_VALIDITY = "password-validity";
private static final String TAG_PASSWORD_TOKEN_HANDLE = "password-token";
private static final String TAG_PROTECTED_PACKAGES = "protected-packages";
private static final String TAG_BYPASS_ROLE_QUALIFICATIONS = "bypass-role-qualifications";
@@ -129,8 +129,10 @@
// This is the list of component allowed to start lock task mode.
List<String> mLockTaskPackages = new ArrayList<>();
- // List of packages protected by device owner
- List<String> mUserControlDisabledPackages = new ArrayList<>();
+ /** @deprecated moved to {@link ActiveAdmin#protectedPackages}. */
+ @Deprecated
+ @Nullable
+ List<String> mUserControlDisabledPackages;
// Bitfield of feature flags to be enabled during LockTask mode.
// We default on the power button menu, in order to be consistent with pre-P behaviour.
@@ -181,7 +183,7 @@
/**
* Serializes DevicePolicyData object as XML.
*/
- static boolean store(DevicePolicyData policyData, JournaledFile file, boolean isFdeDevice) {
+ static boolean store(DevicePolicyData policyData, JournaledFile file) {
FileOutputStream stream = null;
File chooseForWrite = null;
try {
@@ -266,15 +268,6 @@
out.endTag(null, "failed-password-attempts");
}
- // For FDE devices only, we save this flag so we can report on password sufficiency
- // before the user enters their password for the first time after a reboot. For
- // security reasons, we don't want to store the full set of active password metrics.
- if (isFdeDevice) {
- out.startTag(null, TAG_PASSWORD_VALIDITY);
- out.attributeBoolean(null, ATTR_VALUE, policyData.mPasswordValidAtLastCheckpoint);
- out.endTag(null, TAG_PASSWORD_VALIDITY);
- }
-
for (int i = 0; i < policyData.mAcceptedCaCertificates.size(); i++) {
out.startTag(null, TAG_ACCEPTED_CA_CERTIFICATES);
out.attribute(null, ATTR_NAME, policyData.mAcceptedCaCertificates.valueAt(i));
@@ -364,13 +357,6 @@
out.endTag(null, TAG_OWNER_INSTALLED_CA_CERT);
}
- for (int i = 0, size = policyData.mUserControlDisabledPackages.size(); i < size; i++) {
- String packageName = policyData.mUserControlDisabledPackages.get(i);
- out.startTag(null, TAG_PROTECTED_PACKAGES);
- out.attribute(null, ATTR_NAME, packageName);
- out.endTag(null, TAG_PROTECTED_PACKAGES);
- }
-
if (policyData.mAppsSuspended) {
out.startTag(null, TAG_APPS_SUSPENDED);
out.attributeBoolean(null, ATTR_VALUE, policyData.mAppsSuspended);
@@ -409,7 +395,7 @@
* @param adminInfoSupplier function that queries DeviceAdminInfo from PackageManager
* @param ownerComponent device or profile owner component if any.
*/
- static void load(DevicePolicyData policy, boolean isFdeDevice, JournaledFile journaledFile,
+ static void load(DevicePolicyData policy, JournaledFile journaledFile,
Function<ComponentName, DeviceAdminInfo> adminInfoSupplier,
ComponentName ownerComponent) {
FileInputStream stream = null;
@@ -473,7 +459,7 @@
policy.mAdminMap.clear();
policy.mAffiliationIds.clear();
policy.mOwnerInstalledCaCerts.clear();
- policy.mUserControlDisabledPackages.clear();
+ policy.mUserControlDisabledPackages = null;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
@@ -549,27 +535,25 @@
policy.mAdminBroadcastPending = Boolean.toString(true).equals(pending);
} else if (TAG_INITIALIZATION_BUNDLE.equals(tag)) {
policy.mInitBundle = PersistableBundle.restoreFromXml(parser);
- } else if (TAG_PASSWORD_VALIDITY.equals(tag)) {
- if (isFdeDevice) {
- // This flag is only used for FDE devices
- policy.mPasswordValidAtLastCheckpoint =
- parser.getAttributeBoolean(null, ATTR_VALUE, false);
- }
} else if (TAG_PASSWORD_TOKEN_HANDLE.equals(tag)) {
policy.mPasswordTokenHandle = parser.getAttributeLong(null, ATTR_VALUE);
} else if (TAG_CURRENT_INPUT_METHOD_SET.equals(tag)) {
policy.mCurrentInputMethodSet = true;
} else if (TAG_OWNER_INSTALLED_CA_CERT.equals(tag)) {
policy.mOwnerInstalledCaCerts.add(parser.getAttributeValue(null, ATTR_ALIAS));
- } else if (TAG_PROTECTED_PACKAGES.equals(tag)) {
- policy.mUserControlDisabledPackages.add(
- parser.getAttributeValue(null, ATTR_NAME));
} else if (TAG_APPS_SUSPENDED.equals(tag)) {
policy.mAppsSuspended =
parser.getAttributeBoolean(null, ATTR_VALUE, false);
} else if (TAG_BYPASS_ROLE_QUALIFICATIONS.equals(tag)) {
policy.mBypassDevicePolicyManagementRoleQualifications = true;
policy.mCurrentRoleHolder = parser.getAttributeValue(null, ATTR_VALUE);
+ // Deprecated tags below
+ } else if (TAG_PROTECTED_PACKAGES.equals(tag)) {
+ if (policy.mUserControlDisabledPackages == null) {
+ policy.mUserControlDisabledPackages = new ArrayList<>();
+ }
+ policy.mUserControlDisabledPackages.add(
+ parser.getAttributeValue(null, ATTR_NAME));
} else {
Slogf.w(TAG, "Unknown tag: %s", tag);
XmlUtils.skipCurrentTag(parser);
@@ -674,8 +658,6 @@
pw.increaseIndent();
pw.print("mPasswordOwner="); pw.println(mPasswordOwner);
pw.print("mPasswordTokenHandle="); pw.println(Long.toHexString(mPasswordTokenHandle));
- pw.print("mUserControlDisabledPackages=");
- pw.println(mUserControlDisabledPackages);
pw.print("mAppsSuspended="); pw.println(mAppsSuspended);
pw.print("mUserSetupComplete="); pw.println(mUserSetupComplete);
pw.print("mAffiliationIds="); pw.println(mAffiliationIds);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 7f5475c..ba547f8 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -536,7 +536,7 @@
// to decide whether an existing policy in the {@link #DEVICE_POLICIES_XML} needs to
// be upgraded. See {@link PolicyVersionUpgrader} on instructions how to add an upgrade
// step.
- static final int DPMS_VERSION = 2;
+ static final int DPMS_VERSION = 3;
static {
SECURE_SETTINGS_ALLOWLIST = new ArraySet<>();
@@ -1908,39 +1908,12 @@
if (userHandle == UserHandle.USER_SYSTEM) {
mStateCache.setDeviceProvisioned(policy.mUserSetupComplete);
}
-
- migrateDeviceOwnerProtectedPackagesToOwners(userHandle, policy);
}
return policy;
}
}
/**
- * Only used by {@link #getUserData(int)} to migrate <b>existing</b> device owner protected
- * packages that were stored in {@link DevicePolicyData#mUserControlDisabledPackages} to
- * {@link Owners} because the device owner protected packages are now stored on a per device
- * owner basis instead of on a per user basis.
- *
- * Any calls to {@link #setUserControlDisabledPackages(ComponentName, List)} would now store
- * the device owner protected packages in {@link Owners} instead of {@link DevicePolicyData}.
- * @param userHandle The device owner user
- * @param policy The policy data of the device owner user
- */
- private void migrateDeviceOwnerProtectedPackagesToOwners(
- int userHandle, DevicePolicyData policy) {
- ComponentName deviceOwnerComponent = getOwnerComponent(userHandle);
- if (isDeviceOwner(deviceOwnerComponent, userHandle)
- && !policy.mUserControlDisabledPackages.isEmpty()) {
- mOwners.setDeviceOwnerProtectedPackages(
- deviceOwnerComponent.getPackageName(),
- policy.mUserControlDisabledPackages);
-
- policy.mUserControlDisabledPackages = new ArrayList<>();
- saveSettingsLocked(userHandle);
- }
- }
-
- /**
* Creates and loads the policy data from xml for data that is shared between
* various profiles of a user. In contrast to {@link #getUserData(int)}
* it allows access to data of users other than the calling user.
@@ -1964,6 +1937,9 @@
updatePasswordQualityCacheForUserGroup(userHandle);
mPolicyCache.onUserRemoved(userHandle);
+ if (isManagedProfile(userHandle)) {
+ clearManagedProfileApnUnchecked();
+ }
isOrgOwned = mOwners.isProfileOwnerOfOrganizationOwnedDevice(userHandle);
mOwners.removeProfileOwner(userHandle);
@@ -2904,10 +2880,7 @@
}
private void saveSettingsLocked(int userHandle) {
- if (DevicePolicyData.store(
- getUserData(userHandle),
- makeJournaledFile(userHandle),
- !mInjector.storageManagerIsFileBasedEncryptionEnabled())) {
+ if (DevicePolicyData.store(getUserData(userHandle), makeJournaledFile(userHandle))) {
sendChangedNotification(userHandle);
}
invalidateBinderCaches();
@@ -2922,7 +2895,6 @@
private void loadSettingsLocked(DevicePolicyData policy, int userHandle) {
DevicePolicyData.load(policy,
- !mInjector.storageManagerIsFileBasedEncryptionEnabled(),
makeJournaledFile(userHandle),
component -> findAdmin(
component, userHandle, /* throwForMissingPermission= */ false),
@@ -3088,11 +3060,6 @@
// TODO(b/230841522) Make it static.
private class DpmsUpgradeDataProvider implements PolicyUpgraderDataProvider {
@Override
- public boolean storageManagerIsFileBasedEncryptionEnabled() {
- return mInjector.storageManagerIsFileBasedEncryptionEnabled();
- }
-
- @Override
public JournaledFile makeDevicePoliciesJournaledFile(int userId) {
return DevicePolicyManagerService.this.makeJournaledFile(userId, DEVICE_POLICIES_XML);
}
@@ -3141,6 +3108,7 @@
deleteTransferOwnershipBundleLocked(metadata.userId);
}
updateSystemUpdateFreezePeriodsRecord(/* saveIfChanged */ true);
+ pushUserControlDisabledPackagesLocked(metadata.userId);
}
private void maybeLogStart() {
@@ -3180,6 +3148,7 @@
void handleStartUser(int userId) {
synchronized (getLockObject()) {
pushScreenCapturePolicy(userId);
+ pushUserControlDisabledPackagesLocked(userId);
}
pushUserRestrictions(userId);
// When system user is started (device boot), load cache for all users.
@@ -3202,6 +3171,24 @@
startOwnerService(userId, "start-user");
}
+ void pushUserControlDisabledPackagesLocked(int userId) {
+ final int targetUserId;
+ final ActiveAdmin owner;
+ if (getDeviceOwnerUserIdUncheckedLocked() == userId) {
+ owner = getDeviceOwnerAdminLocked();
+ targetUserId = UserHandle.USER_ALL;
+ } else {
+ owner = getProfileOwnerAdminLocked(userId);
+ targetUserId = userId;
+ }
+
+ List<String> protectedPackages = (owner == null || owner.protectedPackages == null)
+ ? Collections.emptyList() : owner.protectedPackages;
+ mInjector.binderWithCleanCallingIdentity(() ->
+ mInjector.getPackageManagerInternal().setOwnerProtectedPackages(
+ targetUserId, protectedPackages));
+ }
+
@Override
void handleUnlockUser(int userId) {
startOwnerService(userId, "unlock-user");
@@ -3562,6 +3549,11 @@
final CallerIdentity caller = getCallerIdentity();
Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle));
+ if (mInjector.getPackageManagerInternal().filterAppAccess(packageName, caller.getUid(),
+ userHandle)) {
+ return false;
+ }
+
synchronized (getLockObject()) {
DevicePolicyData policy = getUserData(userHandle);
final int N = policy.mAdminList.size();
@@ -8765,6 +8757,18 @@
}
}
+ private void clearManagedProfileApnUnchecked() {
+ if (!mHasTelephonyFeature) {
+ return;
+ }
+ final List<ApnSetting> apns = getOverrideApnsUnchecked();
+ for (ApnSetting apn : apns) {
+ if (apn.getApnTypeBitmask() == ApnSetting.TYPE_ENTERPRISE) {
+ removeOverrideApnUnchecked(apn.getId());
+ }
+ }
+ }
+
private void clearDeviceOwnerLocked(ActiveAdmin admin, int userId) {
mDeviceAdminServiceController.stopServiceForOwner(userId, "clear-device-owner");
@@ -8800,6 +8804,7 @@
setNetworkLoggingActiveInternal(false);
deleteTransferOwnershipBundleLocked(userId);
toggleBackupServiceActive(UserHandle.USER_SYSTEM, true);
+ pushUserControlDisabledPackagesLocked(userId);
}
private void clearApplicationRestrictions(int userId) {
@@ -8984,7 +8989,6 @@
policy.mLockTaskPackages.clear();
updateLockTaskPackagesLocked(policy.mLockTaskPackages, userId);
policy.mLockTaskFeatures = DevicePolicyManager.LOCK_TASK_FEATURE_NONE;
- policy.mUserControlDisabledPackages.clear();
saveSettingsLocked(userId);
try {
@@ -12098,6 +12102,10 @@
}
}
+ private boolean isManagedProfileOwner(CallerIdentity caller) {
+ return isProfileOwner(caller) && isManagedProfile(caller.getUserId());
+ }
+
private boolean isDefaultSupervisor(CallerIdentity caller) {
final String supervisor = mContext.getResources().getString(
com.android.internal.R.string.config_defaultSupervisionProfileOwnerComponent);
@@ -16298,7 +16306,7 @@
final CallerIdentity caller = getCallerIdentity(who);
if (apnSetting.getApnTypeBitmask() == ApnSetting.TYPE_ENTERPRISE) {
Preconditions.checkCallAuthorization(isDefaultDeviceOwner(caller)
- || isProfileOwner(caller));
+ || isManagedProfileOwner(caller));
} else {
Preconditions.checkCallAuthorization(isDefaultDeviceOwner(caller));
}
@@ -16326,7 +16334,7 @@
if (apn != null && apn.getApnTypeBitmask() == ApnSetting.TYPE_ENTERPRISE
&& apnSetting.getApnTypeBitmask() == ApnSetting.TYPE_ENTERPRISE) {
Preconditions.checkCallAuthorization(isDefaultDeviceOwner(caller)
- || isProfileOwner(caller));
+ || isManagedProfileOwner(caller));
} else {
Preconditions.checkCallAuthorization(isDefaultDeviceOwner(caller));
}
@@ -16354,7 +16362,7 @@
ApnSetting apn = getApnSetting(apnId);
if (apn != null && apn.getApnTypeBitmask() == ApnSetting.TYPE_ENTERPRISE) {
Preconditions.checkCallAuthorization(isDefaultDeviceOwner(caller)
- || isProfileOwner(caller));
+ || isManagedProfileOwner(caller));
} else {
Preconditions.checkCallAuthorization(isDefaultDeviceOwner(caller));
}
@@ -16399,8 +16407,20 @@
}
Objects.requireNonNull(who, "ComponentName is null");
final CallerIdentity caller = getCallerIdentity(who);
- Preconditions.checkCallAuthorization(isDefaultDeviceOwner(caller));
- return getOverrideApnsUnchecked();
+ Preconditions.checkCallAuthorization(isDefaultDeviceOwner(caller)
+ || isManagedProfileOwner(caller));
+ List<ApnSetting> apnSettings = getOverrideApnsUnchecked();
+ if (isProfileOwner(caller)) {
+ List<ApnSetting> apnSettingList = new ArrayList<>();
+ for (ApnSetting apnSetting : apnSettings) {
+ if (apnSetting.getApnTypeBitmask() == ApnSetting.TYPE_ENTERPRISE) {
+ apnSettingList.add(apnSetting);
+ }
+ }
+ return apnSettingList;
+ } else {
+ return apnSettings;
+ }
}
private List<ApnSetting> getOverrideApnsUnchecked() {
@@ -16970,19 +16990,25 @@
Objects.requireNonNull(who, "ComponentName is null");
Objects.requireNonNull(packages, "packages is null");
final CallerIdentity caller = getCallerIdentity(who);
- Preconditions.checkCallAuthorization(
- isDefaultDeviceOwner(caller) || isFinancedDeviceOwner(caller));
+ Preconditions.checkCallAuthorization(isDefaultDeviceOwner(caller) || isProfileOwner(caller)
+ || isFinancedDeviceOwner(caller));
checkCanExecuteOrThrowUnsafe(
DevicePolicyManager.OPERATION_SET_USER_CONTROL_DISABLED_PACKAGES);
synchronized (getLockObject()) {
- mOwners.setDeviceOwnerProtectedPackages(who.getPackageName(), packages);
- DevicePolicyEventLogger
- .createEvent(DevicePolicyEnums.SET_USER_CONTROL_DISABLED_PACKAGES)
- .setAdmin(who)
- .setStrings(packages.toArray(new String[packages.size()]))
- .write();
+ ActiveAdmin owner = getDeviceOrProfileOwnerAdminLocked(caller.getUserId());
+ if (!Objects.equals(owner.protectedPackages, packages)) {
+ owner.protectedPackages = packages.isEmpty() ? null : packages;
+ saveSettingsLocked(caller.getUserId());
+ pushUserControlDisabledPackagesLocked(caller.getUserId());
+ }
}
+
+ DevicePolicyEventLogger
+ .createEvent(DevicePolicyEnums.SET_USER_CONTROL_DISABLED_PACKAGES)
+ .setAdmin(who)
+ .setStrings(packages.toArray(new String[packages.size()]))
+ .write();
}
@Override
@@ -16990,11 +17016,13 @@
Objects.requireNonNull(who, "ComponentName is null");
final CallerIdentity caller = getCallerIdentity(who);
- Preconditions.checkCallAuthorization(
- isDefaultDeviceOwner(caller) || isFinancedDeviceOwner(caller));
+ Preconditions.checkCallAuthorization(isDefaultDeviceOwner(caller) || isProfileOwner(caller)
+ || isFinancedDeviceOwner(caller));
synchronized (getLockObject()) {
- return mOwners.getDeviceOwnerProtectedPackages(who.getPackageName());
+ ActiveAdmin deviceOwner = getDeviceOrProfileOwnerAdminLocked(caller.getUserId());
+ return deviceOwner.protectedPackages != null
+ ? deviceOwner.protectedPackages : Collections.emptyList();
}
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
index d1c6b34..08bd3e4 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
@@ -31,7 +31,6 @@
import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
-import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.IndentingPrintWriter;
import android.util.Pair;
@@ -49,7 +48,6 @@
import java.io.File;
import java.time.LocalDate;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Set;
@@ -108,12 +106,6 @@
notifyChangeLocked();
pushToActivityTaskManagerLocked();
-
- for (ArrayMap.Entry<String, List<String>> entry :
- mData.mDeviceOwnerProtectedPackages.entrySet()) {
- mPackageManagerInternal.setDeviceOwnerProtectedPackages(
- entry.getKey(), entry.getValue());
- }
}
}
@@ -247,12 +239,6 @@
void clearDeviceOwner() {
synchronized (mData) {
mData.mDeviceOwnerTypes.remove(mData.mDeviceOwner.packageName);
- List<String> protectedPackages =
- mData.mDeviceOwnerProtectedPackages.remove(mData.mDeviceOwner.packageName);
- if (protectedPackages != null) {
- mPackageManagerInternal.setDeviceOwnerProtectedPackages(
- mData.mDeviceOwner.packageName, new ArrayList<>());
- }
mData.mDeviceOwner = null;
mData.mDeviceOwnerUserId = UserHandle.USER_NULL;
@@ -296,12 +282,6 @@
synchronized (mData) {
Integer previousDeviceOwnerType = mData.mDeviceOwnerTypes.remove(
mData.mDeviceOwner.packageName);
- List<String> previousProtectedPackages =
- mData.mDeviceOwnerProtectedPackages.remove(mData.mDeviceOwner.packageName);
- if (previousProtectedPackages != null) {
- mPackageManagerInternal.setDeviceOwnerProtectedPackages(
- mData.mDeviceOwner.packageName, new ArrayList<>());
- }
// We don't set a name because it's not used anyway.
// See DevicePolicyManagerService#getDeviceOwnerName
mData.mDeviceOwner = new OwnerInfo(null, target,
@@ -313,10 +293,6 @@
mData.mDeviceOwnerTypes.put(
mData.mDeviceOwner.packageName, previousDeviceOwnerType);
}
- if (previousProtectedPackages != null) {
- mData.mDeviceOwnerProtectedPackages.put(
- mData.mDeviceOwner.packageName, previousProtectedPackages);
- }
notifyChangeLocked();
pushToActivityTaskManagerLocked();
}
@@ -504,34 +480,6 @@
}
}
- void setDeviceOwnerProtectedPackages(String packageName, List<String> protectedPackages) {
- synchronized (mData) {
- if (!hasDeviceOwner()) {
- Slog.e(TAG,
- "Attempting to set device owner protected packages when there is no "
- + "device owner");
- return;
- } else if (!mData.mDeviceOwner.packageName.equals(packageName)) {
- Slog.e(TAG, "Attempting to set device owner protected packages when the provided "
- + "package name " + packageName
- + " does not match the device owner package name");
- return;
- }
-
- mData.mDeviceOwnerProtectedPackages.put(packageName, protectedPackages);
- mPackageManagerInternal.setDeviceOwnerProtectedPackages(packageName, protectedPackages);
- writeDeviceOwner();
- }
- }
-
- List<String> getDeviceOwnerProtectedPackages(String packageName) {
- synchronized (mData) {
- return mData.mDeviceOwnerProtectedPackages.containsKey(packageName)
- ? mData.mDeviceOwnerProtectedPackages.get(packageName)
- : Collections.emptyList();
- }
- }
-
void writeDeviceOwner() {
synchronized (mData) {
pushToDevicePolicyManager();
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/OwnersData.java b/services/devicepolicy/java/com/android/server/devicepolicy/OwnersData.java
index 4fe4f0d..6948420 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/OwnersData.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/OwnersData.java
@@ -91,8 +91,10 @@
// Device owner type for a managed device.
final ArrayMap<String, Integer> mDeviceOwnerTypes = new ArrayMap<>();
- final ArrayMap<String, List<String>> mDeviceOwnerProtectedPackages = new ArrayMap<>();
-
+ /** @deprecated moved to {@link ActiveAdmin#protectedPackages}. */
+ @Deprecated
+ @Nullable
+ ArrayMap<String, List<String>> mDeviceOwnerProtectedPackages;
// Internal state for the profile owner packages.
final ArrayMap<Integer, OwnerInfo> mProfileOwners = new ArrayMap<>();
@@ -366,21 +368,6 @@
}
}
- if (!mDeviceOwnerProtectedPackages.isEmpty()) {
- for (ArrayMap.Entry<String, List<String>> entry :
- mDeviceOwnerProtectedPackages.entrySet()) {
- List<String> protectedPackages = entry.getValue();
-
- out.startTag(null, TAG_DEVICE_OWNER_PROTECTED_PACKAGES);
- out.attribute(null, ATTR_PACKAGE, entry.getKey());
- out.attributeInt(null, ATTR_SIZE, protectedPackages.size());
- for (int i = 0, size = protectedPackages.size(); i < size; i++) {
- out.attribute(null, ATTR_NAME + i, protectedPackages.get(i));
- }
- out.endTag(null, TAG_DEVICE_OWNER_PROTECTED_PACKAGES);
- }
- }
-
if (mSystemUpdatePolicy != null) {
out.startTag(null, TAG_SYSTEM_UPDATE_POLICY);
mSystemUpdatePolicy.saveToXml(out);
@@ -444,6 +431,7 @@
null, ATTR_DEVICE_OWNER_TYPE_VALUE, DEVICE_OWNER_TYPE_DEFAULT);
mDeviceOwnerTypes.put(packageName, deviceOwnerType);
break;
+ // Deprecated fields below.
case TAG_DEVICE_OWNER_PROTECTED_PACKAGES:
packageName = parser.getAttributeValue(null, ATTR_PACKAGE);
int protectedPackagesSize = parser.getAttributeInt(null, ATTR_SIZE, 0);
@@ -451,6 +439,9 @@
for (int i = 0; i < protectedPackagesSize; i++) {
protectedPackages.add(parser.getAttributeValue(null, ATTR_NAME + i));
}
+ if (mDeviceOwnerProtectedPackages == null) {
+ mDeviceOwnerProtectedPackages = new ArrayMap<>();
+ }
mDeviceOwnerProtectedPackages.put(packageName, protectedPackages);
break;
default:
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyUpgraderDataProvider.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyUpgraderDataProvider.java
index 7b7a454..1474749 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyUpgraderDataProvider.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyUpgraderDataProvider.java
@@ -29,11 +29,6 @@
*/
public interface PolicyUpgraderDataProvider {
/**
- * Returns true if the storage manager indicates file-based encryption is enabled.
- */
- boolean storageManagerIsFileBasedEncryptionEnabled();
-
- /**
* Returns the journaled policies file for a given user.
*/
JournaledFile makeDevicePoliciesJournaledFile(int userId);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyVersionUpgrader.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyVersionUpgrader.java
index 7556d69..8081331 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyVersionUpgrader.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyVersionUpgrader.java
@@ -16,6 +16,7 @@
package com.android.server.devicepolicy;
+import android.annotation.Nullable;
import android.content.ComponentName;
import android.os.UserHandle;
import android.util.Slog;
@@ -28,6 +29,8 @@
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
+import java.util.ArrayList;
+import java.util.List;
/**
* Class for dealing with Device Policy Manager Service version upgrades.
@@ -91,30 +94,82 @@
if (currentVersion == 1) {
Slog.i(LOG_TAG, String.format("Upgrading from version %d", currentVersion));
- // This upgrade step is for Device Owner scenario only: For devices upgrading to S,
- // if there is a device owner, it retains the ability to control sensors-related
- // permission grants.
- for (int userId : allUsers) {
- DevicePolicyData userData = allUsersData.get(userId);
- if (userData == null) {
- continue;
- }
- for (ActiveAdmin admin : userData.mAdminList) {
- if (ownersData.mDeviceOwnerUserId == userId
- && ownersData.mDeviceOwner != null
- && ownersData.mDeviceOwner.admin.equals(admin.info.getComponent())) {
- Slog.i(LOG_TAG, String.format(
- "Marking Device Owner in user %d for permission grant ", userId));
- admin.mAdminCanGrantSensorsPermissions = true;
- }
- }
- }
+ upgradeSensorPermissionsAccess(allUsers, ownersData, allUsersData);
currentVersion = 2;
}
+ if (currentVersion == 2) {
+ Slog.i(LOG_TAG, String.format("Upgrading from version %d", currentVersion));
+ upgradeProtectedPackages(ownersData, allUsersData);
+ currentVersion = 3;
+ }
+
writePoliciesAndVersion(allUsers, allUsersData, ownersData, currentVersion);
}
+ /**
+ * This upgrade step is for Device Owner scenario only: For devices upgrading to S, if there is
+ * a device owner, it retains the ability to control sensors-related permission grants.
+ */
+ private void upgradeSensorPermissionsAccess(
+ int[] allUsers, OwnersData ownersData, SparseArray<DevicePolicyData> allUsersData) {
+ for (int userId : allUsers) {
+ DevicePolicyData userData = allUsersData.get(userId);
+ if (userData == null) {
+ continue;
+ }
+ for (ActiveAdmin admin : userData.mAdminList) {
+ if (ownersData.mDeviceOwnerUserId == userId
+ && ownersData.mDeviceOwner != null
+ && ownersData.mDeviceOwner.admin.equals(admin.info.getComponent())) {
+ Slog.i(LOG_TAG, String.format(
+ "Marking Device Owner in user %d for permission grant ", userId));
+ admin.mAdminCanGrantSensorsPermissions = true;
+ }
+ }
+ }
+ }
+
+ /**
+ * This upgrade step moves device owner protected packages to ActiveAdmin.
+ * Initially these packages were stored in DevicePolicyData, then moved to Owners without
+ * employing PolicyVersionUpgrader. Here we check both places.
+ */
+ private void upgradeProtectedPackages(
+ OwnersData ownersData, SparseArray<DevicePolicyData> allUsersData) {
+ if (ownersData.mDeviceOwner == null) {
+ return;
+ }
+ List<String> protectedPackages = null;
+ DevicePolicyData doUserData = allUsersData.get(ownersData.mDeviceOwnerUserId);
+ if (doUserData == null) {
+ Slog.e(LOG_TAG, "No policy data for do user");
+ return;
+ }
+ if (ownersData.mDeviceOwnerProtectedPackages != null) {
+ protectedPackages = ownersData.mDeviceOwnerProtectedPackages
+ .get(ownersData.mDeviceOwner.packageName);
+ if (protectedPackages != null) {
+ Slog.i(LOG_TAG, "Found protected packages in Owners");
+ }
+ ownersData.mDeviceOwnerProtectedPackages = null;
+ } else if (doUserData.mUserControlDisabledPackages != null) {
+ Slog.i(LOG_TAG, "Found protected packages in DevicePolicyData");
+ protectedPackages = doUserData.mUserControlDisabledPackages;
+ doUserData.mUserControlDisabledPackages = null;
+ }
+
+ ActiveAdmin doAdmin = doUserData.mAdminMap.get(ownersData.mDeviceOwner.admin);
+ if (doAdmin == null) {
+ Slog.e(LOG_TAG, "DO admin not found in DO user");
+ return;
+ }
+
+ if (protectedPackages != null) {
+ doAdmin.protectedPackages = new ArrayList<>(protectedPackages);
+ }
+ }
+
private OwnersData loadOwners(int[] allUsers) {
OwnersData ownersData = new OwnersData(mPathProvider);
ownersData.load(allUsers);
@@ -146,22 +201,27 @@
OwnersData ownersData) {
final SparseArray<DevicePolicyData> allUsersData = new SparseArray<>();
for (int user: allUsers) {
- ComponentName owner = null;
- if (ownersData.mDeviceOwnerUserId == user && ownersData.mDeviceOwner != null) {
- owner = ownersData.mDeviceOwner.admin;
- } else if (ownersData.mProfileOwners.containsKey(user)) {
- owner = ownersData.mProfileOwners.get(user).admin;
- }
+ ComponentName owner = getOwnerForUser(ownersData, user);
allUsersData.append(user, loadDataForUser(user, loadVersion, owner));
}
return allUsersData;
}
+ @Nullable
+ private ComponentName getOwnerForUser(OwnersData ownersData, int user) {
+ ComponentName owner = null;
+ if (ownersData.mDeviceOwnerUserId == user && ownersData.mDeviceOwner != null) {
+ owner = ownersData.mDeviceOwner.admin;
+ } else if (ownersData.mProfileOwners.containsKey(user)) {
+ owner = ownersData.mProfileOwners.get(user).admin;
+ }
+ return owner;
+ }
+
private DevicePolicyData loadDataForUser(
int userId, int loadVersion, ComponentName ownerComponent) {
DevicePolicyData policy = new DevicePolicyData(userId);
DevicePolicyData.load(policy,
- !mProvider.storageManagerIsFileBasedEncryptionEnabled(),
mProvider.makeDevicePoliciesJournaledFile(userId),
mProvider.getAdminInfoSupplier(userId),
ownerComponent);
@@ -169,10 +229,7 @@
}
private boolean writeDataForUser(int userId, DevicePolicyData policy) {
- return DevicePolicyData.store(
- policy,
- mProvider.makeDevicePoliciesJournaledFile(userId),
- !mProvider.storageManagerIsFileBasedEncryptionEnabled());
+ return DevicePolicyData.store(policy, mProvider.makeDevicePoliciesJournaledFile(userId));
}
private JournaledFile getVersionFile() {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 319e63f..05bccd9 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -651,19 +651,14 @@
mFactoryTestMode = FactoryTest.getMode();
// Record process start information.
- // Note SYSPROP_START_COUNT will increment by *2* on a FDE device when it fully boots;
- // one for the password screen, second for the actual boot.
mStartCount = SystemProperties.getInt(SYSPROP_START_COUNT, 0) + 1;
mRuntimeStartElapsedTime = SystemClock.elapsedRealtime();
mRuntimeStartUptime = SystemClock.uptimeMillis();
Process.setStartTimes(mRuntimeStartElapsedTime, mRuntimeStartUptime,
mRuntimeStartElapsedTime, mRuntimeStartUptime);
- // Remember if it's runtime restart(when sys.boot_completed is already set) or reboot
- // We don't use "mStartCount > 1" here because it'll be wrong on a FDE device.
- // TODO: mRuntimeRestart will *not* be set to true if the proccess crashes before
- // sys.boot_completed is set. Fix it.
- mRuntimeRestart = "1".equals(SystemProperties.get("sys.boot_completed"));
+ // Remember if it's runtime restart or reboot.
+ mRuntimeRestart = mStartCount > 1;
}
@Override
@@ -1054,6 +1049,7 @@
t.traceBegin("StartWatchdog");
final Watchdog watchdog = Watchdog.getInstance();
watchdog.start();
+ mDumper.addDumpable(watchdog);
t.traceEnd();
Slog.i(TAG, "Reading configuration...");
diff --git a/services/tests/PackageManagerServiceTests/appenumeration/src/com/android/server/pm/test/appenumeration/CrossUserPackageVisibilityTests.java b/services/tests/PackageManagerServiceTests/appenumeration/src/com/android/server/pm/test/appenumeration/CrossUserPackageVisibilityTests.java
index a7ba45f..d7b442c 100644
--- a/services/tests/PackageManagerServiceTests/appenumeration/src/com/android/server/pm/test/appenumeration/CrossUserPackageVisibilityTests.java
+++ b/services/tests/PackageManagerServiceTests/appenumeration/src/com/android/server/pm/test/appenumeration/CrossUserPackageVisibilityTests.java
@@ -27,6 +27,8 @@
import android.content.Context;
import android.content.pm.IPackageManager;
import android.content.pm.KeySet;
+import android.content.pm.PackageManager;
+import android.os.Process;
import android.os.UserHandle;
import androidx.test.platform.app.InstrumentationRegistry;
@@ -56,8 +58,12 @@
private static final String TEST_DATA_DIR = "/data/local/tmp/appenumerationtests";
private static final String CROSS_USER_TEST_PACKAGE_NAME =
"com.android.appenumeration.crossuserpackagevisibility";
+ private static final String SHARED_USER_TEST_PACKAGE_NAME =
+ "com.android.appenumeration.shareduid";
private static final File CROSS_USER_TEST_APK_FILE =
new File(TEST_DATA_DIR, "AppEnumerationCrossUserPackageVisibilityTestApp.apk");
+ private static final File SHARED_USER_TEST_APK_FILE =
+ new File(TEST_DATA_DIR, "AppEnumerationSharedUserTestApp.apk");
@ClassRule
@Rule
@@ -66,6 +72,7 @@
private Instrumentation mInstrumentation;
private IPackageManager mIPackageManager;
private Context mContext;
+ private UserReference mCurrentUser;
private UserReference mOtherUser;
@Before
@@ -77,17 +84,21 @@
// Get another user
final UserReference primaryUser = sDeviceState.primaryUser();
if (primaryUser.id() == UserHandle.myUserId()) {
+ mCurrentUser = primaryUser;
mOtherUser = sDeviceState.secondaryUser();
} else {
+ mCurrentUser = sDeviceState.secondaryUser();
mOtherUser = primaryUser;
}
uninstallPackage(CROSS_USER_TEST_PACKAGE_NAME);
+ uninstallPackage(SHARED_USER_TEST_PACKAGE_NAME);
}
@After
public void tearDown() {
uninstallPackage(CROSS_USER_TEST_PACKAGE_NAME);
+ uninstallPackage(SHARED_USER_TEST_PACKAGE_NAME);
}
@Test
@@ -151,16 +162,61 @@
assertThat(e1.getMessage()).isEqualTo(e2.getMessage());
}
+ @Test
+ public void testGetFlagsForUid_cannotDetectCrossUserPkg() throws Exception {
+ installPackage(CROSS_USER_TEST_APK_FILE);
+ final int uid = mContext.getPackageManager().getPackageUid(
+ CROSS_USER_TEST_PACKAGE_NAME, PackageManager.PackageInfoFlags.of(0));
+
+ uninstallPackageForUser(CROSS_USER_TEST_PACKAGE_NAME, mCurrentUser);
+
+ assertThat(mIPackageManager.getFlagsForUid(uid)).isEqualTo(0);
+ }
+
+ @Test
+ public void testGetUidForSharedUser_cannotDetectSharedUserPkg() throws Exception {
+ assertThat(mIPackageManager.getUidForSharedUser(SHARED_USER_TEST_PACKAGE_NAME))
+ .isEqualTo(Process.INVALID_UID);
+
+ installPackageForUser(SHARED_USER_TEST_APK_FILE, mOtherUser, true /* forceQueryable */);
+
+ assertThat(mIPackageManager.getUidForSharedUser(SHARED_USER_TEST_PACKAGE_NAME))
+ .isEqualTo(Process.INVALID_UID);
+ }
+
+ private static void installPackage(File apk) {
+ installPackageForUser(apk, null, false /* forceQueryable */);
+ }
+
private static void installPackageForUser(File apk, UserReference user) {
+ installPackageForUser(apk, user, false /* forceQueryable */);
+ }
+
+ private static void installPackageForUser(File apk, UserReference user,
+ boolean forceQueryable) {
assertThat(apk.exists()).isTrue();
- final StringBuilder cmd = new StringBuilder("pm install --user ");
- cmd.append(user.id()).append(" ");
+ final StringBuilder cmd = new StringBuilder("pm install -t ");
+ if (forceQueryable) {
+ cmd.append("--force-queryable ");
+ }
+ if (user != null) {
+ cmd.append("--user ").append(user.id()).append(" ");
+ }
cmd.append(apk.getPath());
final String result = runShellCommand(cmd.toString());
assertThat(result.trim()).contains("Success");
}
private static void uninstallPackage(String packageName) {
- runShellCommand("pm uninstall " + packageName);
+ uninstallPackageForUser(packageName, null /* user */);
+ }
+
+ private static void uninstallPackageForUser(String packageName, UserReference user) {
+ final StringBuilder cmd = new StringBuilder("pm uninstall ");
+ if (user != null) {
+ cmd.append("--user ").append(user.id()).append(" ");
+ }
+ cmd.append(packageName);
+ runShellCommand(cmd.toString());
}
}
diff --git a/services/tests/PackageManagerServiceTests/appenumeration/test-apps/target/AndroidManifest-crossUserPackageVisibility.xml b/services/tests/PackageManagerServiceTests/appenumeration/test-apps/target/AndroidManifest-crossUserPackageVisibility.xml
index 874a1fc..9d38ddf 100644
--- a/services/tests/PackageManagerServiceTests/appenumeration/test-apps/target/AndroidManifest-crossUserPackageVisibility.xml
+++ b/services/tests/PackageManagerServiceTests/appenumeration/test-apps/target/AndroidManifest-crossUserPackageVisibility.xml
@@ -17,6 +17,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.appenumeration.crossuserpackagevisibility">
- <application>
+ <application android:testOnly="true">
</application>
</manifest>
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/Android.bp b/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/Android.bp
index b78a63b..462c580 100644
--- a/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/Android.bp
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/Android.bp
@@ -25,6 +25,7 @@
android_test_helper_app {
name: "PackageManagerServiceDeviceSideTests",
+ sdk_version: "test_current",
srcs: ["src/**/*.kt"],
libs: [
"android.test.base",
@@ -39,5 +40,4 @@
"androidx.test.rules",
"truth-prebuilt",
],
- platform_apis: true,
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
index 8461b39..17b4226 100644
--- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
@@ -3220,8 +3220,7 @@
when(mRoleManager.getRoleHolders(RoleManager.ROLE_SYSTEM_WELLBEING)).thenReturn(
Arrays.asList(package4));
- mockChangeEnabled(SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT, true);
- mService.mConstants.SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT = false;
+ mockChangeEnabled(SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT, false);
mService.mConstants.EXACT_ALARM_DENY_LIST = new ArraySet<>(new String[] {
package1,
package3,
@@ -3233,21 +3232,7 @@
assertFalse(mService.isScheduleExactAlarmAllowedByDefault(package3, uid3));
assertTrue(mService.isScheduleExactAlarmAllowedByDefault(package4, uid4));
- mockChangeEnabled(SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT, false);
- mService.mConstants.SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT = true;
- mService.mConstants.EXACT_ALARM_DENY_LIST = new ArraySet<>(new String[] {
- package1,
- package3,
- });
-
- // Same as above, deny listed packages will be false.
- assertFalse(mService.isScheduleExactAlarmAllowedByDefault(package1, uid1));
- assertTrue(mService.isScheduleExactAlarmAllowedByDefault(package2, uid2));
- assertFalse(mService.isScheduleExactAlarmAllowedByDefault(package3, uid3));
- assertTrue(mService.isScheduleExactAlarmAllowedByDefault(package4, uid4));
-
mockChangeEnabled(SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT, true);
- mService.mConstants.SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT = true;
mService.mConstants.EXACT_ALARM_DENY_LIST = new ArraySet<>(new String[] {
package1,
package3,
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java
index 009dae5..fa8d569 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java
@@ -585,6 +585,7 @@
DeviceConfigSession<Long> bgCurrentDrainInteractionGracePeriod = null;
DeviceConfigSession<Float> bgCurrentDrainRestrictedBucketThreshold = null;
DeviceConfigSession<Float> bgCurrentDrainBgRestrictedThreshold = null;
+ DeviceConfigSession<Boolean> bgCurrentDrainAutoRestrictAbusiveApps = null;
DeviceConfigSession<Boolean> bgPromptFgsWithNotiToBgRestricted = null;
DeviceConfigSession<Boolean> bgPromptAbusiveAppToBgRestricted = null;
DeviceConfigSession<Long> bgNotificationMinInterval = null;
@@ -644,6 +645,14 @@
isLowRamDeviceStatic() ? 1 : 0]);
bgCurrentDrainBgRestrictedThreshold.set(bgRestrictedThreshold);
+ bgCurrentDrainAutoRestrictAbusiveApps = new DeviceConfigSession<>(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ AppBatteryPolicy.KEY_BG_CURRENT_DRAIN_AUTO_RESTRICT_ABUSIVE_APPS_ENABLED,
+ DeviceConfig::getBoolean,
+ mContext.getResources().getBoolean(
+ R.bool.config_bg_current_drain_auto_restrict_abusive_apps));
+ bgCurrentDrainAutoRestrictAbusiveApps.set(true);
+
bgPromptFgsWithNotiToBgRestricted = new DeviceConfigSession<>(
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
ConstantsObserver.KEY_BG_PROMPT_FGS_WITH_NOTIFICATION_TO_BG_RESTRICTED,
@@ -1099,6 +1108,7 @@
closeIfNotNull(bgCurrentDrainInteractionGracePeriod);
closeIfNotNull(bgCurrentDrainRestrictedBucketThreshold);
closeIfNotNull(bgCurrentDrainBgRestrictedThreshold);
+ closeIfNotNull(bgCurrentDrainAutoRestrictAbusiveApps);
closeIfNotNull(bgPromptFgsWithNotiToBgRestricted);
closeIfNotNull(bgPromptAbusiveAppToBgRestricted);
closeIfNotNull(bgNotificationMinInterval);
@@ -1651,6 +1661,7 @@
DeviceConfigSession<Float> bgCurrentDrainBgRestrictedThreshold = null;
DeviceConfigSession<Float> bgCurrentDrainRestrictedBucketHighThreshold = null;
DeviceConfigSession<Float> bgCurrentDrainBgRestrictedHighThreshold = null;
+ DeviceConfigSession<Boolean> bgCurrentDrainAutoRestrictAbusiveApps = null;
DeviceConfigSession<Long> bgMediaPlaybackMinDurationThreshold = null;
DeviceConfigSession<Long> bgLocationMinDurationThreshold = null;
DeviceConfigSession<Boolean> bgCurrentDrainEventDurationBasedThresholdEnabled = null;
@@ -1736,6 +1747,14 @@
isLowRamDeviceStatic() ? 1 : 0]);
bgCurrentDrainBgRestrictedHighThreshold.set(bgRestrictedHighThreshold);
+ bgCurrentDrainAutoRestrictAbusiveApps = new DeviceConfigSession<>(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ AppBatteryPolicy.KEY_BG_CURRENT_DRAIN_AUTO_RESTRICT_ABUSIVE_APPS_ENABLED,
+ DeviceConfig::getBoolean,
+ mContext.getResources().getBoolean(
+ R.bool.config_bg_current_drain_auto_restrict_abusive_apps));
+ bgCurrentDrainAutoRestrictAbusiveApps.set(true);
+
bgMediaPlaybackMinDurationThreshold = new DeviceConfigSession<>(
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
AppBatteryPolicy.KEY_BG_CURRENT_DRAIN_MEDIA_PLAYBACK_MIN_DURATION,
@@ -2226,6 +2245,7 @@
closeIfNotNull(bgCurrentDrainBgRestrictedThreshold);
closeIfNotNull(bgCurrentDrainRestrictedBucketHighThreshold);
closeIfNotNull(bgCurrentDrainBgRestrictedHighThreshold);
+ closeIfNotNull(bgCurrentDrainAutoRestrictAbusiveApps);
closeIfNotNull(bgMediaPlaybackMinDurationThreshold);
closeIfNotNull(bgLocationMinDurationThreshold);
closeIfNotNull(bgCurrentDrainEventDurationBasedThresholdEnabled);
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/PrefetchControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/PrefetchControllerTest.java
index 8a954ca..5f9f1b2 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/PrefetchControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/PrefetchControllerTest.java
@@ -233,27 +233,34 @@
@Test
public void testConstantsUpdating_ValidValues() {
setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_THRESHOLD_MS, 5 * HOUR_IN_MILLIS);
+ setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_ALLOWANCE_MS, 5 * MINUTE_IN_MILLIS);
assertEquals(5 * HOUR_IN_MILLIS, mPrefetchController.getLaunchTimeThresholdMs());
+ assertEquals(5 * MINUTE_IN_MILLIS, mPrefetchController.getLaunchTimeAllowanceMs());
}
@Test
public void testConstantsUpdating_InvalidValues() {
// Test negatives/too low.
setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_THRESHOLD_MS, 4 * MINUTE_IN_MILLIS);
+ setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_ALLOWANCE_MS, -MINUTE_IN_MILLIS);
assertEquals(HOUR_IN_MILLIS, mPrefetchController.getLaunchTimeThresholdMs());
+ assertEquals(0, mPrefetchController.getLaunchTimeAllowanceMs());
// Test larger than a day. Controller should cap at one day.
setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_THRESHOLD_MS, 25 * HOUR_IN_MILLIS);
+ setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_ALLOWANCE_MS, 5 * HOUR_IN_MILLIS);
assertEquals(24 * HOUR_IN_MILLIS, mPrefetchController.getLaunchTimeThresholdMs());
+ assertEquals(2 * HOUR_IN_MILLIS, mPrefetchController.getLaunchTimeAllowanceMs());
}
@Test
public void testConstantsUpdating_ThresholdChangesAlarms() {
final long launchDelayMs = 11 * HOUR_IN_MILLIS;
setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_THRESHOLD_MS, 7 * HOUR_IN_MILLIS);
+ setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_ALLOWANCE_MS, 0);
when(mUsageStatsManagerInternal
.getEstimatedPackageLaunchTime(SOURCE_PACKAGE, SOURCE_USER_ID))
.thenReturn(sSystemClock.millis() + launchDelayMs);
@@ -276,6 +283,7 @@
@Test
public void testConstraintNotSatisfiedWhenLaunchLate() {
+ setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_ALLOWANCE_MS, 0);
setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_THRESHOLD_MS, 7 * HOUR_IN_MILLIS);
final JobStatus job = createJobStatus("testConstraintNotSatisfiedWhenLaunchLate", 1);
@@ -290,6 +298,8 @@
@Test
public void testConstraintSatisfiedWhenLaunchSoon() {
+ setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_ALLOWANCE_MS, 0);
+
final JobStatus job = createJobStatus("testConstraintSatisfiedWhenLaunchSoon", 2);
when(mUsageStatsManagerInternal
.getEstimatedPackageLaunchTime(SOURCE_PACKAGE, SOURCE_USER_ID))
@@ -338,6 +348,8 @@
@Test
public void testConstraintSatisfiedWhenWidget() {
+ setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_ALLOWANCE_MS, 0);
+
final JobStatus jobNonWidget = createJobStatus("testConstraintSatisfiedWhenWidget", 1);
final JobStatus jobWidget = createJobStatus("testConstraintSatisfiedWhenWidget", 2);
@@ -365,6 +377,7 @@
@Test
public void testEstimatedLaunchTimeChangedToLate() {
setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_THRESHOLD_MS, 7 * HOUR_IN_MILLIS);
+ setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_ALLOWANCE_MS, 0);
when(mUsageStatsManagerInternal
.getEstimatedPackageLaunchTime(SOURCE_PACKAGE, SOURCE_USER_ID))
.thenReturn(sSystemClock.millis() + HOUR_IN_MILLIS);
@@ -393,6 +406,7 @@
@Test
public void testEstimatedLaunchTimeChangedToSoon() {
setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_THRESHOLD_MS, 7 * HOUR_IN_MILLIS);
+ setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_ALLOWANCE_MS, 0);
when(mUsageStatsManagerInternal
.getEstimatedPackageLaunchTime(SOURCE_PACKAGE, SOURCE_USER_ID))
.thenReturn(sSystemClock.millis() + 10 * HOUR_IN_MILLIS);
@@ -413,4 +427,36 @@
verify(mJobSchedulerService, timeout(DEFAULT_WAIT_MS)).onControllerStateChanged(any());
assertTrue(jobStatus.isConstraintSatisfied(JobStatus.CONSTRAINT_PREFETCH));
}
+
+ @Test
+ public void testEstimatedLaunchTimeAllowance() {
+ setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_THRESHOLD_MS, 7 * HOUR_IN_MILLIS);
+ setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_ALLOWANCE_MS, 15 * MINUTE_IN_MILLIS);
+ when(mUsageStatsManagerInternal
+ .getEstimatedPackageLaunchTime(SOURCE_PACKAGE, SOURCE_USER_ID))
+ .thenReturn(sSystemClock.millis() + 10 * HOUR_IN_MILLIS);
+
+ InOrder inOrder = inOrder(mUsageStatsManagerInternal);
+
+ JobStatus jobStatus = createJobStatus("testEstimatedLaunchTimeAllowance", 1);
+ trackJobs(jobStatus);
+ inOrder.verify(mUsageStatsManagerInternal, timeout(DEFAULT_WAIT_MS))
+ .getEstimatedPackageLaunchTime(SOURCE_PACKAGE, SOURCE_USER_ID);
+ // The allowance shouldn't shift the alarm
+ verify(mAlarmManager, timeout(DEFAULT_WAIT_MS).times(1))
+ .setWindow(
+ anyInt(), eq(sElapsedRealtimeClock.millis() + 3 * HOUR_IN_MILLIS),
+ anyLong(), eq(TAG_PREFETCH), any(), any());
+ assertFalse(jobStatus.isConstraintSatisfied(JobStatus.CONSTRAINT_PREFETCH));
+
+ mEstimatedLaunchTimeChangedListener.onEstimatedLaunchTimeChanged(SOURCE_USER_ID,
+ SOURCE_PACKAGE, sSystemClock.millis() + HOUR_IN_MILLIS);
+
+ inOrder.verify(mUsageStatsManagerInternal, timeout(DEFAULT_WAIT_MS).times(0))
+ .getEstimatedPackageLaunchTime(SOURCE_PACKAGE, SOURCE_USER_ID);
+ verify(mJobSchedulerService, timeout(DEFAULT_WAIT_MS)).onControllerStateChanged(any());
+ assertTrue(jobStatus.isConstraintSatisfied(JobStatus.CONSTRAINT_PREFETCH));
+
+ sSystemClock = getShiftedClock(sSystemClock, HOUR_IN_MILLIS + MINUTE_IN_MILLIS);
+ }
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/BackgroundDexOptServiceUnitTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/BackgroundDexOptServiceUnitTest.java
index 444db91..da5c8f0 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/BackgroundDexOptServiceUnitTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/BackgroundDexOptServiceUnitTest.java
@@ -16,6 +16,9 @@
package com.android.server.pm;
+import static com.android.server.pm.BackgroundDexOptService.STATUS_DEX_OPT_FAILED;
+import static com.android.server.pm.BackgroundDexOptService.STATUS_OK;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
@@ -23,12 +26,14 @@
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.testng.Assert.assertThrows;
+import android.annotation.Nullable;
import android.app.job.JobInfo;
import android.app.job.JobParameters;
import android.app.job.JobScheduler;
@@ -38,10 +43,13 @@
import android.content.IntentFilter;
import android.os.HandlerThread;
import android.os.PowerManager;
+import android.util.Log;
+import com.android.internal.util.IndentingPrintWriter;
import com.android.server.LocalServices;
import com.android.server.PinnerService;
import com.android.server.pm.dex.DexManager;
+import com.android.server.pm.dex.DexoptOptions;
import org.junit.After;
import org.junit.Before;
@@ -52,7 +60,11 @@
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
+import java.io.ByteArrayOutputStream;
+import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.stream.Collectors;
@@ -66,8 +78,12 @@
private static final long TEST_WAIT_TIMEOUT_MS = 10_000;
- private static final List<String> DEFAULT_PACKAGE_LIST = List.of("aaa", "bbb");
- private static final List<String> EMPTY_PACKAGE_LIST = List.of();
+ private static final String PACKAGE_AAA = "aaa";
+ private static final List<String> DEFAULT_PACKAGE_LIST = List.of(PACKAGE_AAA, "bbb");
+ private int mDexOptResultForPackageAAA = PackageDexOptimizer.DEX_OPT_PERFORMED;
+
+ // Store expected dexopt sequence for verification.
+ private ArrayList<DexOptInfo> mDexInfoSequence = new ArrayList<>();
@Mock
private Context mContext;
@@ -116,14 +132,23 @@
when(mInjector.getDexOptThermalCutoff()).thenReturn(PowerManager.THERMAL_STATUS_CRITICAL);
when(mInjector.getCurrentThermalStatus()).thenReturn(PowerManager.THERMAL_STATUS_NONE);
when(mInjector.supportSecondaryDex()).thenReturn(true);
- when(mDexOptHelper.getOptimizablePackages(any())).thenReturn(DEFAULT_PACKAGE_LIST);
- when(mDexOptHelper.performDexOptWithStatus(any())).thenReturn(
- PackageDexOptimizer.DEX_OPT_PERFORMED);
- when(mDexOptHelper.performDexOpt(any())).thenReturn(true);
+ setupDexOptHelper();
mService = new BackgroundDexOptService(mInjector);
}
+ private void setupDexOptHelper() {
+ when(mDexOptHelper.getOptimizablePackages(any())).thenReturn(DEFAULT_PACKAGE_LIST);
+ when(mDexOptHelper.performDexOptWithStatus(any())).thenAnswer(inv -> {
+ DexoptOptions opt = inv.getArgument(0);
+ if (opt.getPackageName().equals(PACKAGE_AAA)) {
+ return mDexOptResultForPackageAAA;
+ }
+ return PackageDexOptimizer.DEX_OPT_PERFORMED;
+ });
+ when(mDexOptHelper.performDexOpt(any())).thenReturn(true);
+ }
+
@After
public void tearDown() throws Exception {
LocalServices.removeServiceForTest(BackgroundDexOptService.class);
@@ -159,7 +184,7 @@
@Test
public void testNoExecutionForNoOptimizablePackages() {
initUntilBootCompleted();
- when(mDexOptHelper.getOptimizablePackages(any())).thenReturn(EMPTY_PACKAGE_LIST);
+ when(mDexOptHelper.getOptimizablePackages(any())).thenReturn(Collections.emptyList());
assertThat(mService.onStartJob(mJobServiceForPostBoot,
mJobParametersForPostBoot)).isFalse();
@@ -170,15 +195,70 @@
public void testPostBootUpdateFullRun() {
initUntilBootCompleted();
- runFullJob(mJobServiceForPostBoot, mJobParametersForPostBoot, false, 1);
+ runFullJob(mJobServiceForPostBoot, mJobParametersForPostBoot,
+ /* expectedReschedule= */ false, /* expectedStatus= */ STATUS_OK,
+ /* totalJobFinishedWithParams= */ 1, /* expectedSkippedPackage= */ null);
+ }
+
+ @Test
+ public void testPostBootUpdateFullRunWithPackageFailure() {
+ mDexOptResultForPackageAAA = PackageDexOptimizer.DEX_OPT_FAILED;
+
+ initUntilBootCompleted();
+
+ runFullJob(mJobServiceForPostBoot, mJobParametersForPostBoot,
+ /* expectedReschedule= */ false, /* expectedStatus= */ STATUS_DEX_OPT_FAILED,
+ /* totalJobFinishedWithParams= */ 1, /* expectedSkippedPackage= */ PACKAGE_AAA);
+
+ assertThat(getFailedPackageNamesPrimary()).containsExactly(PACKAGE_AAA);
+ assertThat(getFailedPackageNamesSecondary()).isEmpty();
}
@Test
public void testIdleJobFullRun() {
initUntilBootCompleted();
+ runFullJob(mJobServiceForPostBoot, mJobParametersForPostBoot,
+ /* expectedReschedule= */ false, /* expectedStatus= */ STATUS_OK,
+ /* totalJobFinishedWithParams= */ 1, /* expectedSkippedPackage= */ null);
+ runFullJob(mJobServiceForIdle, mJobParametersForIdle,
+ /* expectedReschedule= */ true, /* expectedStatus= */ STATUS_OK,
+ /* totalJobFinishedWithParams= */ 1, /* expectedSkippedPackage= */ null);
+ }
- runFullJob(mJobServiceForPostBoot, mJobParametersForPostBoot, false, 1);
- runFullJob(mJobServiceForIdle, mJobParametersForIdle, true, 2);
+ @Test
+ public void testIdleJobFullRunWithFailureOnceAndSuccessAfterUpdate() {
+ mDexOptResultForPackageAAA = PackageDexOptimizer.DEX_OPT_FAILED;
+
+ initUntilBootCompleted();
+
+ runFullJob(mJobServiceForPostBoot, mJobParametersForPostBoot,
+ /* expectedReschedule= */ false, /* expectedStatus= */ STATUS_DEX_OPT_FAILED,
+ /* totalJobFinishedWithParams= */ 1, /* expectedSkippedPackage= */ PACKAGE_AAA);
+
+ assertThat(getFailedPackageNamesPrimary()).containsExactly(PACKAGE_AAA);
+ assertThat(getFailedPackageNamesSecondary()).isEmpty();
+
+ runFullJob(mJobServiceForIdle, mJobParametersForIdle,
+ /* expectedReschedule= */ true, /* expectedStatus= */ STATUS_OK,
+ /* totalJobFinishedWithParams= */ 1, /* expectedSkippedPackage= */ PACKAGE_AAA);
+
+ assertThat(getFailedPackageNamesPrimary()).containsExactly(PACKAGE_AAA);
+ assertThat(getFailedPackageNamesSecondary()).isEmpty();
+
+ mService.notifyPackageChanged(PACKAGE_AAA);
+
+ assertThat(getFailedPackageNamesPrimary()).isEmpty();
+ assertThat(getFailedPackageNamesSecondary()).isEmpty();
+
+ // Succeed this time.
+ mDexOptResultForPackageAAA = PackageDexOptimizer.DEX_OPT_PERFORMED;
+
+ runFullJob(mJobServiceForIdle, mJobParametersForIdle,
+ /* expectedReschedule= */ true, /* expectedStatus= */ STATUS_OK,
+ /* totalJobFinishedWithParams= */ 2, /* expectedSkippedPackage= */ null);
+
+ assertThat(getFailedPackageNamesPrimary()).isEmpty();
+ assertThat(getFailedPackageNamesSecondary()).isEmpty();
}
@Test
@@ -404,8 +484,10 @@
}
private void runFullJob(BackgroundDexOptJobService jobService, JobParameters params,
- boolean expectedReschedule, int totalJobRuns) {
+ boolean expectedReschedule, int expectedStatus, int totalJobFinishedWithParams,
+ @Nullable String expectedSkippedPackage) {
when(mInjector.createAndStartThread(any(), any())).thenReturn(Thread.currentThread());
+ addFullRunSequence(expectedSkippedPackage);
assertThat(mService.onStartJob(jobService, params)).isTrue();
ArgumentCaptor<Runnable> argThreadRunnable = ArgumentCaptor.forClass(Runnable.class);
@@ -413,20 +495,99 @@
argThreadRunnable.getValue().run();
- verify(jobService).jobFinished(params, expectedReschedule);
+ verify(jobService, times(totalJobFinishedWithParams)).jobFinished(params,
+ expectedReschedule);
// Never block
verify(mDexOptHelper, never()).controlDexOptBlocking(true);
- verifyPerformDexOpt(DEFAULT_PACKAGE_LIST, totalJobRuns);
+ verifyPerformDexOpt();
+ assertThat(getLastExecutionStatus()).isEqualTo(expectedStatus);
}
- private void verifyPerformDexOpt(List<String> pkgs, int expectedRuns) {
+ private void verifyPerformDexOpt() {
InOrder inOrder = inOrder(mDexOptHelper);
- for (int i = 0; i < expectedRuns; i++) {
- for (String pkg : pkgs) {
- inOrder.verify(mDexOptHelper, times(1)).performDexOptWithStatus(argThat((option) ->
- option.getPackageName().equals(pkg) && !option.isDexoptOnlySecondaryDex()));
- inOrder.verify(mDexOptHelper, times(1)).performDexOpt(argThat((option) ->
- option.getPackageName().equals(pkg) && option.isDexoptOnlySecondaryDex()));
+ inOrder.verify(mDexOptHelper).getOptimizablePackages(any());
+ for (DexOptInfo info : mDexInfoSequence) {
+ if (info.isPrimary) {
+ verify(mDexOptHelper).performDexOptWithStatus(
+ argThat((option) -> option.getPackageName().equals(info.packageName)
+ && !option.isDexoptOnlySecondaryDex()));
+ } else {
+ inOrder.verify(mDexOptHelper).performDexOpt(
+ argThat((option) -> option.getPackageName().equals(info.packageName)
+ && option.isDexoptOnlySecondaryDex()));
+ }
+ }
+
+ // Even InOrder cannot check the order if the same call is made multiple times.
+ // To check the order across multiple runs, we reset the mock so that order can be checked
+ // in each call.
+ mDexInfoSequence.clear();
+ reset(mDexOptHelper);
+ setupDexOptHelper();
+ }
+
+ private String findDumpValueForKey(String key) {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ PrintWriter pw = new PrintWriter(out, true);
+ IndentingPrintWriter writer = new IndentingPrintWriter(pw, "");
+ try {
+ mService.dump(writer);
+ writer.flush();
+ Log.i(TAG, "dump output:" + out.toString());
+ for (String line : out.toString().split(System.lineSeparator())) {
+ String[] vals = line.split(":");
+ if (vals[0].equals(key)) {
+ if (vals.length == 2) {
+ return vals[1].strip();
+ } else {
+ break;
+ }
+ }
+ }
+ return "";
+ } finally {
+ writer.close();
+ }
+ }
+
+ List<String> findStringListFromDump(String key) {
+ String values = findDumpValueForKey(key);
+ if (values.isEmpty()) {
+ return Collections.emptyList();
+ }
+ return Arrays.asList(values.split(","));
+ }
+
+ private List<String> getFailedPackageNamesPrimary() {
+ return findStringListFromDump("mFailedPackageNamesPrimary");
+ }
+
+ private List<String> getFailedPackageNamesSecondary() {
+ return findStringListFromDump("mFailedPackageNamesSecondary");
+ }
+
+ private int getLastExecutionStatus() {
+ return Integer.parseInt(findDumpValueForKey("mLastExecutionStatus"));
+ }
+
+ private static class DexOptInfo {
+ public final String packageName;
+ public final boolean isPrimary;
+
+ private DexOptInfo(String packageName, boolean isPrimary) {
+ this.packageName = packageName;
+ this.isPrimary = isPrimary;
+ }
+ }
+
+ private void addFullRunSequence(@Nullable String expectedSkippedPackage) {
+ for (String packageName : DEFAULT_PACKAGE_LIST) {
+ if (packageName.equals(expectedSkippedPackage)) {
+ // only fails primary dexopt in mocking but add secodary
+ mDexInfoSequence.add(new DexOptInfo(packageName, /* isPrimary= */ false));
+ } else {
+ mDexInfoSequence.add(new DexOptInfo(packageName, /* isPrimary= */ true));
+ mDexInfoSequence.add(new DexOptInfo(packageName, /* isPrimary= */ false));
}
}
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/BroadcastHelperTest.kt b/services/tests/mockingservicestests/src/com/android/server/pm/BroadcastHelperTest.kt
index e13da97..d25649e 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/BroadcastHelperTest.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/BroadcastHelperTest.kt
@@ -67,9 +67,9 @@
snapshot, packagesToChange, uidsToChange, TEST_USER_ID)
assertThat(broadcastParams).hasSize(1)
- assertThat(broadcastParams[0].packageNames).containsExactlyElementsIn(
+ assertThat(broadcastParams[0].packageNames).asList().containsExactlyElementsIn(
packagesToChange.toCollection(ArrayList()))
- assertThat(broadcastParams[0].uids.toArray()).asList().containsExactlyElementsIn(
+ assertThat(broadcastParams[0].uids).asList().containsExactlyElementsIn(
uidsToChange.toCollection(ArrayList()))
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/DeletePackageHelperTest.kt b/services/tests/mockingservicestests/src/com/android/server/pm/DeletePackageHelperTest.kt
index 9b4d967..69584e0 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/DeletePackageHelperTest.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/DeletePackageHelperTest.kt
@@ -68,13 +68,34 @@
}
@Test
- fun deleteSystemPackageFailsIfNotAdmin() {
+ fun deleteSystemPackageFailsIfNotAdminAndNotProfile() {
val ps = mPms.mSettings.getPackageLPr("a.data.package")
whenever(PackageManagerServiceUtils.isSystemApp(ps)).thenReturn(true)
whenever(mUserManagerInternal.getUserInfo(1)).thenReturn(UserInfo(1, "test", 0))
+ whenever(mUserManagerInternal.getProfileParentId(1)).thenReturn(1)
val dph = DeletePackageHelper(mPms)
- val result = dph.deletePackageX("a.data.package", 1L, 1, 0, false)
+ val result = dph.deletePackageX("a.data.package", 1L, 1,
+ PackageManager.DELETE_SYSTEM_APP, false)
+
+ assertThat(result).isEqualTo(PackageManager.DELETE_FAILED_USER_RESTRICTED)
+ }
+
+ @Test
+ fun deleteSystemPackageFailsIfProfileOfNonAdmin() {
+ val userId = 1
+ val parentId = 5
+ val ps = mPms.mSettings.getPackageLPr("a.data.package")
+ whenever(PackageManagerServiceUtils.isSystemApp(ps)).thenReturn(true)
+ whenever(mUserManagerInternal.getUserInfo(userId)).thenReturn(
+ UserInfo(userId, "test", UserInfo.FLAG_PROFILE))
+ whenever(mUserManagerInternal.getProfileParentId(userId)).thenReturn(parentId)
+ whenever(mUserManagerInternal.getUserInfo(parentId)).thenReturn(
+ UserInfo(userId, "testparent", 0))
+
+ val dph = DeletePackageHelper(mPms)
+ val result = dph.deletePackageX("a.data.package", 1L, userId,
+ PackageManager.DELETE_SYSTEM_APP, false)
assertThat(result).isEqualTo(PackageManager.DELETE_FAILED_USER_RESTRICTED)
}
@@ -92,4 +113,23 @@
assertThat(result).isEqualTo(PackageManager.DELETE_SUCCEEDED)
}
+
+ @Test
+ fun deleteSystemPackageSucceedsIfProfileOfAdmin() {
+ val userId = 1
+ val parentId = 5
+ val ps = mPms.mSettings.getPackageLPr("a.data.package")
+ whenever(PackageManagerServiceUtils.isSystemApp(ps)).thenReturn(true)
+ whenever(mUserManagerInternal.getUserInfo(userId)).thenReturn(
+ UserInfo(userId, "test", UserInfo.FLAG_PROFILE))
+ whenever(mUserManagerInternal.getProfileParentId(userId)).thenReturn(parentId)
+ whenever(mUserManagerInternal.getUserInfo(parentId)).thenReturn(
+ UserInfo(userId, "testparent", UserInfo.FLAG_ADMIN))
+
+ val dph = DeletePackageHelper(mPms)
+ val result = dph.deletePackageX("a.data.package", 1L, userId,
+ PackageManager.DELETE_SYSTEM_APP, false)
+
+ assertThat(result).isEqualTo(PackageManager.DELETE_SUCCEEDED)
+ }
}
\ No newline at end of file
diff --git a/services/tests/mockingservicestests/src/com/android/server/sensorprivacy/CameraPrivacyLightControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/sensorprivacy/CameraPrivacyLightControllerTest.java
index fa3e05a..20cfd59 100644
--- a/services/tests/mockingservicestests/src/com/android/server/sensorprivacy/CameraPrivacyLightControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/sensorprivacy/CameraPrivacyLightControllerTest.java
@@ -24,20 +24,33 @@
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import android.app.AppOpsManager;
import android.content.Context;
+import android.content.res.Resources;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
import android.hardware.lights.Light;
+import android.hardware.lights.LightState;
import android.hardware.lights.LightsManager;
import android.hardware.lights.LightsRequest;
+import android.os.Handler;
+import android.os.Looper;
import android.permission.PermissionManager;
import android.util.ArraySet;
import com.android.dx.mockito.inline.extended.ExtendedMockito;
+import com.android.internal.R;
import org.junit.After;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
@@ -53,26 +66,43 @@
public class CameraPrivacyLightControllerTest {
+ private int mDayColor = 1;
+ private int mNightColor = 0;
+ private int mCameraPrivacyLightAlsAveragingIntervalMillis = 5000;
+ private int mCameraPrivacyLightAlsNightThreshold = (int) getLightSensorValue(15);
+
private MockitoSession mMockitoSession;
@Mock
private Context mContext;
@Mock
+ private Resources mResources;
+
+ @Mock
private LightsManager mLightsManager;
@Mock
private AppOpsManager mAppOpsManager;
@Mock
+ private SensorManager mSensorManager;
+
+ @Mock
private LightsManager.LightsSession mLightsSession;
+ @Mock
+ private Sensor mLightSensor;
+
private ArgumentCaptor<AppOpsManager.OnOpActiveChangedListener> mAppOpsListenerCaptor =
ArgumentCaptor.forClass(AppOpsManager.OnOpActiveChangedListener.class);
private ArgumentCaptor<LightsRequest> mLightsRequestCaptor =
ArgumentCaptor.forClass(LightsRequest.class);
+ private ArgumentCaptor<SensorEventListener> mLightSensorListenerCaptor =
+ ArgumentCaptor.forClass(SensorEventListener.class);
+
private Set<String> mExemptedPackages = new ArraySet<>();
private List<Light> mLights = new ArrayList<>();
@@ -86,11 +116,22 @@
.spyStatic(PermissionManager.class)
.startMocking();
+ doReturn(mDayColor).when(mContext).getColor(R.color.camera_privacy_light_day);
+ doReturn(mNightColor).when(mContext).getColor(R.color.camera_privacy_light_night);
+
+ doReturn(mResources).when(mContext).getResources();
+ doReturn(mCameraPrivacyLightAlsAveragingIntervalMillis).when(mResources)
+ .getInteger(R.integer.config_cameraPrivacyLightAlsAveragingIntervalMillis);
+ doReturn(mCameraPrivacyLightAlsNightThreshold).when(mResources)
+ .getInteger(R.integer.config_cameraPrivacyLightAlsNightThreshold);
+
doReturn(mLightsManager).when(mContext).getSystemService(LightsManager.class);
doReturn(mAppOpsManager).when(mContext).getSystemService(AppOpsManager.class);
+ doReturn(mSensorManager).when(mContext).getSystemService(SensorManager.class);
doReturn(mLights).when(mLightsManager).getLights();
doReturn(mLightsSession).when(mLightsManager).openSession(anyInt());
+ doReturn(mLightSensor).when(mSensorManager).getDefaultSensor(Sensor.TYPE_LIGHT);
doReturn(mExemptedPackages)
.when(() -> PermissionManager.getIndicatorExemptedPackages(any()));
@@ -107,7 +148,7 @@
@Test
public void testAppsOpsListenerNotRegisteredWithoutCameraLights() {
mLights.add(getNextLight(false));
- new CameraPrivacyLightController(mContext);
+ createCameraPrivacyLightController();
verify(mAppOpsManager, times(0)).startWatchingActive(any(), any(), any());
}
@@ -116,7 +157,7 @@
public void testAppsOpsListenerRegisteredWithCameraLight() {
mLights.add(getNextLight(true));
- new CameraPrivacyLightController(mContext);
+ createCameraPrivacyLightController();
verify(mAppOpsManager, times(1)).startWatchingActive(any(), any(), any());
}
@@ -128,14 +169,13 @@
mLights.add(getNextLight(r.nextBoolean()));
}
- new CameraPrivacyLightController(mContext);
+ createCameraPrivacyLightController();
// Verify no session has been opened at this point.
verify(mLightsManager, times(0)).openSession(anyInt());
// Set camera op as active.
- verify(mAppOpsManager).startWatchingActive(any(), any(), mAppOpsListenerCaptor.capture());
- mAppOpsListenerCaptor.getValue().onOpActiveChanged(OPSTR_CAMERA, 10101, "pkg1", true);
+ openCamera();
// Verify session has been opened exactly once
verify(mLightsManager, times(1)).openSession(anyInt());
@@ -161,7 +201,7 @@
public void testWillOnlyOpenOnceWhenTwoPackagesStartOp() {
mLights.add(getNextLight(true));
- new CameraPrivacyLightController(mContext);
+ createCameraPrivacyLightController();
verify(mAppOpsManager).startWatchingActive(any(), any(), mAppOpsListenerCaptor.capture());
@@ -176,7 +216,7 @@
public void testWillCloseOnFinishOp() {
mLights.add(getNextLight(true));
- new CameraPrivacyLightController(mContext);
+ createCameraPrivacyLightController();
verify(mAppOpsManager).startWatchingActive(any(), any(), mAppOpsListenerCaptor.capture());
@@ -192,7 +232,7 @@
public void testWillCloseOnFinishOpForAllPackages() {
mLights.add(getNextLight(true));
- new CameraPrivacyLightController(mContext);
+ createCameraPrivacyLightController();
int numUids = 100;
List<Integer> uids = new ArrayList<>(numUids);
@@ -226,7 +266,7 @@
mLights.add(getNextLight(true));
mExemptedPackages.add("pkg1");
- new CameraPrivacyLightController(mContext);
+ createCameraPrivacyLightController();
verify(mAppOpsManager).startWatchingActive(any(), any(), mAppOpsListenerCaptor.capture());
@@ -235,6 +275,147 @@
verify(mLightsManager, times(0)).openSession(anyInt());
}
+ @Test
+ public void testNoLightSensor() {
+ mLights.add(getNextLight(true));
+ doReturn(null).when(mSensorManager).getDefaultSensor(Sensor.TYPE_LIGHT);
+
+ createCameraPrivacyLightController();
+
+ openCamera();
+
+ verify(mLightsSession).requestLights(mLightsRequestCaptor.capture());
+ LightsRequest lightsRequest = mLightsRequestCaptor.getValue();
+ for (LightState lightState : lightsRequest.getLightStates()) {
+ assertEquals(mDayColor, lightState.getColor());
+ }
+ }
+
+ @Test
+ public void testALSListenerNotRegisteredUntilCameraIsOpened() {
+ mLights.add(getNextLight(true));
+ Sensor sensor = mock(Sensor.class);
+ doReturn(sensor).when(mSensorManager).getDefaultSensor(Sensor.TYPE_LIGHT);
+
+ CameraPrivacyLightController cplc = createCameraPrivacyLightController();
+
+ verify(mSensorManager, never()).registerListener(any(SensorEventListener.class),
+ any(Sensor.class), anyInt(), any(Handler.class));
+
+ openCamera();
+
+ verify(mSensorManager, times(1)).registerListener(mLightSensorListenerCaptor.capture(),
+ any(Sensor.class), anyInt(), any(Handler.class));
+
+ mAppOpsListenerCaptor.getValue().onOpActiveChanged(OPSTR_CAMERA, 10001, "pkg", false);
+ verify(mSensorManager, times(1)).unregisterListener(mLightSensorListenerCaptor.getValue());
+ }
+
+ @Ignore
+ @Test
+ public void testDayColor() {
+ testBrightnessToColor(20, mDayColor);
+ }
+
+ @Ignore
+ @Test
+ public void testNightColor() {
+ testBrightnessToColor(10, mNightColor);
+ }
+
+ private void testBrightnessToColor(int brightnessValue, int color) {
+ mLights.add(getNextLight(true));
+ Sensor sensor = mock(Sensor.class);
+ doReturn(sensor).when(mSensorManager).getDefaultSensor(Sensor.TYPE_LIGHT);
+
+ CameraPrivacyLightController cplc = createCameraPrivacyLightController();
+ cplc.setElapsedRealTime(0);
+
+ openCamera();
+
+ verify(mSensorManager).registerListener(mLightSensorListenerCaptor.capture(),
+ any(Sensor.class), anyInt(), any(Handler.class));
+ SensorEventListener sensorListener = mLightSensorListenerCaptor.getValue();
+ float[] sensorEventValues = new float[1];
+ SensorEvent sensorEvent = new SensorEvent(sensor, 0, 0, sensorEventValues);
+
+ sensorEventValues[0] = getLightSensorValue(brightnessValue);
+ sensorListener.onSensorChanged(sensorEvent);
+
+ verify(mLightsSession, atLeastOnce()).requestLights(mLightsRequestCaptor.capture());
+ for (LightState lightState : mLightsRequestCaptor.getValue().getLightStates()) {
+ assertEquals(color, lightState.getColor());
+ }
+ }
+
+ @Ignore
+ @Test
+ public void testDayToNightTransistion() {
+ mLights.add(getNextLight(true));
+ Sensor sensor = mock(Sensor.class);
+ doReturn(sensor).when(mSensorManager).getDefaultSensor(Sensor.TYPE_LIGHT);
+
+ CameraPrivacyLightController cplc = createCameraPrivacyLightController();
+ cplc.setElapsedRealTime(0);
+
+ openCamera();
+ // There will be an initial call at brightness 0
+ verify(mLightsSession, times(1)).requestLights(any(LightsRequest.class));
+
+ verify(mSensorManager).registerListener(mLightSensorListenerCaptor.capture(),
+ any(Sensor.class), anyInt(), any(Handler.class));
+ SensorEventListener sensorListener = mLightSensorListenerCaptor.getValue();
+
+ onSensorEvent(cplc, sensorListener, sensor, 0, 20);
+
+ // 5 sec avg = 20
+ onSensorEvent(cplc, sensorListener, sensor, 5000, 30);
+
+ verify(mLightsSession, times(2)).requestLights(mLightsRequestCaptor.capture());
+ for (LightState lightState : mLightsRequestCaptor.getValue().getLightStates()) {
+ assertEquals(mDayColor, lightState.getColor());
+ }
+
+ // 5 sec avg = 22
+
+ onSensorEvent(cplc, sensorListener, sensor, 6000, 10);
+
+ // 5 sec avg = 18
+
+ onSensorEvent(cplc, sensorListener, sensor, 8000, 5);
+
+ // Should have always been day
+ verify(mLightsSession, times(2)).requestLights(mLightsRequestCaptor.capture());
+ for (LightState lightState : mLightsRequestCaptor.getValue().getLightStates()) {
+ assertEquals(mDayColor, lightState.getColor());
+ }
+
+ // 5 sec avg = 12
+
+ onSensorEvent(cplc, sensorListener, sensor, 10000, 5);
+
+ // Should now be night
+ verify(mLightsSession, times(3)).requestLights(mLightsRequestCaptor.capture());
+ for (LightState lightState : mLightsRequestCaptor.getValue().getLightStates()) {
+ assertEquals(mNightColor, lightState.getColor());
+ }
+ }
+
+ private void onSensorEvent(CameraPrivacyLightController cplc,
+ SensorEventListener sensorListener, Sensor sensor, long timestamp, int value) {
+ cplc.setElapsedRealTime(timestamp);
+ sensorListener.onSensorChanged(new SensorEvent(sensor, 0, timestamp,
+ new float[] {getLightSensorValue(value)}));
+ }
+
+ // Use the test thread so that the test is deterministic
+ private CameraPrivacyLightController createCameraPrivacyLightController() {
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
+ return new CameraPrivacyLightController(mContext, Looper.myLooper());
+ }
+
private Light getNextLight(boolean cameraType) {
Light light = ExtendedMockito.mock(Light.class);
if (cameraType) {
@@ -245,4 +426,13 @@
doReturn(mNextLightId++).when(light).getId();
return light;
}
+
+ private float getLightSensorValue(int i) {
+ return (float) Math.exp(i / CameraPrivacyLightController.LIGHT_VALUE_MULTIPLIER);
+ }
+
+ private void openCamera() {
+ verify(mAppOpsManager).startWatchingActive(any(), any(), mAppOpsListenerCaptor.capture());
+ mAppOpsListenerCaptor.getValue().onOpActiveChanged(OPSTR_CAMERA, 10001, "pkg", true);
+ }
}
diff --git a/services/tests/servicestests/assets/PolicyVersionUpgraderTest/protected_packages_device_owner_2.xml b/services/tests/servicestests/assets/PolicyVersionUpgraderTest/protected_packages_device_owner_2.xml
new file mode 100644
index 0000000..0725d25
--- /dev/null
+++ b/services/tests/servicestests/assets/PolicyVersionUpgraderTest/protected_packages_device_owner_2.xml
@@ -0,0 +1,6 @@
+<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
+<root>
+ <device-owner package="com.android.frameworks.servicestests" name="" component="com.android.frameworks.servicestests/com.android.server.devicepolicy.DummyDeviceAdmins$Admin1" userRestrictionsMigrated="true" isPoOrganizationOwnedDevice="true" />
+ <device-owner-context userId="0" />
+ <device-owner-protected-packages package="com.android.frameworks.servicestests" size="2" name0="com.some.app" name1="foo.bar.baz" />
+</root>
diff --git a/services/tests/servicestests/assets/PolicyVersionUpgraderTest/protected_packages_device_policies.xml b/services/tests/servicestests/assets/PolicyVersionUpgraderTest/protected_packages_device_policies.xml
new file mode 100644
index 0000000..2d06ee6
--- /dev/null
+++ b/services/tests/servicestests/assets/PolicyVersionUpgraderTest/protected_packages_device_policies.xml
@@ -0,0 +1,13 @@
+<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
+<policies setup-complete="true" provisioning-state="3">
+ <admin name="com.android.frameworks.servicestests/com.android.server.devicepolicy.DummyDeviceAdmins$Admin1">
+ <policies flags="991" />
+ <strong-auth-unlock-timeout value="0" />
+ <test-only-admin value="true" />
+ <cross-profile-calendar-packages />
+ <cross-profile-packages />
+ </admin>
+ <lock-task-features value="16" />
+ <protected-packages name="com.some.app" />
+ <protected-packages name="foo.bar.baz" />
+</policies>
diff --git a/services/tests/servicestests/src/com/android/server/am/BroadcastRecordTest.java b/services/tests/servicestests/src/com/android/server/am/BroadcastRecordTest.java
index 18e0f29..bce99a0 100644
--- a/services/tests/servicestests/src/com/android/server/am/BroadcastRecordTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/BroadcastRecordTest.java
@@ -416,6 +416,7 @@
null /* resolvedType */,
null /* requiredPermissions */,
null /* excludedPermissions */,
+ null /* excludedPackages */,
0 /* appOp */,
null /* options */,
new ArrayList<>(receivers), // Make a copy to not affect the original list.
diff --git a/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java b/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java
index 5b3a128..98f0603 100644
--- a/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java
@@ -339,7 +339,7 @@
ArgumentCaptor<Intent> intentArgumentCaptor = ArgumentCaptor.forClass(Intent.class);
verify(mIActivityManager, times(2)).broadcastIntentWithFeature(any(), any(),
intentArgumentCaptor.capture(), any(), any(), anyInt(), any(), any(), any(), any(),
- anyInt(), any(), anyBoolean(), anyBoolean(), eq(USER_ID_1));
+ any(), anyInt(), any(), anyBoolean(), anyBoolean(), eq(USER_ID_1));
List<Intent> capturedIntents = intentArgumentCaptor.getAllValues();
assertEquals(capturedIntents.get(0).getAction(), Intent.ACTION_LOCKED_BOOT_COMPLETED);
assertEquals(capturedIntents.get(1).getAction(), Intent.ACTION_BOOT_COMPLETED);
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/InputControllerTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/InputControllerTest.java
index 77cbb3a..5d9d765 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/InputControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/InputControllerTest.java
@@ -34,6 +34,9 @@
import android.testing.TestableLooper;
import android.view.Display;
import android.view.DisplayInfo;
+import android.view.WindowManager;
+
+import androidx.test.InstrumentationRegistry;
import com.android.server.LocalServices;
@@ -79,7 +82,9 @@
// Allow virtual devices to be created on the looper thread for testing.
final InputController.DeviceCreationThreadVerifier threadVerifier = () -> true;
mInputController = new InputController(new Object(), mNativeWrapperMock,
- new Handler(TestableLooper.get(this).getLooper()), threadVerifier);
+ new Handler(TestableLooper.get(this).getLooper()),
+ InstrumentationRegistry.getTargetContext().getSystemService(WindowManager.class),
+ threadVerifier);
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
index cbb9fd7..f9671e5 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
@@ -77,6 +77,7 @@
import android.util.ArraySet;
import android.view.DisplayInfo;
import android.view.KeyEvent;
+import android.view.WindowManager;
import androidx.test.InstrumentationRegistry;
@@ -208,7 +209,8 @@
// Allow virtual devices to be created on the looper thread for testing.
final InputController.DeviceCreationThreadVerifier threadVerifier = () -> true;
mInputController = new InputController(new Object(), mNativeWrapperMock,
- new Handler(TestableLooper.get(this).getLooper()), threadVerifier);
+ new Handler(TestableLooper.get(this).getLooper()),
+ mContext.getSystemService(WindowManager.class), threadVerifier);
mAssociationInfo = new AssociationInfo(1, 0, null,
MacAddress.BROADCAST_ADDRESS, "", null, true, false, 0, 0);
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 0fc201e..ec6b674 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -6996,22 +6996,23 @@
dpm.setUserControlDisabledPackages(admin1, testPackages);
verify(getServices().packageManagerInternal)
- .setDeviceOwnerProtectedPackages(admin1.getPackageName(), testPackages);
+ .setOwnerProtectedPackages(UserHandle.USER_ALL, testPackages);
assertThat(dpm.getUserControlDisabledPackages(admin1)).isEqualTo(testPackages);
}
@Test
- public void testSetUserControlDisabledPackages_failingAsPO() {
+ public void testSetUserControlDisabledPackages_asPO() {
final List<String> testPackages = new ArrayList<>();
testPackages.add("package_1");
testPackages.add("package_2");
mServiceContext.permissions.add(permission.MANAGE_DEVICE_ADMINS);
setAsProfileOwner(admin1);
- assertExpectException(SecurityException.class, /* messageRegex= */ null,
- () -> dpm.setUserControlDisabledPackages(admin1, testPackages));
- assertExpectException(SecurityException.class, /* messageRegex= */ null,
- () -> dpm.getUserControlDisabledPackages(admin1));
+ dpm.setUserControlDisabledPackages(admin1, testPackages);
+
+ verify(getServices().packageManagerInternal)
+ .setOwnerProtectedPackages(CALLER_USER_HANDLE, testPackages);
+ assertThat(dpm.getUserControlDisabledPackages(admin1)).isEqualTo(testPackages);
}
private void configureProfileOwnerOfOrgOwnedDevice(ComponentName who, int userId) {
@@ -7845,7 +7846,7 @@
dpm.setUserControlDisabledPackages(admin1, packages);
verify(getServices().packageManagerInternal)
- .setDeviceOwnerProtectedPackages(eq(admin1.getPackageName()), eq(packages));
+ .setOwnerProtectedPackages(eq(UserHandle.USER_ALL), eq(packages));
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/PolicyVersionUpgraderTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/PolicyVersionUpgraderTest.java
index 9efc10c..72fac55 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/PolicyVersionUpgraderTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/PolicyVersionUpgraderTest.java
@@ -63,20 +63,15 @@
public class PolicyVersionUpgraderTest extends DpmTestBase {
// NOTE: Only change this value if the corresponding CL also adds a test to test the upgrade
// to the new version.
- private static final int LATEST_TESTED_VERSION = 2;
+ private static final int LATEST_TESTED_VERSION = 3;
public static final String PERMISSIONS_TAG = "admin-can-grant-sensors-permissions";
+ public static final String DEVICE_OWNER_XML = "device_owner_2.xml";
private ComponentName mFakeAdmin;
private class FakePolicyUpgraderDataProvider implements PolicyUpgraderDataProvider {
- boolean mIsFileBasedEncryptionEnabled;
Map<ComponentName, DeviceAdminInfo> mComponentToDeviceAdminInfo = new HashMap<>();
int[] mUsers;
- @Override
- public boolean storageManagerIsFileBasedEncryptionEnabled() {
- return mIsFileBasedEncryptionEnabled;
- }
-
private JournaledFile makeJournaledFile(int userId, String fileName) {
File parentDir = getServices().environment.getUserSystemDirectory(userId);
@@ -119,18 +114,18 @@
mUpgrader = new PolicyVersionUpgrader(mProvider, getServices().pathProvider);
mFakeAdmin = new ComponentName(
"com.android.frameworks.servicestests",
- "com.android.server.devicepolicy.DummyDeviceAdmins$Admin1");
+ "com.android.server.devicepolicy.DummyDeviceAdmins$Admin1");
ActivityInfo activityInfo = createActivityInfo(mFakeAdmin);
DeviceAdminInfo dai = createDeviceAdminInfo(activityInfo);
mProvider.mComponentToDeviceAdminInfo.put(mFakeAdmin, dai);
- mProvider.mUsers = new int[] {0};
+ mProvider.mUsers = new int[]{0};
}
@Test
public void testSameVersionDoesNothing() throws IOException {
writeVersionToXml(DevicePolicyManagerService.DPMS_VERSION);
final int userId = mProvider.mUsers[0];
- preparePoliciesFile(userId);
+ preparePoliciesFile(userId, "device_policies.xml");
String oldContents = readPoliciesFile(userId);
mUpgrader.upgradePolicy(DevicePolicyManagerService.DPMS_VERSION);
@@ -142,19 +137,19 @@
@Test
public void testUpgrade0To1RemovesPasswordMetrics() throws IOException, XmlPullParserException {
final String activePasswordTag = "active-password";
- mProvider.mUsers = new int[] {0, 10};
+ mProvider.mUsers = new int[]{0, 10};
getServices().addUser(10, /* flags= */ 0, USER_TYPE_PROFILE_MANAGED);
writeVersionToXml(0);
for (int userId : mProvider.mUsers) {
- preparePoliciesFile(userId);
+ preparePoliciesFile(userId, "device_policies.xml");
}
// Validate test set-up.
assertThat(isTagPresent(readPoliciesFileToStream(0), activePasswordTag)).isTrue();
mUpgrader.upgradePolicy(1);
- assertThat(readVersionFromXml()).isGreaterThan(1);
- for (int user: mProvider.mUsers) {
+ assertThat(readVersionFromXml()).isAtLeast(1);
+ for (int user : mProvider.mUsers) {
assertThat(isTagPresent(readPoliciesFileToStream(user), activePasswordTag)).isFalse();
}
}
@@ -163,17 +158,17 @@
public void testUpgrade1To2MarksDoForPermissionControl()
throws IOException, XmlPullParserException {
final int ownerUser = 10;
- mProvider.mUsers = new int[] {0, ownerUser};
+ mProvider.mUsers = new int[]{0, ownerUser};
getServices().addUser(ownerUser, FLAG_PRIMARY, USER_TYPE_FULL_SYSTEM);
writeVersionToXml(1);
for (int userId : mProvider.mUsers) {
- preparePoliciesFile(userId);
+ preparePoliciesFile(userId, "device_policies.xml");
}
- prepareDeviceOwnerFile(ownerUser);
+ prepareDeviceOwnerFile(ownerUser, "device_owner_2.xml");
mUpgrader.upgradePolicy(2);
- assertThat(readVersionFromXml()).isEqualTo(2);
+ assertThat(readVersionFromXml()).isAtLeast(2);
assertThat(getBooleanValueTag(readPoliciesFileToStream(mProvider.mUsers[0]),
PERMISSIONS_TAG)).isFalse();
assertThat(getBooleanValueTag(readPoliciesFileToStream(ownerUser),
@@ -186,8 +181,8 @@
getServices().addUser(ownerUser, FLAG_PRIMARY, USER_TYPE_FULL_SYSTEM);
setUpPackageManagerForAdmin(admin1, UserHandle.getUid(ownerUser, 123 /* admin app ID */));
writeVersionToXml(0);
- preparePoliciesFile(ownerUser);
- prepareDeviceOwnerFile(ownerUser);
+ preparePoliciesFile(ownerUser, "device_policies.xml");
+ prepareDeviceOwnerFile(ownerUser, "device_owner_2.xml");
DevicePolicyManagerServiceTestable dpms;
final long ident = getContext().binder.clearCallingIdentity();
@@ -202,11 +197,65 @@
getContext().binder.restoreCallingIdentity(ident);
}
+ assertThat(readVersionFromXml()).isEqualTo(DevicePolicyManagerService.DPMS_VERSION);
+
// DO should be marked as able to grant sensors permission during upgrade and should be
// reported as such via the API.
assertThat(dpms.canAdminGrantSensorsPermissionsForUser(ownerUser)).isTrue();
}
+ /**
+ * Up to Android R DO protected packages were stored in DevicePolicyData, verify that they are
+ * moved to ActiveAdmin.
+ */
+ @Test
+ public void testUserControlDisabledPackagesFromR() throws Exception {
+ final String oldTag = "protected-packages";
+ final String newTag = "protected_packages";
+ final int ownerUser = 0;
+ mProvider.mUsers = new int[]{0};
+ getServices().addUser(ownerUser, FLAG_PRIMARY, USER_TYPE_FULL_SYSTEM);
+ writeVersionToXml(2);
+ preparePoliciesFile(ownerUser, "protected_packages_device_policies.xml");
+ prepareDeviceOwnerFile(ownerUser, "device_owner_2.xml");
+
+ // Validate the setup.
+ assertThat(isTagPresent(readPoliciesFileToStream(ownerUser), oldTag)).isTrue();
+ assertThat(isTagPresent(readPoliciesFileToStream(ownerUser), newTag)).isFalse();
+
+ mUpgrader.upgradePolicy(3);
+
+ assertThat(readVersionFromXml()).isAtLeast(3);
+ assertThat(isTagPresent(readPoliciesFileToStream(ownerUser), oldTag)).isFalse();
+ assertThat(isTagPresent(readPoliciesFileToStream(ownerUser), newTag)).isTrue();
+ }
+
+ /**
+ * In Android S DO protected packages were stored in Owners, verify that they are moved to
+ * ActiveAdmin.
+ */
+ @Test
+ public void testUserControlDisabledPackagesFromS() throws Exception {
+ final String oldTag = "device-owner-protected-packages";
+ final String newTag = "protected_packages";
+ final int ownerUser = 0;
+ mProvider.mUsers = new int[]{0};
+ getServices().addUser(ownerUser, FLAG_PRIMARY, USER_TYPE_FULL_SYSTEM);
+ writeVersionToXml(2);
+ preparePoliciesFile(ownerUser, "device_policies.xml");
+ prepareDeviceOwnerFile(ownerUser, "protected_packages_device_owner_2.xml");
+
+ // Validate the setup.
+ assertThat(isTagPresent(readDoToStream(), oldTag)).isTrue();
+ assertThat(isTagPresent(readPoliciesFileToStream(ownerUser), newTag)).isFalse();
+
+ mUpgrader.upgradePolicy(3);
+
+ assertThat(readVersionFromXml()).isAtLeast(3);
+ assertThat(isTagPresent(readDoToStream(), oldTag)).isFalse();
+ assertThat(isTagPresent(readPoliciesFileToStream(ownerUser), newTag)).isTrue();
+ }
+
@Test
public void isLatestVersionTested() {
assertThat(DevicePolicyManagerService.DPMS_VERSION).isEqualTo(LATEST_TESTED_VERSION);
@@ -226,32 +275,27 @@
return Integer.parseInt(versionString);
}
- private void preparePoliciesFile(int userId) throws IOException {
+ private void preparePoliciesFile(int userId, String assetFile) throws IOException {
JournaledFile policiesFile = mProvider.makeDevicePoliciesJournaledFile(userId);
DpmTestUtils.writeToFile(
policiesFile.chooseForWrite(),
- DpmTestUtils.readAsset(mRealTestContext,
- "PolicyVersionUpgraderTest/device_policies.xml"));
+ DpmTestUtils.readAsset(mRealTestContext, "PolicyVersionUpgraderTest/" + assetFile));
policiesFile.commit();
}
- private void prepareDeviceOwnerFile(int userId) throws IOException {
- File parentDir = getServices().pathProvider.getDataSystemDirectory();
- File doFilePath = (new File(parentDir, "device_owner_2.xml")).getAbsoluteFile();
- android.util.Log.i("YYYYYY", "DO paath: " + doFilePath);
+ private void prepareDeviceOwnerFile(int userId, String assetFile) throws IOException {
+ File doFilePath = getDoFilePath();
String doFileContent = DpmTestUtils.readAsset(mRealTestContext,
- "PolicyVersionUpgraderTest/device_owner_2.xml")
+ "PolicyVersionUpgraderTest/" + assetFile)
// Substitute the right DO userId, XML in resources has 0
.replace("userId=\"0\"", "userId=\"" + userId + "\"");
DpmTestUtils.writeToFile(doFilePath, doFileContent);
}
- private void prepareProfileOwnerFile(int userId) throws IOException {
- File parentDir = getServices().pathProvider.getUserSystemDirectory(userId);
- DpmTestUtils.writeToFile(
- (new File(parentDir, "profile_owner.xml")).getAbsoluteFile(),
- DpmTestUtils.readAsset(mRealTestContext,
- "PolicyVersionUpgraderTest/profile_owner.xml"));
+ private File getDoFilePath() {
+ File parentDir = getServices().pathProvider.getDataSystemDirectory();
+ File doFilePath = (new File(parentDir, DEVICE_OWNER_XML)).getAbsoluteFile();
+ return doFilePath;
}
private String readPoliciesFile(int userId) throws IOException {
@@ -259,6 +303,10 @@
return new String(Files.asByteSource(policiesFile).read(), Charset.defaultCharset());
}
+ private InputStream readDoToStream() throws IOException {
+ return new FileInputStream(getDoFilePath());
+ }
+
private InputStream readPoliciesFileToStream(int userId) throws IOException {
File policiesFile = mProvider.makeDevicePoliciesJournaledFile(userId).chooseForRead();
return new FileInputStream(policiesFile);
diff --git a/services/tests/servicestests/src/com/android/server/display/PersistentDataStoreTest.java b/services/tests/servicestests/src/com/android/server/display/PersistentDataStoreTest.java
index 57a9cb2..9fe8609c 100644
--- a/services/tests/servicestests/src/com/android/server/display/PersistentDataStoreTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/PersistentDataStoreTest.java
@@ -24,6 +24,8 @@
import android.content.Context;
import android.hardware.display.BrightnessConfiguration;
+import android.os.Handler;
+import android.os.test.TestLooper;
import android.util.Pair;
import androidx.test.InstrumentationRegistry;
@@ -47,11 +49,14 @@
public class PersistentDataStoreTest {
private PersistentDataStore mDataStore;
private TestInjector mInjector;
+ private TestLooper mTestLooper;
@Before
public void setUp() {
mInjector = new TestInjector();
- mDataStore = new PersistentDataStore(mInjector);
+ mTestLooper = new TestLooper();
+ Handler handler = new Handler(mTestLooper.getLooper());
+ mDataStore = new PersistentDataStore(mInjector, handler);
}
@Test
@@ -147,7 +152,7 @@
}
@Test
- public void testStoreAndReloadOfDisplayBrightnessConfigurations() {
+ public void testStoreAndReloadOfDisplayBrightnessConfigurations() throws InterruptedException {
final String uniqueDisplayId = "test:123";
int userSerial = 0;
String packageName = "pdsTestPackage";
@@ -178,6 +183,7 @@
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
mInjector.setWriteStream(baos);
mDataStore.saveIfNeeded();
+ mTestLooper.dispatchAll();
assertTrue(mInjector.wasWriteSuccessful());
TestInjector newInjector = new TestInjector();
PersistentDataStore newDataStore = new PersistentDataStore(newInjector);
@@ -222,7 +228,7 @@
}
@Test
- public void testStoreAndReloadOfBrightnessConfigurations() {
+ public void testStoreAndReloadOfBrightnessConfigurations() throws InterruptedException {
final float[] lux = { 0f, 10f };
final float[] nits = {1f, 100f };
final BrightnessConfiguration config = new BrightnessConfiguration.Builder(lux, nits)
@@ -238,6 +244,7 @@
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
mInjector.setWriteStream(baos);
mDataStore.saveIfNeeded();
+ mTestLooper.dispatchAll();
assertTrue(mInjector.wasWriteSuccessful());
TestInjector newInjector = new TestInjector();
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
index f27b8c2..8112ca8 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
@@ -560,8 +560,19 @@
HdmiCecMessage reportArcInitiated = HdmiCecMessageBuilder.buildReportArcInitiated(
ADDR_TV,
ADDR_AUDIO_SYSTEM);
- assertThat(mNativeWrapper.getResultMessages()).contains(reportArcInitiated);
+ // <Report ARC Initiated> should only be sent after SAD querying is done
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(reportArcInitiated);
+
+ // Finish querying SADs
assertThat(mNativeWrapper.getResultMessages()).contains(SAD_QUERY);
+ mNativeWrapper.clearResultMessages();
+ mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS);
+ mTestLooper.dispatchAll();
+ assertThat(mNativeWrapper.getResultMessages()).contains(SAD_QUERY);
+ mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS);
+ mTestLooper.dispatchAll();
+
+ assertThat(mNativeWrapper.getResultMessages()).contains(reportArcInitiated);
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/RequestSadActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/RequestSadActionTest.java
index f7983ca..3228e82 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/RequestSadActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/RequestSadActionTest.java
@@ -139,11 +139,12 @@
}
@Test
- public void noResponse_queryAgain_emptyResult() {
+ public void noResponse_queryAgainOnce_emptyResult() {
RequestSadAction action = new RequestSadAction(mHdmiCecLocalDeviceTv, ADDR_AUDIO_SYSTEM,
mCallback);
action.start();
mTestLooper.dispatchAll();
+ assertThat(mSupportedSads).isNull();
HdmiCecMessage expected1 = HdmiCecMessageBuilder.buildRequestShortAudioDescriptor(
mTvLogicalAddress, Constants.ADDR_AUDIO_SYSTEM,
@@ -153,45 +154,90 @@
mTestLooper.moveTimeForward(TIMEOUT_MS);
mTestLooper.dispatchAll();
assertThat(mNativeWrapper.getResultMessages()).contains(expected1);
- mNativeWrapper.clearResultMessages();
mTestLooper.moveTimeForward(TIMEOUT_MS);
mTestLooper.dispatchAll();
+ assertThat(mSupportedSads).isNotNull();
+ assertThat(mSupportedSads.size()).isEqualTo(0);
+
HdmiCecMessage expected2 = HdmiCecMessageBuilder.buildRequestShortAudioDescriptor(
mTvLogicalAddress, Constants.ADDR_AUDIO_SYSTEM,
CODECS_TO_QUERY_2.stream().mapToInt(i -> i).toArray());
- assertThat(mNativeWrapper.getResultMessages()).contains(expected2);
- mNativeWrapper.clearResultMessages();
- mTestLooper.moveTimeForward(TIMEOUT_MS);
- mTestLooper.dispatchAll();
- assertThat(mNativeWrapper.getResultMessages()).contains(expected2);
- mNativeWrapper.clearResultMessages();
- mTestLooper.moveTimeForward(TIMEOUT_MS);
- mTestLooper.dispatchAll();
-
HdmiCecMessage expected3 = HdmiCecMessageBuilder.buildRequestShortAudioDescriptor(
mTvLogicalAddress, Constants.ADDR_AUDIO_SYSTEM,
CODECS_TO_QUERY_3.stream().mapToInt(i -> i).toArray());
- assertThat(mNativeWrapper.getResultMessages()).contains(expected3);
- mNativeWrapper.clearResultMessages();
- mTestLooper.moveTimeForward(TIMEOUT_MS);
- mTestLooper.dispatchAll();
- assertThat(mNativeWrapper.getResultMessages()).contains(expected3);
- mNativeWrapper.clearResultMessages();
- mTestLooper.moveTimeForward(TIMEOUT_MS);
- mTestLooper.dispatchAll();
-
HdmiCecMessage expected4 = HdmiCecMessageBuilder.buildRequestShortAudioDescriptor(
mTvLogicalAddress, Constants.ADDR_AUDIO_SYSTEM,
CODECS_TO_QUERY_4.stream().mapToInt(i -> i).toArray());
- assertThat(mNativeWrapper.getResultMessages()).contains(expected4);
- mNativeWrapper.clearResultMessages();
+
mTestLooper.moveTimeForward(TIMEOUT_MS);
mTestLooper.dispatchAll();
- assertThat(mNativeWrapper.getResultMessages()).contains(expected4);
+ mTestLooper.moveTimeForward(TIMEOUT_MS);
+ mTestLooper.dispatchAll();
+ mTestLooper.moveTimeForward(TIMEOUT_MS);
+ mTestLooper.dispatchAll();
+ mTestLooper.moveTimeForward(TIMEOUT_MS);
+ mTestLooper.dispatchAll();
+ mTestLooper.moveTimeForward(TIMEOUT_MS);
+ mTestLooper.dispatchAll();
mTestLooper.moveTimeForward(TIMEOUT_MS);
mTestLooper.dispatchAll();
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(expected2);
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(expected3);
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(expected4);
+ assertThat(mSupportedSads.size()).isEqualTo(0);
+ }
+
+ @Test
+ public void unrecognizedOpcode_dontQueryAgain_emptyResult() {
+ RequestSadAction action = new RequestSadAction(mHdmiCecLocalDeviceTv, ADDR_AUDIO_SYSTEM,
+ mCallback);
+ action.start();
+ mTestLooper.dispatchAll();
+ assertThat(mSupportedSads).isNull();
+
+ HdmiCecMessage unrecognizedOpcode = HdmiCecMessageBuilder.buildFeatureAbortCommand(
+ Constants.ADDR_AUDIO_SYSTEM, mTvLogicalAddress,
+ Constants.MESSAGE_REQUEST_SHORT_AUDIO_DESCRIPTOR,
+ Constants.ABORT_UNRECOGNIZED_OPCODE);
+
+ HdmiCecMessage expected1 = HdmiCecMessageBuilder.buildRequestShortAudioDescriptor(
+ mTvLogicalAddress, Constants.ADDR_AUDIO_SYSTEM,
+ CODECS_TO_QUERY_1.stream().mapToInt(i -> i).toArray());
+ assertThat(mNativeWrapper.getResultMessages()).contains(expected1);
+ action.processCommand(unrecognizedOpcode);
+ mTestLooper.dispatchAll();
+
+ assertThat(mSupportedSads).isNotNull();
+ assertThat(mSupportedSads.size()).isEqualTo(0);
+
+ HdmiCecMessage expected2 = HdmiCecMessageBuilder.buildRequestShortAudioDescriptor(
+ mTvLogicalAddress, Constants.ADDR_AUDIO_SYSTEM,
+ CODECS_TO_QUERY_2.stream().mapToInt(i -> i).toArray());
+ HdmiCecMessage expected3 = HdmiCecMessageBuilder.buildRequestShortAudioDescriptor(
+ mTvLogicalAddress, Constants.ADDR_AUDIO_SYSTEM,
+ CODECS_TO_QUERY_3.stream().mapToInt(i -> i).toArray());
+ HdmiCecMessage expected4 = HdmiCecMessageBuilder.buildRequestShortAudioDescriptor(
+ mTvLogicalAddress, Constants.ADDR_AUDIO_SYSTEM,
+ CODECS_TO_QUERY_4.stream().mapToInt(i -> i).toArray());
+
+ mTestLooper.moveTimeForward(TIMEOUT_MS);
+ mTestLooper.dispatchAll();
+ mTestLooper.moveTimeForward(TIMEOUT_MS);
+ mTestLooper.dispatchAll();
+ mTestLooper.moveTimeForward(TIMEOUT_MS);
+ mTestLooper.dispatchAll();
+ mTestLooper.moveTimeForward(TIMEOUT_MS);
+ mTestLooper.dispatchAll();
+ mTestLooper.moveTimeForward(TIMEOUT_MS);
+ mTestLooper.dispatchAll();
+ mTestLooper.moveTimeForward(TIMEOUT_MS);
+ mTestLooper.dispatchAll();
+
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(expected2);
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(expected3);
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(expected4);
assertThat(mSupportedSads.size()).isEqualTo(0);
}
@@ -455,11 +501,12 @@
}
@Test
- public void invalidMessageLength_queryAgain() {
+ public void invalidMessageLength_queryAgainOnce() {
RequestSadAction action = new RequestSadAction(mHdmiCecLocalDeviceTv, ADDR_AUDIO_SYSTEM,
mCallback);
action.start();
mTestLooper.dispatchAll();
+ assertThat(mSupportedSads).isNull();
HdmiCecMessage expected1 = HdmiCecMessageBuilder.buildRequestShortAudioDescriptor(
mTvLogicalAddress, Constants.ADDR_AUDIO_SYSTEM,
@@ -482,63 +529,35 @@
mTestLooper.moveTimeForward(TIMEOUT_MS);
mTestLooper.dispatchAll();
+ assertThat(mSupportedSads).isNotNull();
+ assertThat(mSupportedSads.size()).isEqualTo(0);
+
HdmiCecMessage expected2 = HdmiCecMessageBuilder.buildRequestShortAudioDescriptor(
mTvLogicalAddress, Constants.ADDR_AUDIO_SYSTEM,
CODECS_TO_QUERY_2.stream().mapToInt(i -> i).toArray());
- byte[] sadsToRespond_2 = new byte[]{
- 0x05, 0x18, 0x4A,
- 0x06, 0x64, 0x5A,
- 0x07,
- 0x08, 0x20, 0x0A};
- HdmiCecMessage response2 = HdmiCecMessageBuilder.buildReportShortAudioDescriptor(
- Constants.ADDR_AUDIO_SYSTEM, mTvLogicalAddress, sadsToRespond_2);
- assertThat(mNativeWrapper.getResultMessages()).contains(expected2);
- mNativeWrapper.clearResultMessages();
- action.processCommand(response2);
- mTestLooper.dispatchAll();
- mTestLooper.moveTimeForward(TIMEOUT_MS);
- mTestLooper.dispatchAll();
- assertThat(mNativeWrapper.getResultMessages()).contains(expected2);
- mNativeWrapper.clearResultMessages();
- mTestLooper.moveTimeForward(TIMEOUT_MS);
- mTestLooper.dispatchAll();
-
HdmiCecMessage expected3 = HdmiCecMessageBuilder.buildRequestShortAudioDescriptor(
mTvLogicalAddress, Constants.ADDR_AUDIO_SYSTEM,
CODECS_TO_QUERY_3.stream().mapToInt(i -> i).toArray());
- byte[] sadsToRespond_3 = new byte[0];
- HdmiCecMessage response3 = HdmiCecMessageBuilder.buildReportShortAudioDescriptor(
- Constants.ADDR_AUDIO_SYSTEM, mTvLogicalAddress, sadsToRespond_3);
- assertThat(mNativeWrapper.getResultMessages()).contains(expected3);
- mNativeWrapper.clearResultMessages();
- action.processCommand(response3);
- mTestLooper.dispatchAll();
- mTestLooper.moveTimeForward(TIMEOUT_MS);
- mTestLooper.dispatchAll();
- assertThat(mNativeWrapper.getResultMessages()).contains(expected3);
- mNativeWrapper.clearResultMessages();
- mTestLooper.moveTimeForward(TIMEOUT_MS);
- mTestLooper.dispatchAll();
-
HdmiCecMessage expected4 = HdmiCecMessageBuilder.buildRequestShortAudioDescriptor(
mTvLogicalAddress, Constants.ADDR_AUDIO_SYSTEM,
CODECS_TO_QUERY_4.stream().mapToInt(i -> i).toArray());
- byte[] sadsToRespond_4 = new byte[]{
- 0x0D, 0x18, 0x4A,
- 0x0E, 0x64, 0x5A,
- 0x0F, 0x4B};
- HdmiCecMessage response4 = HdmiCecMessageBuilder.buildReportShortAudioDescriptor(
- Constants.ADDR_AUDIO_SYSTEM, mTvLogicalAddress, sadsToRespond_4);
- assertThat(mNativeWrapper.getResultMessages()).contains(expected4);
- mNativeWrapper.clearResultMessages();
- action.processCommand(response4);
+
+ mTestLooper.moveTimeForward(TIMEOUT_MS);
mTestLooper.dispatchAll();
mTestLooper.moveTimeForward(TIMEOUT_MS);
mTestLooper.dispatchAll();
- assertThat(mNativeWrapper.getResultMessages()).contains(expected4);
+ mTestLooper.moveTimeForward(TIMEOUT_MS);
+ mTestLooper.dispatchAll();
+ mTestLooper.moveTimeForward(TIMEOUT_MS);
+ mTestLooper.dispatchAll();
+ mTestLooper.moveTimeForward(TIMEOUT_MS);
+ mTestLooper.dispatchAll();
mTestLooper.moveTimeForward(TIMEOUT_MS);
mTestLooper.dispatchAll();
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(expected2);
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(expected3);
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(expected4);
assertThat(mSupportedSads.size()).isEqualTo(0);
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java
index 0943918..20482af 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java
@@ -524,6 +524,18 @@
assertThat(backingApexFile).isNull();
}
+ @Test
+ public void testActiveApexChanged() throws RemoteException {
+ ApexInfo apex1 = createApexInfo(
+ "com.apex1", 37, true, true, new File("/data/apex/active/com.apex@37.apex"));
+ apex1.activeApexChanged = true;
+ apex1.preinstalledModulePath = apex1.modulePath;
+ when(mApexService.getActivePackages()).thenReturn(new ApexInfo[]{apex1});
+ final ApexManager.ActiveApexInfo activeApex = mApexManager.getActiveApexInfos().get(0);
+ assertThat(activeApex.apexModuleName).isEqualTo("com.apex1");
+ assertThat(activeApex.activeApexChanged).isTrue();
+ }
+
private ApexInfo createApexInfoForTestPkg(boolean isActive, boolean isFactory, int version) {
File apexFile = extractResource(TEST_APEX_PKG, TEST_APEX_FILE_NAME);
ApexInfo apexInfo = new ApexInfo();
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/GnssTimeUpdateServiceTest.java b/services/tests/servicestests/src/com/android/server/timedetector/GnssTimeUpdateServiceTest.java
index 8ac6dfb..aad5cd6 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/GnssTimeUpdateServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/GnssTimeUpdateServiceTest.java
@@ -85,6 +85,9 @@
when(mMockContext.getSystemService(AlarmManager.class))
.thenReturn(mMockAlarmManager);
+ when(mMockLocationManager.hasProvider(LocationManager.GPS_PROVIDER))
+ .thenReturn(true);
+
LocalServices.addService(LocationManagerInternal.class, mLocationManagerInternal);
mGnssTimeUpdateService =
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 95a9ec4..62acc7a 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -9348,8 +9348,7 @@
nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
- mBinderService.setNotificationsEnabledForPackage(
- r.getSbn().getPackageName(), r.getUid(), false);
+ when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
// normal blocked notifications - blocked
mService.addEnqueuedNotification(r);
@@ -9574,6 +9573,8 @@
@Test
public void testMaybeShowReviewPermissionsNotification_unknown() {
+ reset(mMockNm);
+
// Set up various possible states of the settings int and confirm whether or not the
// notification is shown as expected
@@ -9587,6 +9588,8 @@
@Test
public void testMaybeShowReviewPermissionsNotification_shouldShow() {
+ reset(mMockNm);
+
// If state is SHOULD_SHOW, it ... should show
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE,
@@ -9599,6 +9602,8 @@
@Test
public void testMaybeShowReviewPermissionsNotification_alreadyShown() {
+ reset(mMockNm);
+
// If state is either USER_INTERACTED or DISMISSED, we should not show this on boot
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE,
@@ -9615,6 +9620,8 @@
@Test
public void testMaybeShowReviewPermissionsNotification_reshown() {
+ reset(mMockNm);
+
// If we have re-shown the notification and the user did not subsequently interacted with
// it, then make sure we show when trying on boot
Settings.Global.putInt(mContext.getContentResolver(),
@@ -9628,6 +9635,8 @@
@Test
public void testRescheduledReviewPermissionsNotification() {
+ reset(mMockNm);
+
// when rescheduled, the notification goes through the NotificationManagerInternal service
// this call doesn't need to know anything about previously scheduled state -- if called,
// it should send the notification & write the appropriate int to Settings
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PermissionHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PermissionHelperTest.java
index 3a352cb..4c7e843 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PermissionHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PermissionHelperTest.java
@@ -17,7 +17,6 @@
import static android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
import static android.content.pm.PackageManager.FLAG_PERMISSION_POLICY_FIXED;
-import static android.content.pm.PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
import static android.content.pm.PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET;
import static android.content.pm.PackageManager.GET_PERMISSIONS;
@@ -26,8 +25,6 @@
import static com.google.common.truth.Truth.assertThat;
-import static junit.framework.Assert.fail;
-
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
@@ -54,7 +51,6 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Lists;
import org.junit.Before;
import org.junit.Test;
@@ -62,14 +58,7 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.lang.reflect.Parameter;
-import java.lang.reflect.Type;
-import java.util.List;
import java.util.Map;
-import java.util.Objects;
import java.util.Set;
@SmallTest
@@ -88,7 +77,7 @@
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- mPermissionHelper = new PermissionHelper(mPmi, mPackageManager, mPermManager, false);
+ mPermissionHelper = new PermissionHelper(mPmi, mPackageManager, mPermManager);
PackageInfo testPkgInfo = new PackageInfo();
testPkgInfo.requestedPermissions = new String[]{ Manifest.permission.POST_NOTIFICATIONS };
when(mPackageManager.getPackageInfo(anyString(), anyLong(), anyInt()))
@@ -97,12 +86,12 @@
@Test
public void testHasPermission() throws Exception {
- when(mPmi.checkPostNotificationsPermissionGrantedOrLegacyAccess(anyInt()))
+ when(mPmi.checkUidPermission(anyInt(), anyString()))
.thenReturn(PERMISSION_GRANTED);
assertThat(mPermissionHelper.hasPermission(1)).isTrue();
- when(mPmi.checkPostNotificationsPermissionGrantedOrLegacyAccess(anyInt()))
+ when(mPmi.checkUidPermission(anyInt(), anyString()))
.thenReturn(PERMISSION_DENIED);
assertThat(mPermissionHelper.hasPermission(1)).isFalse();
@@ -194,79 +183,12 @@
verify(mPermManager).grantRuntimePermission(
"pkg", Manifest.permission.POST_NOTIFICATIONS, 10);
verify(mPermManager).updatePermissionFlags("pkg", Manifest.permission.POST_NOTIFICATIONS,
- FLAG_PERMISSION_USER_SET | FLAG_PERMISSION_REVIEW_REQUIRED,
- FLAG_PERMISSION_USER_SET, true, 10);
- }
-
- @Test
- public void testSetNotificationPermission_grantReviewRequired() throws Exception {
- when(mPmi.checkPermission(anyString(), anyString(), anyInt()))
- .thenReturn(PERMISSION_DENIED);
-
- mPermissionHelper.setNotificationPermission("pkg", 10, true, false, true);
-
- verify(mPermManager, never()).revokeRuntimePermission(
- "pkg", Manifest.permission.POST_NOTIFICATIONS, 10, "PermissionHelper");
- verify(mPermManager).updatePermissionFlags("pkg", Manifest.permission.POST_NOTIFICATIONS,
- FLAG_PERMISSION_REVIEW_REQUIRED, FLAG_PERMISSION_REVIEW_REQUIRED, true, 10);
- }
-
- @Test
- public void testSetNotificationPermission_pkgPerm_grantReviewRequired() throws Exception {
- when(mPmi.checkPermission(anyString(), anyString(), anyInt()))
- .thenReturn(PERMISSION_DENIED);
-
- PermissionHelper.PackagePermission pkgPerm = new PermissionHelper.PackagePermission(
- "pkg", 10, true, false);
- mPermissionHelper.setNotificationPermission(pkgPerm);
-
- verify(mPermManager, never()).revokeRuntimePermission(
- "pkg", Manifest.permission.POST_NOTIFICATIONS, 10, "PermissionHelper");
- verify(mPermManager).updatePermissionFlags("pkg", Manifest.permission.POST_NOTIFICATIONS,
- FLAG_PERMISSION_REVIEW_REQUIRED, FLAG_PERMISSION_REVIEW_REQUIRED, true, 10);
- }
-
- @Test
- public void testSetNotificationPermission_pkgPerm_notUserSet_grantedByDefaultPermNotSet()
- throws Exception {
- when(mPmi.checkPermission(anyString(), anyString(), anyInt()))
- .thenReturn(PERMISSION_DENIED);
- when(mPermManager.getPermissionFlags(anyString(),
- eq(Manifest.permission.POST_NOTIFICATIONS),
- anyInt())).thenReturn(FLAG_PERMISSION_GRANTED_BY_DEFAULT);
- PermissionHelper.PackagePermission pkgPerm = new PermissionHelper.PackagePermission(
- "pkg", 10, true, false);
-
- mPermissionHelper.setNotificationPermission(pkgPerm);
- verify(mPermManager, never()).revokeRuntimePermission(
- anyString(), anyString(), anyInt(), anyString());
- verify(mPermManager, never()).updatePermissionFlags(
- anyString(), anyString(), anyInt(), anyInt(), anyBoolean(), anyInt());
- }
-
- @Test
- public void testSetNotificationPermission_pkgPerm_userSet_grantedByDefaultPermSet()
- throws Exception {
- when(mPmi.checkPermission(anyString(), anyString(), anyInt()))
- .thenReturn(PERMISSION_DENIED);
- when(mPermManager.getPermissionFlags(anyString(),
- eq(Manifest.permission.POST_NOTIFICATIONS),
- anyInt())).thenReturn(FLAG_PERMISSION_GRANTED_BY_DEFAULT);
- PermissionHelper.PackagePermission pkgPerm = new PermissionHelper.PackagePermission(
- "pkg", 10, true, true);
-
- mPermissionHelper.setNotificationPermission(pkgPerm);
- verify(mPermManager).grantRuntimePermission(
- "pkg", Manifest.permission.POST_NOTIFICATIONS, 10);
- verify(mPermManager).updatePermissionFlags("pkg", Manifest.permission.POST_NOTIFICATIONS,
- FLAG_PERMISSION_USER_SET | FLAG_PERMISSION_REVIEW_REQUIRED,
- FLAG_PERMISSION_USER_SET, true, 10);
+ FLAG_PERMISSION_USER_SET, FLAG_PERMISSION_USER_SET, true, 10);
}
@Test
public void testSetNotificationPermission_pkgPerm_grantedByDefaultPermSet_allUserSet()
throws Exception {
- mPermissionHelper = new PermissionHelper(mPmi, mPackageManager, mPermManager, true);
when(mPmi.checkPermission(anyString(), anyString(), anyInt()))
.thenReturn(PERMISSION_DENIED);
when(mPermManager.getPermissionFlags(anyString(),
@@ -279,8 +201,7 @@
verify(mPermManager).grantRuntimePermission(
"pkg", Manifest.permission.POST_NOTIFICATIONS, 10);
verify(mPermManager).updatePermissionFlags("pkg", Manifest.permission.POST_NOTIFICATIONS,
- FLAG_PERMISSION_USER_SET | FLAG_PERMISSION_REVIEW_REQUIRED,
- FLAG_PERMISSION_USER_SET, true, 10);
+ FLAG_PERMISSION_USER_SET, FLAG_PERMISSION_USER_SET, true, 10);
}
@Test
@@ -293,8 +214,7 @@
verify(mPermManager).revokeRuntimePermission(
eq("pkg"), eq(Manifest.permission.POST_NOTIFICATIONS), eq(10), anyString());
verify(mPermManager).updatePermissionFlags("pkg", Manifest.permission.POST_NOTIFICATIONS,
- FLAG_PERMISSION_USER_SET | FLAG_PERMISSION_REVIEW_REQUIRED,
- FLAG_PERMISSION_USER_SET, true, 10);
+ FLAG_PERMISSION_USER_SET, FLAG_PERMISSION_USER_SET, true, 10);
}
@Test
@@ -306,8 +226,8 @@
verify(mPermManager).grantRuntimePermission(
"pkg", Manifest.permission.POST_NOTIFICATIONS, 10);
- verify(mPermManager, never()).updatePermissionFlags(
- anyString(), anyString(), anyInt(), anyInt(), anyBoolean(), anyInt());
+ verify(mPermManager).updatePermissionFlags("pkg", Manifest.permission.POST_NOTIFICATIONS,
+ 0, FLAG_PERMISSION_USER_SET, true, 10);
}
@Test
@@ -319,8 +239,8 @@
verify(mPermManager).revokeRuntimePermission(
eq("pkg"), eq(Manifest.permission.POST_NOTIFICATIONS), eq(10), anyString());
- verify(mPermManager, never()).updatePermissionFlags(
- anyString(), anyString(), anyInt(), anyInt(), anyBoolean(), anyInt());
+ verify(mPermManager).updatePermissionFlags("pkg", Manifest.permission.POST_NOTIFICATIONS,
+ 0, FLAG_PERMISSION_USER_SET, true, 10);
}
@Test
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index a5cec7e..8d50cea 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -85,6 +85,7 @@
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.Signature;
+import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.graphics.Color;
import android.media.AudioAttributes;
@@ -121,6 +122,8 @@
import com.android.server.UiServiceTestCase;
import com.android.server.notification.PermissionHelper.PackagePermission;
+import com.google.common.collect.ImmutableList;
+
import org.json.JSONArray;
import org.json.JSONObject;
import org.junit.Before;
@@ -3523,8 +3526,37 @@
@Test
public void testUpdateNotificationChannel_fixedPermission() {
+ List<UserInfo> users = ImmutableList.of(new UserInfo(UserHandle.USER_SYSTEM, "user0", 0));
when(mPermissionHelper.isPermissionFixed(PKG_O, 0)).thenReturn(true);
+ PackageInfo pm = new PackageInfo();
+ pm.packageName = PKG_O;
+ pm.applicationInfo = new ApplicationInfo();
+ pm.applicationInfo.uid = UID_O;
+ List<PackageInfo> packages = ImmutableList.of(pm);
+ when(mPm.getInstalledPackagesAsUser(any(), anyInt())).thenReturn(packages);
+ mHelper.updateFixedImportance(users);
+ assertTrue(mHelper.isImportanceLocked(PKG_O, UID_O));
+
+ NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
+ mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false);
+
+ NotificationChannel update = new NotificationChannel("a", "a", IMPORTANCE_NONE);
+ update.setAllowBubbles(false);
+
+ mHelper.updateNotificationChannel(PKG_O, UID_O, update, true);
+
+ assertEquals(IMPORTANCE_HIGH,
+ mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).getImportance());
+ assertEquals(false,
+ mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).canBubble());
+ }
+
+ @Test
+ public void testUpdateNotificationChannel_defaultApp() {
+ ArraySet<Pair<String, Integer>> toAdd = new ArraySet<>();
+ toAdd.add(new Pair(PKG_O, UID_O));
+ mHelper.updateDefaultApps(0, null, toAdd);
NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false);
@@ -3595,6 +3627,58 @@
}
@Test
+ public void testUpdateFixedImportance_multiUser() {
+ NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
+ NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW);
+ NotificationChannel c = new NotificationChannel("c", "c", IMPORTANCE_DEFAULT);
+ // different uids, same package
+ mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false);
+ mHelper.createNotificationChannel(PKG_O, UID_O, b, false, false);
+ mHelper.createNotificationChannel(PKG_O, UserHandle.PER_USER_RANGE + 1, c, true, true);
+
+ UserInfo user = new UserInfo();
+ user.id = 0;
+ List<UserInfo> users = ImmutableList.of(user);
+ when(mPermissionHelper.isPermissionFixed(PKG_O, 0)).thenReturn(true);
+ PackageInfo pm = new PackageInfo();
+ pm.packageName = PKG_O;
+ pm.applicationInfo = new ApplicationInfo();
+ pm.applicationInfo.uid = UID_O;
+ List<PackageInfo> packages = ImmutableList.of(pm);
+ when(mPm.getInstalledPackagesAsUser(any(), eq(0))).thenReturn(packages);
+ mHelper.updateFixedImportance(users);
+
+ assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false)
+ .isImportanceLockedByCriticalDeviceFunction());
+ assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, b.getId(), false)
+ .isImportanceLockedByCriticalDeviceFunction());
+ assertFalse(mHelper.getNotificationChannel(
+ PKG_O, UserHandle.PER_USER_RANGE + 1, c.getId(), false)
+ .isImportanceLockedByCriticalDeviceFunction());
+ }
+
+ @Test
+ public void testUpdateFixedImportance_channelDoesNotExistYet() {
+ UserInfo user = new UserInfo();
+ user.id = 0;
+ List<UserInfo> users = ImmutableList.of(user);
+ when(mPermissionHelper.isPermissionFixed(PKG_O, 0)).thenReturn(true);
+ PackageInfo pm = new PackageInfo();
+ pm.packageName = PKG_O;
+ pm.applicationInfo = new ApplicationInfo();
+ pm.applicationInfo.uid = UID_O;
+ List<PackageInfo> packages = ImmutableList.of(pm);
+ when(mPm.getInstalledPackagesAsUser(any(), eq(0))).thenReturn(packages);
+ mHelper.updateFixedImportance(users);
+
+ NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
+ mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false);
+
+ assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false)
+ .isImportanceLockedByCriticalDeviceFunction());
+ }
+
+ @Test
public void testUpdateDefaultApps_add_multiUser() {
NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW);
@@ -3759,6 +3843,62 @@
}
@Test
+ public void testUpdateFixedImportance_thenDefaultAppsRemoves() {
+ UserInfo user = new UserInfo();
+ user.id = 0;
+ List<UserInfo> users = ImmutableList.of(user);
+ when(mPermissionHelper.isPermissionFixed(PKG_O, 0)).thenReturn(true);
+ PackageInfo pm = new PackageInfo();
+ pm.packageName = PKG_O;
+ pm.applicationInfo = new ApplicationInfo();
+ pm.applicationInfo.uid = UID_O;
+ List<PackageInfo> packages = ImmutableList.of(pm);
+ when(mPm.getInstalledPackagesAsUser(any(), eq(0))).thenReturn(packages);
+ mHelper.updateFixedImportance(users);
+
+ ArraySet<String> toRemove = new ArraySet<>();
+ toRemove.add(PKG_O);
+ mHelper.updateDefaultApps(0, toRemove, null);
+
+ assertTrue(mHelper.isImportanceLocked(PKG_O, UID_O));
+
+ NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
+ mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false);
+
+ // Still locked by permission if not role
+ assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false)
+ .isImportanceLockedByCriticalDeviceFunction());
+ }
+
+ @Test
+ public void testUpdateDefaultApps_thenNotFixedPermission() {
+ ArraySet<Pair<String, Integer>> toAdd = new ArraySet<>();
+ toAdd.add(new Pair(PKG_O, UID_O));
+ mHelper.updateDefaultApps(0, null, toAdd);
+
+ UserInfo user = new UserInfo();
+ user.id = 0;
+ List<UserInfo> users = ImmutableList.of(user);
+ when(mPermissionHelper.isPermissionFixed(PKG_O, 0)).thenReturn(false);
+ PackageInfo pm = new PackageInfo();
+ pm.packageName = PKG_O;
+ pm.applicationInfo = new ApplicationInfo();
+ pm.applicationInfo.uid = UID_O;
+ List<PackageInfo> packages = ImmutableList.of(pm);
+ when(mPm.getInstalledPackagesAsUser(any(), eq(0))).thenReturn(packages);
+ mHelper.updateFixedImportance(users);
+
+ assertTrue(mHelper.isImportanceLocked(PKG_O, UID_O));
+
+ NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
+ mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false);
+
+ // Still locked by role if not permission
+ assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false)
+ .isImportanceLockedByCriticalDeviceFunction());
+ }
+
+ @Test
public void testChannelXml_backupDefaultApp() throws Exception {
NotificationChannel channel1 =
new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
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 533540e..b8f0b72 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -611,10 +611,9 @@
activity.setRequestedOrientation(activityCurOrientation == ORIENTATION_LANDSCAPE
? SCREEN_ORIENTATION_PORTRAIT : SCREEN_ORIENTATION_LANDSCAPE);
- // Asserts fixed orientation request is ignored, and the orientation is not changed
- // (fill Task).
- assertEquals(activityCurOrientation, activity.getConfiguration().orientation);
- assertFalse(activity.isLetterboxedForFixedOrientationAndAspectRatio());
+ // Asserts fixed orientation request is not ignored, and the orientation is changed.
+ assertNotEquals(activityCurOrientation, activity.getConfiguration().orientation);
+ assertTrue(activity.isLetterboxedForFixedOrientationAndAspectRatio());
}
@Test
@@ -1787,13 +1786,16 @@
public void testActivityOnCancelFixedRotationTransform() {
final ActivityRecord activity = createActivityWithTask();
final DisplayRotation displayRotation = activity.mDisplayContent.getDisplayRotation();
+ final RemoteDisplayChangeController remoteDisplayChangeController = activity
+ .mDisplayContent.mRemoteDisplayChangeController;
spyOn(displayRotation);
+ spyOn(remoteDisplayChangeController);
final DisplayContent display = activity.mDisplayContent;
final int originalRotation = display.getRotation();
// Make {@link DisplayContent#sendNewConfiguration} not apply rotation immediately.
- doReturn(true).when(displayRotation).isWaitingForRemoteRotation();
+ doReturn(true).when(remoteDisplayChangeController).isWaitingForRemoteDisplayChange();
doReturn((originalRotation + 1) % 4).when(displayRotation).rotationForOrientation(
anyInt() /* orientation */, anyInt() /* lastRotation */);
// Set to visible so the activity can freeze the screen.
@@ -1831,7 +1833,7 @@
// Simulate the remote rotation has completed and the configuration doesn't change, then
// the rotated activity should also be restored by clearing the transform.
displayRotation.updateRotationUnchecked(true /* forceUpdate */);
- doReturn(false).when(displayRotation).isWaitingForRemoteRotation();
+ doReturn(false).when(remoteDisplayChangeController).isWaitingForRemoteDisplayChange();
clearInvocations(activity);
display.setFixedRotationLaunchingAppUnchecked(activity);
display.sendNewConfiguration();
@@ -2166,39 +2168,6 @@
}
@Test
- public void testSupportsSplitScreenWindowingMode() {
- final ActivityRecord activity = new ActivityBuilder(mAtm)
- .setCreateTask(true)
- .setResizeMode(ActivityInfo.RESIZE_MODE_UNRESIZEABLE)
- .setScreenOrientation(SCREEN_ORIENTATION_LANDSCAPE)
- .build();
-
- // Not allow non-resizable
- mAtm.mForceResizableActivities = false;
- mAtm.mSupportsNonResizableMultiWindow = -1;
- mAtm.mDevEnableNonResizableMultiWindow = false;
- assertFalse(activity.supportsSplitScreenWindowingMode());
-
- // Force resizable
- mAtm.mForceResizableActivities = true;
- mAtm.mSupportsNonResizableMultiWindow = -1;
- mAtm.mDevEnableNonResizableMultiWindow = false;
- assertTrue(activity.supportsSplitScreenWindowingMode());
-
- // Use development option to allow non-resizable
- mAtm.mForceResizableActivities = false;
- mAtm.mSupportsNonResizableMultiWindow = -1;
- mAtm.mDevEnableNonResizableMultiWindow = true;
- assertTrue(activity.supportsSplitScreenWindowingMode());
-
- // Always allow non-resizable
- mAtm.mForceResizableActivities = false;
- mAtm.mSupportsNonResizableMultiWindow = 1;
- mAtm.mDevEnableNonResizableMultiWindow = false;
- assertTrue(activity.supportsSplitScreenWindowingMode());
- }
-
- @Test
public void testSupportsFreeform() {
final ActivityRecord activity = new ActivityBuilder(mAtm)
.setCreateTask(true)
@@ -2631,7 +2600,11 @@
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_WINDOW_MANAGER,
"splash_screen_exception_list", DEFAULT_COMPONENT_PACKAGE_NAME, false);
testLegacySplashScreen(Build.VERSION_CODES.R, TYPE_PARAMETER_LEGACY_SPLASH_SCREEN);
- testLegacySplashScreen(Build.VERSION_CODES.S, 0);
+ testLegacySplashScreen(Build.VERSION_CODES.S, TYPE_PARAMETER_LEGACY_SPLASH_SCREEN);
+ testLegacySplashScreen(Build.VERSION_CODES.TIRAMISU,
+ TYPE_PARAMETER_LEGACY_SPLASH_SCREEN);
+ // Above T
+ testLegacySplashScreen(Build.VERSION_CODES.TIRAMISU + 1, 0);
} finally {
try {
DeviceConfig.setProperties(properties);
@@ -2854,6 +2827,11 @@
assertTrue(activity2.isResizeable());
activity1.reparent(taskFragment1, POSITION_TOP);
+ // Adds an Activity which doesn't have shared starting data, and verify if it blocks
+ // starting window removal.
+ final ActivityRecord activity3 = new ActivityBuilder(mAtm).build();
+ taskFragment2.addChild(activity3, POSITION_TOP);
+
verify(activity1.getSyncTransaction()).reparent(eq(startingWindow.mSurfaceControl),
eq(task.mSurfaceControl));
assertEquals(activity1.mStartingData, startingWindow.mStartingData);
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
index 0a13a36..00e1ed2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
@@ -1157,6 +1157,41 @@
verify(activity).setDropInputMode(DropInputMode.NONE);
}
+ /**
+ * We don't need to drop input for fully trusted embedding (system app, and embedding in the
+ * same app). This will allow users to do fast tapping.
+ */
+ @Test
+ public void testOverrideTaskFragmentAdapter_noInputProtectedForFullyTrustedAnimation() {
+ final Task task = createTask(mDisplayContent);
+ final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
+ final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
+ setupTaskFragmentRemoteAnimation(organizer, task.mTaskId, remoteAnimationRunner);
+
+ // Create a TaskFragment with only trusted embedded activity
+ final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm)
+ .setParentTask(task)
+ .createActivityCount(1)
+ .setOrganizer(organizer)
+ .build();
+ final ActivityRecord activity = taskFragment.getChildAt(0).asActivityRecord();
+ prepareActivityForAppTransition(activity);
+ final int uid = mAtm.mTaskFragmentOrganizerController.getTaskFragmentOrganizerUid(
+ getITaskFragmentOrganizer(organizer));
+ doReturn(true).when(task).isFullyTrustedEmbedding(uid);
+ spyOn(mDisplayContent.mAppTransition);
+
+ // Prepare and start transition.
+ prepareAndTriggerAppTransition(activity, null /* closingActivity */, taskFragment);
+ mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+
+ // The animation will be animated remotely by client, but input should not be dropped for
+ // fully trusted.
+ assertTrue(remoteAnimationRunner.isAnimationStarted());
+ verify(activity, never()).setDropInputForAnimation(true);
+ verify(activity, never()).setDropInputMode(DropInputMode.ALL);
+ }
+
@Test
public void testTransitionGoodToGoForTaskFragments() {
final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
@@ -1226,8 +1261,7 @@
TestRemoteAnimationRunner remoteAnimationRunner) {
final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter(
remoteAnimationRunner, 10, 1);
- final ITaskFragmentOrganizer iOrganizer =
- ITaskFragmentOrganizer.Stub.asInterface(organizer.getOrganizerToken().asBinder());
+ final ITaskFragmentOrganizer iOrganizer = getITaskFragmentOrganizer(organizer);
final RemoteAnimationDefinition definition = new RemoteAnimationDefinition();
definition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_CHANGE, adapter);
definition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_OPEN, adapter);
@@ -1237,6 +1271,11 @@
definition);
}
+ private static ITaskFragmentOrganizer getITaskFragmentOrganizer(
+ TaskFragmentOrganizer organizer) {
+ return ITaskFragmentOrganizer.Stub.asInterface(organizer.getOrganizerToken().asBinder());
+ }
+
private void prepareAndTriggerAppTransition(@Nullable ActivityRecord openingActivity,
@Nullable ActivityRecord closingActivity, @Nullable TaskFragment changingTaskFragment) {
if (openingActivity != null) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
index eb6395b..3592158 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
@@ -39,8 +39,10 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt;
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 static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS;
import static com.android.server.wm.WindowContainer.POSITION_TOP;
import static org.junit.Assert.assertEquals;
@@ -48,7 +50,9 @@
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
import android.graphics.Rect;
import android.os.Binder;
@@ -376,7 +380,7 @@
doReturn(false).when(dc).onDescendantOrientationChanged(any());
final WindowState exitingAppWindow = createWindow(null /* parent */, TYPE_BASE_APPLICATION,
dc, "exiting app");
- final ActivityRecord exitingActivity= exitingAppWindow.mActivityRecord;
+ final ActivityRecord exitingActivity = exitingAppWindow.mActivityRecord;
// Wait until everything in animation handler get executed to prevent the exiting window
// from being removed during WindowSurfacePlacer Traversal.
waitUntilHandlersIdle();
@@ -405,6 +409,41 @@
}
@Test
+ public void testDelayWhileRecents() {
+ final DisplayContent dc = createNewDisplay(Display.STATE_ON);
+ doReturn(false).when(dc).onDescendantOrientationChanged(any());
+ final Task task = createTask(dc);
+
+ // Simulate activity1 launches activity2.
+ final ActivityRecord activity1 = createActivityRecord(task);
+ activity1.setVisible(true);
+ activity1.mVisibleRequested = false;
+ activity1.allDrawn = true;
+ final ActivityRecord activity2 = createActivityRecord(task);
+ activity2.setVisible(false);
+ activity2.mVisibleRequested = true;
+ activity2.allDrawn = true;
+
+ dc.mClosingApps.add(activity1);
+ dc.mOpeningApps.add(activity2);
+ dc.prepareAppTransition(TRANSIT_OPEN);
+ assertTrue(dc.mAppTransition.containsTransitRequest(TRANSIT_OPEN));
+
+ // Wait until everything in animation handler get executed to prevent the exiting window
+ // from being removed during WindowSurfacePlacer Traversal.
+ waitUntilHandlersIdle();
+
+ // Start recents
+ doReturn(true).when(task)
+ .isSelfAnimating(anyInt(), eq(ANIMATION_TYPE_RECENTS));
+
+ dc.mAppTransitionController.handleAppTransitionReady();
+
+ verify(activity1, never()).commitVisibility(anyBoolean(), anyBoolean(), anyBoolean());
+ verify(activity2, never()).commitVisibility(anyBoolean(), anyBoolean(), anyBoolean());
+ }
+
+ @Test
public void testGetAnimationStyleResId() {
// Verify getAnimationStyleResId will return as LayoutParams.windowAnimations when without
// specifying window type.
diff --git a/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java b/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java
index 88c7017..ef84a4b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java
@@ -64,6 +64,11 @@
}
@Override
+ public SurfaceControl.Transaction getSyncTransaction() {
+ return mTransaction;
+ }
+
+ @Override
public SurfaceControl.Transaction getPendingTransaction() {
return mTransaction;
}
@@ -102,6 +107,11 @@
}
@Override
+ public SurfaceControl.Transaction getSyncTransaction() {
+ return mHostTransaction;
+ }
+
+ @Override
public SurfaceControl.Transaction getPendingTransaction() {
return mHostTransaction;
}
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 89dfffb..4716d15 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -124,8 +124,8 @@
import android.view.DisplayCutout;
import android.view.DisplayInfo;
import android.view.Gravity;
-import android.view.IDisplayWindowRotationCallback;
-import android.view.IDisplayWindowRotationController;
+import android.view.IDisplayChangeWindowCallback;
+import android.view.IDisplayChangeWindowController;
import android.view.ISystemGestureExclusionListener;
import android.view.IWindowManager;
import android.view.InsetsState;
@@ -136,6 +136,7 @@
import android.view.SurfaceControl.Transaction;
import android.view.View;
import android.view.WindowManager;
+import android.window.DisplayAreaInfo;
import android.window.IDisplayAreaOrganizer;
import android.window.WindowContainerToken;
@@ -1801,15 +1802,16 @@
return true;
}).when(dc).updateDisplayOverrideConfigurationLocked();
final boolean[] called = new boolean[1];
- mWm.mDisplayRotationController =
- new IDisplayWindowRotationController.Stub() {
+ mWm.mDisplayChangeController =
+ new IDisplayChangeWindowController.Stub() {
@Override
- public void onRotateDisplay(int displayId, int fromRotation, int toRotation,
- IDisplayWindowRotationCallback callback) {
+ public void onDisplayChange(int displayId, int fromRotation, int toRotation,
+ DisplayAreaInfo newDisplayAreaInfo,
+ IDisplayChangeWindowCallback callback) throws RemoteException {
called[0] = true;
try {
- callback.continueRotateDisplay(toRotation, null);
+ callback.continueDisplayChange(null);
} catch (RemoteException e) {
assertTrue(false);
}
@@ -1843,13 +1845,14 @@
// Rotate 180 degree so the display doesn't have configuration change. This condition is
// used for the later verification of stop-freezing (without setting mWaitingForConfig).
doReturn((dr.getRotation() + 2) % 4).when(dr).rotationForOrientation(anyInt(), anyInt());
- mWm.mDisplayRotationController =
- new IDisplayWindowRotationController.Stub() {
+ mWm.mDisplayChangeController =
+ new IDisplayChangeWindowController.Stub() {
@Override
- public void onRotateDisplay(int displayId, int fromRotation, int toRotation,
- IDisplayWindowRotationCallback callback) {
+ public void onDisplayChange(int displayId, int fromRotation, int toRotation,
+ DisplayAreaInfo newDisplayAreaInfo,
+ IDisplayChangeWindowCallback callback) throws RemoteException {
try {
- callback.continueRotateDisplay(toRotation, null);
+ callback.continueDisplayChange(null);
} catch (RemoteException e) {
assertTrue(false);
}
@@ -2212,23 +2215,28 @@
*/
@Test
public void testCreateTestDisplayContentFromDimensions() {
- final int displayWidth = 1000;
- final int displayHeight = 2000;
+ final int displayWidth = 540;
+ final int displayHeight = 960;
+ final int density = 192;
+ final int expectedWidthDp = 450; // = 540/(192/160)
+ final int expectedHeightDp = 800; // = 960/(192/160)
final int windowingMode = WINDOWING_MODE_FULLSCREEN;
final boolean ignoreOrientationRequests = false;
final float fixedOrientationLetterboxRatio = 0;
final DisplayContent testDisplayContent = new TestDisplayContent.Builder(mAtm, displayWidth,
- displayHeight).build();
+ displayHeight).setDensityDpi(density).build();
// test display info
final DisplayInfo di = testDisplayContent.getDisplayInfo();
assertEquals(displayWidth, di.logicalWidth);
assertEquals(displayHeight, di.logicalHeight);
- assertEquals(TestDisplayContent.DEFAULT_LOGICAL_DISPLAY_DENSITY, di.logicalDensityDpi);
+ assertEquals(density, di.logicalDensityDpi);
// test configuration
- final WindowConfiguration windowConfig = testDisplayContent.getConfiguration()
- .windowConfiguration;
+ final Configuration config = testDisplayContent.getConfiguration();
+ assertEquals(expectedWidthDp, config.screenWidthDp);
+ assertEquals(expectedHeightDp, config.screenHeightDp);
+ final WindowConfiguration windowConfig = config.windowConfiguration;
assertEquals(displayWidth, windowConfig.getBounds().width());
assertEquals(displayHeight, windowConfig.getBounds().height());
assertEquals(windowingMode, windowConfig.getWindowingMode());
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
index 6d02226..ffa21fa 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
@@ -449,6 +449,36 @@
assertNotNull(app.getInsetsState().peekSource(ITYPE_NAVIGATION_BAR));
}
+ @UseTestDisplay(addWindows = W_INPUT_METHOD)
+ @Test
+ public void testGetInsetsHintForNewControl() {
+ final WindowState app1 = createTestWindow("app1");
+ final WindowState app2 = createTestWindow("app2");
+
+ makeWindowVisible(mImeWindow);
+ final InsetsSourceProvider imeInsetsProvider = getController().getSourceProvider(ITYPE_IME);
+ imeInsetsProvider.setWindowContainer(mImeWindow, null, null);
+ imeInsetsProvider.updateSourceFrame(mImeWindow.getFrame());
+
+ imeInsetsProvider.updateControlForTarget(app1, false);
+ imeInsetsProvider.onPostLayout();
+ final InsetsSourceControl control1 = imeInsetsProvider.getControl(app1);
+ assertNotNull(control1);
+ assertEquals(imeInsetsProvider.getSource().getFrame().height(),
+ control1.getInsetsHint().bottom);
+
+ // Simulate the IME control target updated from app1 to app2 when IME insets was invisible.
+ imeInsetsProvider.setServerVisible(false);
+ imeInsetsProvider.updateControlForTarget(app2, false);
+
+ // Verify insetsHint of the new control is same as last IME source frame after the layout.
+ imeInsetsProvider.onPostLayout();
+ final InsetsSourceControl control2 = imeInsetsProvider.getControl(app2);
+ assertNotNull(control2);
+ assertEquals(imeInsetsProvider.getSource().getFrame().height(),
+ control2.getInsetsHint().bottom);
+ }
+
private WindowState createTestWindow(String name) {
final WindowState win = createWindow(null, TYPE_APPLICATION, name);
win.setHasSurface(true);
diff --git a/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java b/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java
index 1e86522..e502f2f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java
@@ -63,7 +63,7 @@
mLetterbox = new Letterbox(mSurfaces, StubTransaction::new,
() -> mAreCornersRounded, () -> Color.valueOf(mColor),
() -> mHasWallpaperBackground, () -> mBlurRadius, () -> mDarkScrimAlpha,
- /* doubleTapCallback= */ x -> {});
+ /* doubleTapCallbackX= */ x -> {}, /* doubleTapCallbackY= */ y -> {});
mTransaction = spy(StubTransaction.class);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java
index 9fc9489..1d14dc3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java
@@ -82,6 +82,7 @@
import androidx.test.filters.SmallTest;
import com.android.internal.statusbar.IStatusBarService;
+import com.android.internal.telephony.CellBroadcastUtils;
import com.android.internal.widget.LockPatternUtils;
import com.android.server.LocalServices;
import com.android.server.statusbar.StatusBarManagerInternal;
@@ -297,6 +298,22 @@
}
@Test
+ public void testLockTaskViolation_wirelessEmergencyAlerts() {
+ // GIVEN one task record with allowlisted auth that is in lock task mode
+ Task tr = getTask(LOCK_TASK_AUTH_ALLOWLISTED);
+ mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
+
+ // GIVEN cellbroadcast task necessary for emergency warning alerts
+ Task cellbroadcastreceiver = getTask(
+ new Intent().setComponent(
+ CellBroadcastUtils.getDefaultCellBroadcastAlertDialogComponent(mContext)),
+ LOCK_TASK_AUTH_PINNABLE);
+
+ // THEN the cellbroadcast task should all be allowed
+ assertFalse(mLockTaskController.isLockTaskModeViolation(cellbroadcastreceiver));
+ }
+
+ @Test
public void testStopLockTaskMode() throws Exception {
// GIVEN one task record with allowlisted auth that is in lock task mode
Task tr = getTask(LOCK_TASK_AUTH_ALLOWLISTED);
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
index 2847283..caa3569 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -1204,7 +1204,6 @@
RecentTaskInfo info = mRecentTasks.createRecentTaskInfo(task, true);
assertTrue(info.supportsMultiWindow);
- assertTrue(info.supportsSplitScreenMultiWindow);
// The task can be put in split screen even if it is not attached now.
task.removeImmediately();
@@ -1212,7 +1211,6 @@
info = mRecentTasks.createRecentTaskInfo(task, true);
assertTrue(info.supportsMultiWindow);
- assertTrue(info.supportsSplitScreenMultiWindow);
// Test non-resizable.
// The non-resizable task cannot be put in split screen because of the config.
@@ -1222,7 +1220,6 @@
info = mRecentTasks.createRecentTaskInfo(task, true);
assertFalse(info.supportsMultiWindow);
- assertFalse(info.supportsSplitScreenMultiWindow);
// Even if it is not attached, the non-resizable task can be put in split screen as long as
// the device supports it.
@@ -1231,8 +1228,6 @@
info = mRecentTasks.createRecentTaskInfo(task, true);
assertTrue(info.supportsMultiWindow);
- assertTrue(info.supportsSplitScreenMultiWindow);
-
}
private TaskSnapshot createSnapshot(Point taskSize, Point bufferSize) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
index 021568d..eba276f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -61,6 +61,7 @@
import android.util.SparseBooleanArray;
import android.view.IRecentsAnimationRunner;
import android.view.SurfaceControl;
+import android.view.WindowManager.LayoutParams;
import android.window.TaskSnapshot;
import androidx.test.filters.SmallTest;
@@ -162,6 +163,30 @@
}
@Test
+ public void testLaunchAndStartRecents_expectTargetAndVisible() throws Exception {
+ mWm.setRecentsAnimationController(mController);
+ final ActivityRecord homeActivity = createHomeActivity();
+ final Task task = createTask(mDefaultDisplay);
+ // Emulate that activity1 has just launched activity2, but app transition has not yet been
+ // executed.
+ final ActivityRecord activity1 = createActivityRecord(task);
+ activity1.setVisible(true);
+ activity1.mVisibleRequested = false;
+ activity1.addWindow(createWindowState(new LayoutParams(TYPE_BASE_APPLICATION), activity1));
+
+ final ActivityRecord activity2 = createActivityRecord(task);
+ activity2.setVisible(false);
+ activity2.mVisibleRequested = true;
+
+ mDefaultDisplay.getConfiguration().windowConfiguration.setRotation(
+ mDefaultDisplay.getRotation());
+ initializeRecentsAnimationController(mController, homeActivity);
+ mController.startAnimation();
+ verify(mMockRunner, never()).onAnimationCanceled(null /* taskIds */,
+ null /* taskSnapshots */);
+ }
+
+ @Test
public void testWallpaperIncluded_expectTarget() throws Exception {
mWm.setRecentsAnimationController(mController);
final ActivityRecord homeActivity = createHomeActivity();
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 a3b881c..68079f4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
@@ -1090,7 +1090,7 @@
TaskChangeNotificationController controller = mAtm.getTaskChangeNotificationController();
spyOn(controller);
mWm.mRoot.lockAllProfileTasks(profileUserId);
- verify(controller).notifyTaskProfileLocked(eq(task.mTaskId), eq(profileUserId));
+ verify(controller).notifyTaskProfileLocked(any());
// Create the work lock activity on top of the task
final ActivityRecord workLockActivity = new ActivityBuilder(mAtm).setTask(task).build();
@@ -1100,7 +1100,7 @@
// Make sure the listener won't be notified again.
clearInvocations(controller);
mWm.mRoot.lockAllProfileTasks(profileUserId);
- verify(controller, never()).notifyTaskProfileLocked(anyInt(), anyInt());
+ verify(controller, never()).notifyTaskProfileLocked(any());
}
/**
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 76fb7ff..9dc5197 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -1876,6 +1876,28 @@
}
@Test
+ public void testResizableFixedOrientationAppInSplitScreen_letterboxForDifferentOrientation() {
+ setUpDisplaySizeWithApp(1000, 2800);
+ final TestSplitOrganizer organizer =
+ new TestSplitOrganizer(mAtm, mActivity.getDisplayContent());
+
+ // Resizable landscape-only activity.
+ prepareLimitedBounds(mActivity, SCREEN_ORIENTATION_LANDSCAPE, /* isUnresizable= */ false);
+
+ final Rect originalBounds = new Rect(mActivity.getBounds());
+
+ // Move activity to split screen which takes half of the screen.
+ mTask.reparent(organizer.mPrimary, POSITION_TOP, /* moveParents= */ false , "test");
+ organizer.mPrimary.setBounds(0, 0, 1000, 1400);
+ assertEquals(WINDOWING_MODE_MULTI_WINDOW, mTask.getWindowingMode());
+ assertEquals(WINDOWING_MODE_MULTI_WINDOW, mActivity.getWindowingMode());
+
+ // Resizable activity is not in size compat mode but in the letterbox for fixed orientation.
+ assertFitted();
+ assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
+ }
+
+ @Test
public void testSupportsNonResizableInSplitScreen_fillTaskForSameOrientation() {
// Support non resizable in multi window
mAtm.mDevEnableNonResizableMultiWindow = true;
@@ -1928,7 +1950,7 @@
prepareUnresizable(mActivity, /* maxAspect */ 1.1f, SCREEN_ORIENTATION_UNSPECIFIED);
// Bounds are letterboxed to respect the provided max aspect ratio.
- assertEquals(mActivity.getBounds(), new Rect(0, 0, 1000, 1100));
+ assertEquals(mActivity.getBounds(), new Rect(0, 850, 1000, 1950));
// Move activity to split screen which has landscape size.
mTask.reparent(organizer.mPrimary, POSITION_TOP, /* moveParents */ false, "test");
@@ -2045,19 +2067,14 @@
mActivity.mWmService.mLetterboxConfiguration.setLetterboxHorizontalPositionMultiplier(
letterboxHorizontalPositionMultiplier);
prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT);
-
assertEquals(fixedOrientationLetterbox, mActivity.getBounds());
-
// Rotate to put activity in size compat mode.
rotateDisplay(mActivity.mDisplayContent, ROTATION_90);
-
assertTrue(mActivity.inSizeCompatMode());
// Activity is in size compat mode but not scaled.
assertEquals(sizeCompatUnscaled, mActivity.getBounds());
-
// Force activity to scaled down for size compat mode.
resizeDisplay(mTask.mDisplayContent, 700, 1400);
-
assertTrue(mActivity.inSizeCompatMode());
assertScaled();
assertEquals(sizeCompatScaled, mActivity.getBounds());
@@ -2075,6 +2092,109 @@
}
@Test
+ public void testUpdateResolvedBoundsVerticalPosition_top() {
+ // Display configured as (1400, 2800).
+ assertVerticalPositionForDifferentDisplayConfigsForLandscapeActivity(
+ /* letterboxVerticalPositionMultiplier */ 0.0f,
+ // At launch.
+ /* fixedOrientationLetterbox */ new Rect(0, 0, 1400, 700),
+ // After 90 degree rotation.
+ /* sizeCompatUnscaled */ new Rect(700, 0, 2100, 700),
+ // After the display is resized to (1400, 700).
+ /* sizeCompatScaled */ new Rect(0, 0, 700, 350));
+ }
+
+ @Test
+ public void testUpdateResolvedBoundsVerticalPosition_center() {
+ // Display configured as (1400, 2800).
+ assertVerticalPositionForDifferentDisplayConfigsForLandscapeActivity(
+ /* letterboxVerticalPositionMultiplier */ 0.5f,
+ // At launch.
+ /* fixedOrientationLetterbox */ new Rect(0, 1050, 1400, 1750),
+ // After 90 degree rotation.
+ /* sizeCompatUnscaled */ new Rect(700, 350, 2100, 1050),
+ // After the display is resized to (1400, 700).
+ /* sizeCompatScaled */ new Rect(0, 525, 700, 875));
+ }
+
+ @Test
+ public void testUpdateResolvedBoundsVerticalPosition_invalidMultiplier_defaultToCenter() {
+ // Display configured as (1400, 2800).
+
+ // Below 0.0.
+ assertVerticalPositionForDifferentDisplayConfigsForLandscapeActivity(
+ /* letterboxVerticalPositionMultiplier */ -1.0f,
+ // At launch.
+ /* fixedOrientationLetterbox */ new Rect(0, 1050, 1400, 1750),
+ // After 90 degree rotation.
+ /* sizeCompatUnscaled */ new Rect(700, 350, 2100, 1050),
+ // After the display is resized to (1400, 700).
+ /* sizeCompatScaled */ new Rect(0, 525, 700, 875));
+
+ // Above 1.0
+ assertVerticalPositionForDifferentDisplayConfigsForLandscapeActivity(
+ /* letterboxVerticalPositionMultiplier */ 2.0f,
+ // At launch.
+ /* fixedOrientationLetterbox */ new Rect(0, 1050, 1400, 1750),
+ // After 90 degree rotation.
+ /* sizeCompatUnscaled */ new Rect(700, 350, 2100, 1050),
+ // After the display is resized to (1400, 700).
+ /* sizeCompatScaled */ new Rect(0, 525, 700, 875));
+ }
+
+ @Test
+ public void testUpdateResolvedBoundsVerticalPosition_bottom() {
+ // Display configured as (1400, 2800).
+ assertVerticalPositionForDifferentDisplayConfigsForLandscapeActivity(
+ /* letterboxVerticalPositionMultiplier */ 1.0f,
+ // At launch.
+ /* fixedOrientationLetterbox */ new Rect(0, 2100, 1400, 2800),
+ // After 90 degree rotation.
+ /* sizeCompatUnscaled */ new Rect(700, 700, 2100, 1400),
+ // After the display is resized to (1400, 700).
+ /* sizeCompatScaled */ new Rect(0, 1050, 700, 1400));
+ }
+
+ private void assertVerticalPositionForDifferentDisplayConfigsForLandscapeActivity(
+ float letterboxVerticalPositionMultiplier, Rect fixedOrientationLetterbox,
+ Rect sizeCompatUnscaled, Rect sizeCompatScaled) {
+ // Set up a display in portrait and ignoring orientation request.
+ setUpDisplaySizeWithApp(1400, 2800);
+ mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+
+ mActivity.mWmService.mLetterboxConfiguration.setLetterboxVerticalPositionMultiplier(
+ letterboxVerticalPositionMultiplier);
+ prepareUnresizable(mActivity, SCREEN_ORIENTATION_LANDSCAPE);
+
+ assertEquals(fixedOrientationLetterbox, mActivity.getBounds());
+
+ // Rotate to put activity in size compat mode.
+ rotateDisplay(mActivity.mDisplayContent, ROTATION_90);
+
+ assertTrue(mActivity.inSizeCompatMode());
+ // Activity is in size compat mode but not scaled.
+ assertEquals(sizeCompatUnscaled, mActivity.getBounds());
+
+ // Force activity to scaled down for size compat mode.
+ resizeDisplay(mTask.mDisplayContent, 1400, 700);
+
+ assertTrue(mActivity.inSizeCompatMode());
+ assertScaled();
+ assertEquals(sizeCompatScaled, mActivity.getBounds());
+ }
+
+ @Test
+ public void testUpdateResolvedBoundsVerticalPosition_activityFillParentHeight() {
+ // When activity height equals parent height, multiplier shouldn't have any effect.
+ assertVerticalPositionForDifferentDisplayConfigsForPortraitActivity(
+ /* letterboxVerticalPositionMultiplier */ 0.0f);
+ assertVerticalPositionForDifferentDisplayConfigsForPortraitActivity(
+ /* letterboxVerticalPositionMultiplier */ 0.5f);
+ assertVerticalPositionForDifferentDisplayConfigsForPortraitActivity(
+ /* letterboxVerticalPositionMultiplier */ 1.0f);
+ }
+
+ @Test
public void testAreBoundsLetterboxed_letterboxedForAspectRatio_returnsTrue() {
setUpDisplaySizeWithApp(1000, 2500);
@@ -2367,6 +2487,23 @@
mActivity.mWmService.mLetterboxConfiguration.setLetterboxHorizontalPositionMultiplier(
letterboxHorizontalPositionMultiplier);
prepareUnresizable(mActivity, SCREEN_ORIENTATION_LANDSCAPE);
+ assertFitted();
+ // Rotate to put activity in size compat mode.
+ rotateDisplay(mActivity.mDisplayContent, ROTATION_90);
+ assertTrue(mActivity.inSizeCompatMode());
+ // Activity is in size compat mode but not scaled.
+ assertEquals(new Rect(0, 1050, 1400, 1750), mActivity.getBounds());
+ }
+
+ private void assertVerticalPositionForDifferentDisplayConfigsForPortraitActivity(
+ float letterboxVerticalPositionMultiplier) {
+ // Set up a display in portrait and ignoring orientation request.
+ setUpDisplaySizeWithApp(1400, 2800);
+ mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+
+ mActivity.mWmService.mLetterboxConfiguration.setLetterboxVerticalPositionMultiplier(
+ letterboxVerticalPositionMultiplier);
+ prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT);
assertFitted();
@@ -2375,7 +2512,7 @@
assertTrue(mActivity.inSizeCompatMode());
// Activity is in size compat mode but not scaled.
- assertEquals(new Rect(0, 1050, 1400, 1750), mActivity.getBounds());
+ assertEquals(new Rect(1050, 0, 1750, 1400), mActivity.getBounds());
}
private static WindowState addWindowToActivity(ActivityRecord activity) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/SplashScreenExceptionListTest.java b/services/tests/wmtests/src/com/android/server/wm/SplashScreenExceptionListTest.java
index f5d915d..8425844 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SplashScreenExceptionListTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SplashScreenExceptionListTest.java
@@ -90,13 +90,50 @@
public void packageFromDeviceConfigIgnored() {
setExceptionListAndWaitForCallback("com.test.nosplashscreen1,com.test.nosplashscreen2");
- assertIsException("com.test.nosplashscreen1", null);
- assertIsException("com.test.nosplashscreen2", null);
+ // In list, up to T included
+ assertIsException("com.test.nosplashscreen1", VERSION_CODES.R);
+ assertIsException("com.test.nosplashscreen1", VERSION_CODES.S);
+ assertIsException("com.test.nosplashscreen1", VERSION_CODES.TIRAMISU);
- assertIsNotException("com.test.nosplashscreen1", VERSION_CODES.S, null);
- assertIsNotException("com.test.nosplashscreen2", VERSION_CODES.S, null);
- assertIsNotException("com.test.splashscreen", VERSION_CODES.S, null);
- assertIsNotException("com.test.splashscreen", VERSION_CODES.R, null);
+ // In list, after T
+ assertIsNotException("com.test.nosplashscreen2", VERSION_CODES.TIRAMISU + 1);
+ assertIsNotException("com.test.nosplashscreen2", VERSION_CODES.CUR_DEVELOPMENT);
+
+ // Not in list, up to T included
+ assertIsNotException("com.test.splashscreen", VERSION_CODES.S);
+ assertIsNotException("com.test.splashscreen", VERSION_CODES.R);
+ assertIsNotException("com.test.splashscreen", VERSION_CODES.TIRAMISU);
+ }
+
+ @Test
+ public void metaDataOptOut() {
+ String packageName = "com.test.nosplashscreen_opt_out";
+ setExceptionListAndWaitForCallback(packageName);
+
+ Bundle metaData = new Bundle();
+ ApplicationInfo activityInfo = new ApplicationInfo();
+ activityInfo.metaData = metaData;
+
+ // No Exceptions
+ metaData.putBoolean("android.splashscreen.exception_opt_out", true);
+ assertIsNotException(packageName, VERSION_CODES.R, activityInfo);
+ assertIsNotException(packageName, VERSION_CODES.S, activityInfo);
+ assertIsNotException(packageName, VERSION_CODES.TIRAMISU, activityInfo);
+
+ // Exception up to T
+ metaData.putBoolean("android.splashscreen.exception_opt_out", false);
+ assertIsException(packageName, VERSION_CODES.R, activityInfo);
+ assertIsException(packageName, VERSION_CODES.S, activityInfo);
+ assertIsException(packageName, VERSION_CODES.TIRAMISU, activityInfo);
+
+ // No Exception after T
+ assertIsNotException(packageName, VERSION_CODES.TIRAMISU + 1, activityInfo);
+ assertIsNotException(packageName, VERSION_CODES.CUR_DEVELOPMENT, activityInfo);
+
+ // Edge Cases
+ activityInfo.metaData = null;
+ assertIsException(packageName, VERSION_CODES.R, activityInfo);
+ assertIsException(packageName, VERSION_CODES.R);
}
private void setExceptionListAndWaitForCallback(String commaSeparatedList) {
@@ -116,42 +153,25 @@
}
}
- @Test
- public void metaDataOptOut() {
- String packageName = "com.test.nosplashscreen_opt_out";
- setExceptionListAndWaitForCallback(packageName);
-
- Bundle metaData = new Bundle();
- ApplicationInfo activityInfo = new ApplicationInfo();
- activityInfo.metaData = metaData;
-
- // No Exceptions
- metaData.putBoolean("android.splashscreen.exception_opt_out", true);
- assertIsNotException(packageName, VERSION_CODES.R, activityInfo);
- assertIsNotException(packageName, VERSION_CODES.S, activityInfo);
-
- // Exception Pre S
- metaData.putBoolean("android.splashscreen.exception_opt_out", false);
- assertIsException(packageName, activityInfo);
- assertIsNotException(packageName, VERSION_CODES.S, activityInfo);
-
- // Edge Cases
- activityInfo.metaData = null;
- assertIsException(packageName, activityInfo);
- assertIsException(packageName, null);
+ private void assertIsNotException(String packageName, int targetSdk) {
+ assertIsNotException(packageName, targetSdk, null);
}
private void assertIsNotException(String packageName, int targetSdk,
ApplicationInfo activityInfo) {
assertFalse(String.format("%s (sdk=%d) should have not been considered as an exception",
- packageName, targetSdk),
+ packageName, targetSdk),
mList.isException(packageName, targetSdk, () -> activityInfo));
}
+ private void assertIsException(String packageName, int targetSdk) {
+ assertIsException(packageName, targetSdk, null);
+ }
+
private void assertIsException(String packageName,
- ApplicationInfo activityInfo) {
+ int targetSdk, ApplicationInfo activityInfo) {
assertTrue(String.format("%s (sdk=%d) should have been considered as an exception",
- packageName, VERSION_CODES.R),
- mList.isException(packageName, VERSION_CODES.R, () -> activityInfo));
+ packageName, targetSdk),
+ mList.isException(packageName, targetSdk, () -> activityInfo));
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java
index 79ba175..ff0063c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java
@@ -338,6 +338,11 @@
}
@Override
+ public SurfaceControl.Transaction getSyncTransaction() {
+ return mTransaction;
+ }
+
+ @Override
public Transaction getPendingTransaction() {
return mTransaction;
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
index 75b5e73..5340a79 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
@@ -511,11 +511,12 @@
@Test
public void testApplyTransaction_reparentActivityToTaskFragment_triggerLifecycleUpdate()
throws RemoteException {
- final ActivityRecord activity = createActivityRecord(mDefaultDisplay);
+ final Task task = createTask(mDisplayContent);
+ final ActivityRecord activity = createActivityRecord(task);
mOrganizer.applyTransaction(mTransaction);
mController.registerOrganizer(mIOrganizer);
mTaskFragment = new TaskFragmentBuilder(mAtm)
- .setCreateParentTask()
+ .setParentTask(task)
.setFragmentToken(mFragmentToken)
.build();
mAtm.mWindowOrganizerController.mLaunchTaskFragments
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 9304761..44b1d83 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
@@ -31,7 +31,6 @@
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
-import static android.util.DisplayMetrics.DENSITY_DEFAULT;
import static android.view.IWindowManager.FIXED_TO_USER_ROTATION_ENABLED;
import static android.view.Surface.ROTATION_0;
import static android.view.Surface.ROTATION_90;
@@ -497,34 +496,6 @@
assertEquals(reqBounds.height(), task.getBounds().height());
}
- /** Tests that the task bounds adjust properly to changes between FULLSCREEN and FREEFORM */
- @Test
- public void testBoundsOnModeChangeFreeformToFullscreen() {
- DisplayContent display = mAtm.mRootWindowContainer.getDefaultDisplay();
- Task rootTask = new TaskBuilder(mSupervisor).setDisplay(display).setCreateActivity(true)
- .setWindowingMode(WINDOWING_MODE_FREEFORM).build();
- Task task = rootTask.getBottomMostTask();
- task.getRootActivity().setOrientation(SCREEN_ORIENTATION_UNSPECIFIED);
- DisplayInfo info = new DisplayInfo();
- display.mDisplay.getDisplayInfo(info);
- final Rect fullScreenBounds = new Rect(0, 0, info.logicalWidth, info.logicalHeight);
- final Rect freeformBounds = new Rect(fullScreenBounds);
- freeformBounds.inset((int) (freeformBounds.width() * 0.2),
- (int) (freeformBounds.height() * 0.2));
- task.setBounds(freeformBounds);
-
- assertEquals(freeformBounds, task.getBounds());
-
- // FULLSCREEN inherits bounds
- rootTask.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
- assertEquals(fullScreenBounds, task.getBounds());
- assertEquals(freeformBounds, task.mLastNonFullscreenBounds);
-
- // FREEFORM restores bounds
- rootTask.setWindowingMode(WINDOWING_MODE_FREEFORM);
- assertEquals(freeformBounds, task.getBounds());
- }
-
/**
* Tests that a task with forced orientation has orientation-consistent bounds within the
* parent.
@@ -590,6 +561,7 @@
// FULLSCREEN letterboxes bounds on activity level, no constraint on task level.
rootTask.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ rootTask.setBounds(null);
assertThat(task.getBounds().height()).isGreaterThan(task.getBounds().width());
assertThat(top.getBounds().width()).isGreaterThan(top.getBounds().height());
assertEquals(fullScreenBoundsPort, task.getBounds());
@@ -667,8 +639,6 @@
final Task task = new TaskBuilder(mSupervisor).setDisplay(display).build();
final Configuration inOutConfig = new Configuration();
final Configuration parentConfig = new Configuration();
- final int longSide = 1200;
- final int shortSide = 600;
final Rect parentBounds = new Rect(0, 0, 250, 500);
final Rect parentAppBounds = new Rect(0, 0, 250, 480);
parentConfig.windowConfiguration.setBounds(parentBounds);
@@ -689,14 +659,17 @@
// If bounds are overridden, config properties should be made to match. Surface hierarchy
// will crop for policy.
inOutConfig.setToDefaults();
+ final int longSide = 960;
+ final int shortSide = 540;
+ parentConfig.densityDpi = 192;
final Rect largerPortraitBounds = new Rect(0, 0, shortSide, longSide);
inOutConfig.windowConfiguration.setBounds(largerPortraitBounds);
task.computeConfigResourceOverrides(inOutConfig, parentConfig);
// The override bounds are beyond the parent, the out appBounds should not be intersected
// by parent appBounds.
assertEquals(largerPortraitBounds, inOutConfig.windowConfiguration.getAppBounds());
- assertEquals(longSide, inOutConfig.screenHeightDp * parentConfig.densityDpi / 160);
- assertEquals(shortSide, inOutConfig.screenWidthDp * parentConfig.densityDpi / 160);
+ assertEquals(800, inOutConfig.screenHeightDp); // 960/(192/160) = 800
+ assertEquals(450, inOutConfig.screenWidthDp); // 540/(192/160) = 450
inOutConfig.setToDefaults();
// Landscape bounds.
@@ -716,16 +689,17 @@
// Without limiting to be inside the parent bounds, the out screen size should keep relative
// to the input bounds.
final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(task).build();
- final ActivityRecord.CompatDisplayInsets compatIntsets =
+ final ActivityRecord.CompatDisplayInsets compatInsets =
new ActivityRecord.CompatDisplayInsets(
display, activity, /* fixedOrientationBounds= */ null);
- task.computeConfigResourceOverrides(inOutConfig, parentConfig, compatIntsets);
+ task.computeConfigResourceOverrides(inOutConfig, parentConfig, compatInsets);
assertEquals(largerLandscapeBounds, inOutConfig.windowConfiguration.getAppBounds());
- assertEquals((shortSide - statusBarHeight) * DENSITY_DEFAULT / parentConfig.densityDpi,
- inOutConfig.screenHeightDp);
- assertEquals(longSide * DENSITY_DEFAULT / parentConfig.densityDpi,
- inOutConfig.screenWidthDp);
+ final float density = parentConfig.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
+ final int expectedHeightDp = (int) ((shortSide - statusBarHeight) / density + 0.5f);
+ assertEquals(expectedHeightDp, inOutConfig.screenHeightDp);
+ final int expectedWidthDp = (int) (longSide / density + 0.5f);
+ assertEquals(expectedWidthDp, inOutConfig.screenWidthDp);
assertEquals(Configuration.ORIENTATION_LANDSCAPE, inOutConfig.orientation);
}
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 16adffd..d9d819b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
@@ -821,8 +821,11 @@
player.onTransactionReady(mDisplayContent.getSyncTransaction());
final DisplayRotation displayRotation = mDisplayContent.getDisplayRotation();
+ final RemoteDisplayChangeController displayChangeController = mDisplayContent
+ .mRemoteDisplayChangeController;
spyOn(displayRotation);
- doReturn(true).when(displayRotation).isWaitingForRemoteRotation();
+ spyOn(displayChangeController);
+ doReturn(true).when(displayChangeController).isWaitingForRemoteDisplayChange();
doReturn(prevRotation + 1).when(displayRotation).rotationForOrientation(
anyInt() /* orientation */, anyInt() /* lastRotation */);
// Rotation update is skipped while the recents animation is running.
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
index 746f2b5..3abf7ce 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
@@ -21,6 +21,7 @@
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
@@ -39,24 +40,30 @@
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.when;
import android.Manifest;
+import android.app.ActivityManager;
+import android.app.ClientTransactionHandler;
import android.app.IApplicationThread;
+import android.app.servertransaction.ConfigurationChangeItem;
import android.content.ComponentName;
import android.content.pm.ApplicationInfo;
import android.content.pm.ServiceInfo;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.LocaleList;
+import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.InOrder;
import org.mockito.Mockito;
@@ -282,6 +289,39 @@
}
@Test
+ public void testCachedStateConfigurationChange() throws RemoteException {
+ final ClientLifecycleManager clientManager = mAtm.getLifecycleManager();
+ doNothing().when(clientManager).scheduleTransaction(any(), any());
+ final IApplicationThread thread = mWpc.getThread();
+ final Configuration newConfig = new Configuration(mWpc.getConfiguration());
+ newConfig.densityDpi += 100;
+ // Non-cached state will send the change directly.
+ mWpc.setReportedProcState(ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND);
+ clearInvocations(clientManager);
+ mWpc.onConfigurationChanged(newConfig);
+ verify(clientManager).scheduleTransaction(eq(thread), any());
+
+ // Cached state won't send the change.
+ clearInvocations(clientManager);
+ mWpc.setReportedProcState(ActivityManager.PROCESS_STATE_CACHED_ACTIVITY);
+ newConfig.densityDpi += 100;
+ mWpc.onConfigurationChanged(newConfig);
+ verify(clientManager, never()).scheduleTransaction(eq(thread), any());
+
+ // Cached -> non-cached will send the previous deferred config immediately.
+ mWpc.setReportedProcState(ActivityManager.PROCESS_STATE_RECEIVER);
+ final ArgumentCaptor<ConfigurationChangeItem> captor =
+ ArgumentCaptor.forClass(ConfigurationChangeItem.class);
+ verify(clientManager).scheduleTransaction(eq(thread), captor.capture());
+ final ClientTransactionHandler client = mock(ClientTransactionHandler.class);
+ captor.getValue().preExecute(client, null /* token */);
+ final ArgumentCaptor<Configuration> configCaptor =
+ ArgumentCaptor.forClass(Configuration.class);
+ verify(client).updatePendingConfiguration(configCaptor.capture());
+ assertEquals(newConfig, configCaptor.getValue());
+ }
+
+ @Test
public void testComputeOomAdjFromActivities() {
final ActivityRecord activity = createActivityRecord(mWpc);
activity.mVisibleRequested = true;
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 9957d05..e138d52 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -229,14 +229,22 @@
// {@link com.android.internal.R.dimen.config_fixedOrientationLetterboxAspectRatio}, is set
// on some device form factors.
mAtm.mWindowManager.mLetterboxConfiguration.setFixedOrientationLetterboxAspectRatio(0);
- // Ensure letterbox position multiplier is not overridden on any device target.
+ // Ensure letterbox horizontal position multiplier is not overridden on any device target.
// {@link com.android.internal.R.dimen.config_letterboxHorizontalPositionMultiplier},
// may be set on some device form factors.
mAtm.mWindowManager.mLetterboxConfiguration.setLetterboxHorizontalPositionMultiplier(0.5f);
- // Ensure letterbox reachability treatment isn't overridden on any device target.
- // {@link com.android.internal.R.bool.config_letterboxIsReachabilityEnabled},
+ // Ensure letterbox vertical position multiplier is not overridden on any device target.
+ // {@link com.android.internal.R.dimen.config_letterboxHorizontalPositionMultiplier},
// may be set on some device form factors.
- mAtm.mWindowManager.mLetterboxConfiguration.setIsReachabilityEnabled(false);
+ mAtm.mWindowManager.mLetterboxConfiguration.setLetterboxVerticalPositionMultiplier(0.5f);
+ // Ensure letterbox horizontal reachability treatment isn't overridden on any device target.
+ // {@link com.android.internal.R.bool.config_letterboxIsHorizontalReachabilityEnabled},
+ // may be set on some device form factors.
+ mAtm.mWindowManager.mLetterboxConfiguration.setIsHorizontalReachabilityEnabled(false);
+ // Ensure letterbox vertical reachability treatment isn't overridden on any device target.
+ // {@link com.android.internal.R.bool.config_letterboxIsVerticalReachabilityEnabled},
+ // may be set on some device form factors.
+ mAtm.mWindowManager.mLetterboxConfiguration.setIsVerticalReachabilityEnabled(false);
checkDeviceSpecificOverridesNotApplied();
}
@@ -246,7 +254,8 @@
// Revert back to device overrides.
mAtm.mWindowManager.mLetterboxConfiguration.resetFixedOrientationLetterboxAspectRatio();
mAtm.mWindowManager.mLetterboxConfiguration.resetLetterboxHorizontalPositionMultiplier();
- mAtm.mWindowManager.mLetterboxConfiguration.resetIsReachabilityEnabled();
+ mAtm.mWindowManager.mLetterboxConfiguration.resetIsHorizontalReachabilityEnabled();
+ mAtm.mWindowManager.mLetterboxConfiguration.resetIsVerticalReachabilityEnabled();
}
/**
diff --git a/services/usb/java/com/android/server/usb/UsbDirectMidiDevice.java b/services/usb/java/com/android/server/usb/UsbDirectMidiDevice.java
index 177e819..dc96c66 100644
--- a/services/usb/java/com/android/server/usb/UsbDirectMidiDevice.java
+++ b/services/usb/java/com/android/server/usb/UsbDirectMidiDevice.java
@@ -23,6 +23,7 @@
import android.hardware.usb.UsbEndpoint;
import android.hardware.usb.UsbInterface;
import android.hardware.usb.UsbManager;
+import android.hardware.usb.UsbRequest;
import android.media.midi.MidiDeviceInfo;
import android.media.midi.MidiDeviceServer;
import android.media.midi.MidiDeviceStatus;
@@ -44,6 +45,7 @@
import java.io.Closeable;
import java.io.IOException;
+import java.nio.ByteBuffer;
import java.util.ArrayList;
/**
@@ -73,10 +75,10 @@
// event schedulers for each input port of the physical device
private MidiEventScheduler[] mEventSchedulers;
- // Arbitrary number for timeout to not continue sending/receiving number from
- // an inactive device. This number tries to balances the number of cycles and
- // not being permanently stuck.
- private static final int BULK_TRANSFER_TIMEOUT_MILLISECONDS = 100;
+ // Arbitrary number for timeout to not continue sending to
+ // an inactive device. This number tries to balances the number
+ // of cycles and not being permanently stuck.
+ private static final int BULK_TRANSFER_TIMEOUT_MILLISECONDS = 10;
private ArrayList<UsbDeviceConnection> mUsbDeviceConnections;
private ArrayList<ArrayList<UsbEndpoint>> mInputUsbEndpoints;
@@ -87,38 +89,36 @@
private final Object mLock = new Object();
private boolean mIsOpen;
+ private boolean mServerAvailable;
private UsbMidiPacketConverter mUsbMidiPacketConverter;
private final MidiDeviceServer.Callback mCallback = new MidiDeviceServer.Callback() {
-
@Override
public void onDeviceStatusChanged(MidiDeviceServer server, MidiDeviceStatus status) {
MidiDeviceInfo deviceInfo = status.getDeviceInfo();
int numInputPorts = deviceInfo.getInputPortCount();
int numOutputPorts = deviceInfo.getOutputPortCount();
- boolean hasOpenPorts = false;
+ int numOpenPorts = 0;
for (int i = 0; i < numInputPorts; i++) {
if (status.isInputPortOpen(i)) {
- hasOpenPorts = true;
- break;
+ numOpenPorts++;
}
}
- if (!hasOpenPorts) {
- for (int i = 0; i < numOutputPorts; i++) {
- if (status.getOutputPortOpenCount(i) > 0) {
- hasOpenPorts = true;
- break;
- }
+ for (int i = 0; i < numOutputPorts; i++) {
+ if (status.getOutputPortOpenCount(i) > 0) {
+ numOpenPorts += status.getOutputPortOpenCount(i);
}
}
synchronized (mLock) {
- if (hasOpenPorts && !mIsOpen) {
+ Log.d(TAG, "numOpenPorts: " + numOpenPorts + " isOpen: " + mIsOpen
+ + " mServerAvailable: " + mServerAvailable);
+ if ((numOpenPorts > 0) && !mIsOpen && mServerAvailable) {
openLocked();
- } else if (!hasOpenPorts && mIsOpen) {
+ } else if ((numOpenPorts == 0) && mIsOpen) {
closeLocked();
}
}
@@ -330,48 +330,55 @@
new Thread("UsbDirectMidiDevice input thread " + portFinal) {
@Override
public void run() {
- byte[] inputBuffer = new byte[endpointFinal.getMaxPacketSize()];
- Log.d(TAG, "input buffer size: " + inputBuffer.length);
+ final UsbRequest request = new UsbRequest();
try {
+ request.initialize(connectionFinal, endpointFinal);
+ byte[] inputBuffer = new byte[endpointFinal.getMaxPacketSize()];
while (true) {
// Record time of event immediately after waking.
long timestamp = System.nanoTime();
- synchronized (mLock) {
- if (!mIsOpen) break;
+ if (!mIsOpen) break;
+ final ByteBuffer byteBuffer = ByteBuffer.wrap(inputBuffer);
+ if (!request.queue(byteBuffer)) {
+ Log.w(TAG, "Cannot queue request");
+ break;
+ }
+ final UsbRequest response = connectionFinal.requestWait();
+ if (response != request) {
+ Log.w(TAG, "Unexpected response");
+ break;
+ }
+ int bytesRead = byteBuffer.position();
- int nRead = connectionFinal.bulkTransfer(endpointFinal,
- inputBuffer, inputBuffer.length,
- BULK_TRANSFER_TIMEOUT_MILLISECONDS);
-
- if (nRead > 0) {
- if (DEBUG) {
- logByteArray("Input before conversion ", inputBuffer,
- 0, nRead);
- }
- byte[] convertedArray;
- if (mIsUniversalMidiDevice) {
- // For USB, each 32 bit word of a UMP is
- // sent with the least significant byte first.
- convertedArray = swapEndiannessPerWord(inputBuffer,
- nRead);
- } else {
- convertedArray =
- mUsbMidiPacketConverter.usbMidiToRawMidi(
- inputBuffer, nRead);
- }
-
- if (DEBUG) {
- logByteArray("Input after conversion ", convertedArray,
- 0, convertedArray.length);
- }
-
- outputReceivers[portFinal].send(convertedArray, 0,
- convertedArray.length, timestamp);
+ if (bytesRead > 0) {
+ if (DEBUG) {
+ logByteArray("Input before conversion ", inputBuffer,
+ 0, bytesRead);
}
+ byte[] convertedArray;
+ if (mIsUniversalMidiDevice) {
+ // For USB, each 32 bit word of a UMP is
+ // sent with the least significant byte first.
+ convertedArray = swapEndiannessPerWord(inputBuffer,
+ bytesRead);
+ } else {
+ convertedArray =
+ mUsbMidiPacketConverter.usbMidiToRawMidi(
+ inputBuffer, bytesRead);
+ }
+
+ if (DEBUG) {
+ logByteArray("Input after conversion ", convertedArray,
+ 0, convertedArray.length);
+ }
+ outputReceivers[portFinal].send(convertedArray, 0,
+ convertedArray.length, timestamp);
}
}
} catch (IOException e) {
Log.d(TAG, "reader thread exiting");
+ } finally {
+ request.close();
}
Log.d(TAG, "input thread exit");
}
@@ -453,7 +460,7 @@
mContext = context;
MidiManager midiManager = context.getSystemService(MidiManager.class);
if (midiManager == null) {
- Log.e(TAG, "No MidiManager in UsbDirectMidiDevice.create()");
+ Log.e(TAG, "No MidiManager in UsbDirectMidiDevice.register()");
return false;
}
@@ -490,6 +497,7 @@
mUsbDevice.getSerialNumber());
properties.putParcelable(MidiDeviceInfo.PROPERTY_USB_DEVICE, mUsbDevice);
+ mServerAvailable = true;
mServer = midiManager.createDeviceServer(mMidiInputPortReceivers, mNumInputs,
null, null, properties, MidiDeviceInfo.TYPE_USB, mDefaultMidiProtocol, mCallback);
if (mServer == null) {
@@ -505,6 +513,7 @@
if (mIsOpen) {
closeLocked();
}
+ mServerAvailable = false;
}
if (mServer != null) {
@@ -564,6 +573,10 @@
Log.e(TAG, "Usb Interface is null");
return false;
}
+ if (connection == null) {
+ Log.e(TAG, "UsbDeviceConnection is null");
+ return false;
+ }
if (!connection.claimInterface(usbInterface, true)) {
Log.e(TAG, "Can't claim interface");
return false;
diff --git a/services/usb/java/com/android/server/usb/UsbMidiDevice.java b/services/usb/java/com/android/server/usb/UsbMidiDevice.java
index 275f217..67955e1 100644
--- a/services/usb/java/com/android/server/usb/UsbMidiDevice.java
+++ b/services/usb/java/com/android/server/usb/UsbMidiDevice.java
@@ -71,40 +71,38 @@
private final Object mLock = new Object();
private boolean mIsOpen;
+ private boolean mServerAvailable;
// pipe file descriptor for signalling input thread to exit
// only accessed from JNI code
private int mPipeFD = -1;
private final MidiDeviceServer.Callback mCallback = new MidiDeviceServer.Callback() {
-
@Override
public void onDeviceStatusChanged(MidiDeviceServer server, MidiDeviceStatus status) {
MidiDeviceInfo deviceInfo = status.getDeviceInfo();
- int inputPorts = deviceInfo.getInputPortCount();
- int outputPorts = deviceInfo.getOutputPortCount();
- boolean hasOpenPorts = false;
+ int numInputPorts = deviceInfo.getInputPortCount();
+ int numOutputPorts = deviceInfo.getOutputPortCount();
+ int numOpenPorts = 0;
- for (int i = 0; i < inputPorts; i++) {
+ for (int i = 0; i < numInputPorts; i++) {
if (status.isInputPortOpen(i)) {
- hasOpenPorts = true;
- break;
+ numOpenPorts++;
}
}
- if (!hasOpenPorts) {
- for (int i = 0; i < outputPorts; i++) {
- if (status.getOutputPortOpenCount(i) > 0) {
- hasOpenPorts = true;
- break;
- }
+ for (int i = 0; i < numOutputPorts; i++) {
+ if (status.getOutputPortOpenCount(i) > 0) {
+ numOpenPorts += status.getOutputPortOpenCount(i);
}
}
synchronized (mLock) {
- if (hasOpenPorts && !mIsOpen) {
+ Log.d(TAG, "numOpenPorts: " + numOpenPorts + " isOpen: " + mIsOpen
+ + " mServerAvailable: " + mServerAvailable);
+ if ((numOpenPorts > 0) && !mIsOpen && mServerAvailable) {
openLocked();
- } else if (!hasOpenPorts && mIsOpen) {
+ } else if ((numOpenPorts == 0) && mIsOpen) {
closeLocked();
}
}
@@ -298,10 +296,11 @@
private boolean register(Context context, Bundle properties) {
MidiManager midiManager = (MidiManager)context.getSystemService(Context.MIDI_SERVICE);
if (midiManager == null) {
- Log.e(TAG, "No MidiManager in UsbMidiDevice.create()");
+ Log.e(TAG, "No MidiManager in UsbMidiDevice.register()");
return false;
}
+ mServerAvailable = true;
mServer = midiManager.createDeviceServer(mMidiInputPortReceivers, mNumInputs,
null, null, properties, MidiDeviceInfo.TYPE_USB,
MidiDeviceInfo.PROTOCOL_UNKNOWN, mCallback);
@@ -318,6 +317,7 @@
if (mIsOpen) {
closeLocked();
}
+ mServerAvailable = false;
}
if (mServer != null) {
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
index 99fcbc7..f5b5e1a 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
@@ -125,6 +125,10 @@
private static final long RESET_DEBUG_HOTWORD_LOGGING_TIMEOUT_MILLIS = 60 * 60 * 1000; // 1 hour
private static final int MAX_ISOLATED_PROCESS_NUMBER = 10;
+ // The error codes are used for onError callback
+ private static final int HOTWORD_DETECTION_SERVICE_DIED = -1;
+ private static final int CALLBACK_ONDETECTED_GOT_SECURITY_EXCEPTION = -2;
+
// Hotword metrics
private static final int METRICS_INIT_UNKNOWN_TIMEOUT =
HOTWORD_DETECTION_SERVICE_INIT_RESULT_REPORTED__RESULT__CALLBACK_INIT_STATE_UNKNOWN_TIMEOUT;
@@ -421,19 +425,24 @@
Slog.d(TAG, "onDetected");
}
synchronized (mLock) {
- if (mPerformingSoftwareHotwordDetection) {
- enforcePermissionsForDataDelivery();
- mSoftwareCallback.onDetected(result, null, null);
- mPerformingSoftwareHotwordDetection = false;
- if (result != null) {
- Slog.i(TAG, "Egressed " + HotwordDetectedResult.getUsageSize(result)
- + " bits from hotword trusted process");
- if (mDebugHotwordLogging) {
- Slog.i(TAG, "Egressed detected result: " + result);
- }
- }
- } else {
+ if (!mPerformingSoftwareHotwordDetection) {
Slog.i(TAG, "Hotword detection has already completed");
+ return;
+ }
+ mPerformingSoftwareHotwordDetection = false;
+ try {
+ enforcePermissionsForDataDelivery();
+ } catch (SecurityException e) {
+ mSoftwareCallback.onError();
+ return;
+ }
+ mSoftwareCallback.onDetected(result, null, null);
+ if (result != null) {
+ Slog.i(TAG, "Egressed " + HotwordDetectedResult.getUsageSize(result)
+ + " bits from hotword trusted process");
+ if (mDebugHotwordLogging) {
+ Slog.i(TAG, "Egressed detected result: " + result);
+ }
}
}
}
@@ -514,20 +523,25 @@
public void onDetected(HotwordDetectedResult result) throws RemoteException {
Slog.v(TAG, "onDetected");
synchronized (mLock) {
- if (mValidatingDspTrigger) {
- mValidatingDspTrigger = false;
+ if (!mValidatingDspTrigger) {
+ Slog.i(TAG, "Ignored hotword detected since trigger has been handled");
+ return;
+ }
+ mValidatingDspTrigger = false;
+ try {
enforcePermissionsForDataDelivery();
enforceExtraKeyphraseIdNotLeaked(result, recognitionEvent);
- externalCallback.onKeyphraseDetected(recognitionEvent, result);
- if (result != null) {
- Slog.i(TAG, "Egressed " + HotwordDetectedResult.getUsageSize(result)
- + " bits from hotword trusted process");
- if (mDebugHotwordLogging) {
- Slog.i(TAG, "Egressed detected result: " + result);
- }
+ } catch (SecurityException e) {
+ externalCallback.onError(CALLBACK_ONDETECTED_GOT_SECURITY_EXCEPTION);
+ return;
+ }
+ externalCallback.onKeyphraseDetected(recognitionEvent, result);
+ if (result != null) {
+ Slog.i(TAG, "Egressed " + HotwordDetectedResult.getUsageSize(result)
+ + " bits from hotword trusted process");
+ if (mDebugHotwordLogging) {
+ Slog.i(TAG, "Egressed detected result: " + result);
}
- } else {
- Slog.i(TAG, "Ignored hotword detected since trigger has been handled");
}
}
}
@@ -598,7 +612,8 @@
HotwordMetricsLogger.writeKeyphraseTriggerEvent(
mDetectorType,
METRICS_KEYPHRASE_TRIGGERED_DETECT_SECURITY_EXCEPTION);
- throw e;
+ externalCallback.onError(CALLBACK_ONDETECTED_GOT_SECURITY_EXCEPTION);
+ return;
}
externalCallback.onKeyphraseDetected(recognitionEvent, result);
if (result != null) {
@@ -888,7 +903,13 @@
throws RemoteException {
bestEffortClose(serviceAudioSink);
bestEffortClose(serviceAudioSource);
- enforcePermissionsForDataDelivery();
+ try {
+ enforcePermissionsForDataDelivery();
+ } catch (SecurityException e) {
+ bestEffortClose(audioSource);
+ callback.onError();
+ return;
+ }
callback.onDetected(triggerResult, null /* audioFormat */,
null /* audioStream */);
if (triggerResult != null) {
@@ -988,7 +1009,7 @@
Slog.w(TAG, "binderDied");
try {
- mCallback.onError(-1);
+ mCallback.onError(HOTWORD_DETECTION_SERVICE_DIED);
} catch (RemoteException e) {
Slog.w(TAG, "Failed to report onError status: " + e);
}
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 980ea5c..432af3a 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -2895,7 +2895,19 @@
if (key != null) {
final Object value = bundle.get(key);
final Object newValue = newBundle.get(key);
- if (!Objects.equals(value, newValue)) {
+ if (!newBundle.containsKey(key)) {
+ return false;
+ }
+ if (value instanceof Bundle && newValue instanceof Bundle) {
+ if (!areBundlesEqual((Bundle) value, (Bundle) newValue)) {
+ return false;
+ }
+ }
+ if (value instanceof byte[] && newValue instanceof byte[]) {
+ if (!Arrays.equals((byte[]) value, (byte[]) newValue)) {
+ return false;
+ }
+ } else if (!Objects.equals(value, newValue)) {
return false;
}
}
diff --git a/telephony/common/android/telephony/LocationAccessPolicy.java b/telephony/common/android/telephony/LocationAccessPolicy.java
index 85d59a2..d4b6c91 100644
--- a/telephony/common/android/telephony/LocationAccessPolicy.java
+++ b/telephony/common/android/telephony/LocationAccessPolicy.java
@@ -316,9 +316,11 @@
return LocationPermissionResult.ALLOWED;
}
- // Check the system-wide requirements. If the location main switch is off or
- // the app's profile isn't in foreground, return a soft denial.
- if (!checkSystemLocationAccess(context, query.callingUid, query.callingPid)) {
+ // Check the system-wide requirements. If the location main switch is off and the caller is
+ // not in the allowlist of apps that always have loation access or the app's profile
+ // isn't in the foreground, return a soft denial.
+ if (!checkSystemLocationAccess(context, query.callingUid, query.callingPid,
+ query.callingPackage)) {
return LocationPermissionResult.DENIED_SOFT;
}
@@ -344,15 +346,16 @@
return LocationPermissionResult.ALLOWED;
}
-
private static boolean checkManifestPermission(Context context, int pid, int uid,
String permissionToCheck) {
return context.checkPermission(permissionToCheck, pid, uid)
== PackageManager.PERMISSION_GRANTED;
}
- private static boolean checkSystemLocationAccess(@NonNull Context context, int uid, int pid) {
- if (!isLocationModeEnabled(context, UserHandle.getUserHandleForUid(uid).getIdentifier())) {
+ private static boolean checkSystemLocationAccess(@NonNull Context context, int uid, int pid,
+ @NonNull String callingPackage) {
+ if (!isLocationModeEnabled(context, UserHandle.getUserHandleForUid(uid).getIdentifier())
+ && !isLocationBypassAllowed(context, callingPackage)) {
if (DBG) Log.w(TAG, "Location disabled, failed, (" + uid + ")");
return false;
}
@@ -361,7 +364,10 @@
return isCurrentProfile(context, uid) || checkInteractAcrossUsersFull(context, pid, uid);
}
- private static boolean isLocationModeEnabled(@NonNull Context context, @UserIdInt int userId) {
+ /**
+ * @return Whether location is enabled for the given user.
+ */
+ public static boolean isLocationModeEnabled(@NonNull Context context, @UserIdInt int userId) {
LocationManager locationManager = context.getSystemService(LocationManager.class);
if (locationManager == null) {
Log.w(TAG, "Couldn't get location manager, denying location access");
@@ -370,6 +376,24 @@
return locationManager.isLocationEnabledForUser(UserHandle.of(userId));
}
+ private static boolean isLocationBypassAllowed(@NonNull Context context,
+ @NonNull String callingPackage) {
+ for (String bypassPackage : getLocationBypassPackages(context)) {
+ if (callingPackage.equals(bypassPackage)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @return An array of packages that are always allowed to access location.
+ */
+ public static @NonNull String[] getLocationBypassPackages(@NonNull Context context) {
+ return context.getResources().getStringArray(
+ com.android.internal.R.array.config_serviceStateLocationAllowedPackages);
+ }
+
private static boolean checkInteractAcrossUsersFull(
@NonNull Context context, int pid, int uid) {
return checkManifestPermission(context, pid, uid,
diff --git a/telephony/common/com/android/internal/telephony/CellBroadcastUtils.java b/telephony/common/com/android/internal/telephony/CellBroadcastUtils.java
index 6c63755..6181329 100644
--- a/telephony/common/com/android/internal/telephony/CellBroadcastUtils.java
+++ b/telephony/common/com/android/internal/telephony/CellBroadcastUtils.java
@@ -16,6 +16,7 @@
package com.android.internal.telephony;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
@@ -62,4 +63,17 @@
return packageName;
}
+
+ /**
+ * Utility method to get cellbroadcast alert dialog component name
+ */
+ public static ComponentName getDefaultCellBroadcastAlertDialogComponent(Context context) {
+ String cellBroadcastReceiverPackageName =
+ getDefaultCellBroadcastReceiverPackageName(context);
+ if (TextUtils.isEmpty(cellBroadcastReceiverPackageName)) {
+ return null;
+ }
+ return ComponentName.createRelative(cellBroadcastReceiverPackageName,
+ "com.android.cellbroadcastreceiver.CellBroadcastAlertDialog");
+ }
}
diff --git a/telephony/common/com/android/internal/telephony/SmsApplication.java b/telephony/common/com/android/internal/telephony/SmsApplication.java
index 78b0b84..4924a82 100644
--- a/telephony/common/com/android/internal/telephony/SmsApplication.java
+++ b/telephony/common/com/android/internal/telephony/SmsApplication.java
@@ -68,7 +68,6 @@
public final class SmsApplication {
static final String LOG_TAG = "SmsApplication";
public static final String PHONE_PACKAGE_NAME = "com.android.phone";
- public static final String BLUETOOTH_PACKAGE_NAME = "com.android.bluetooth.services";
public static final String MMS_SERVICE_PACKAGE_NAME = "com.android.mms.service";
public static final String TELEPHONY_PROVIDER_PACKAGE_NAME = "com.android.providers.telephony";
@@ -541,11 +540,13 @@
PackageManager packageManager = context.getPackageManager();
AppOpsManager appOps = context.getSystemService(AppOpsManager.class);
+ final String bluetoothPackageName = context.getResources()
+ .getString(com.android.internal.R.string.config_systemBluetoothStack);
// Assign permission to special system apps
assignExclusiveSmsPermissionsToSystemApp(context, packageManager, appOps,
PHONE_PACKAGE_NAME, true);
assignExclusiveSmsPermissionsToSystemApp(context, packageManager, appOps,
- BLUETOOTH_PACKAGE_NAME, true);
+ bluetoothPackageName, false);
assignExclusiveSmsPermissionsToSystemApp(context, packageManager, appOps,
MMS_SERVICE_PACKAGE_NAME, true);
assignExclusiveSmsPermissionsToSystemApp(context, packageManager, appOps,
@@ -1128,8 +1129,11 @@
return false;
}
final String defaultSmsPackage = getDefaultSmsApplicationPackageName(context);
+ final String bluetoothPackageName = context.getResources()
+ .getString(com.android.internal.R.string.config_systemBluetoothStack);
+
if ((defaultSmsPackage != null && defaultSmsPackage.equals(packageName))
- || BLUETOOTH_PACKAGE_NAME.equals(packageName)) {
+ || bluetoothPackageName.equals(packageName)) {
return true;
}
return false;
diff --git a/telephony/java/android/telephony/NetworkRegistrationInfo.java b/telephony/java/android/telephony/NetworkRegistrationInfo.java
index c701e44..1d6798b 100644
--- a/telephony/java/android/telephony/NetworkRegistrationInfo.java
+++ b/telephony/java/android/telephony/NetworkRegistrationInfo.java
@@ -183,8 +183,17 @@
@TransportType
private final int mTransportType;
+ /**
+ * The initial registration state
+ */
@RegistrationState
- private final int mRegistrationState;
+ private final int mInitialRegistrationState;
+
+ /**
+ * The registration state that might have been overridden by config
+ */
+ @RegistrationState
+ private int mRegistrationState;
/**
* Save the {@link ServiceState.RoamingType roaming type}. it can be overridden roaming type
@@ -255,6 +264,7 @@
mDomain = domain;
mTransportType = transportType;
mRegistrationState = registrationState;
+ mInitialRegistrationState = registrationState;
mRoamingType = (registrationState == REGISTRATION_STATE_ROAMING)
? ServiceState.ROAMING_TYPE_UNKNOWN : ServiceState.ROAMING_TYPE_NOT_ROAMING;
setAccessNetworkTechnology(accessNetworkTechnology);
@@ -310,6 +320,7 @@
mDomain = source.readInt();
mTransportType = source.readInt();
mRegistrationState = source.readInt();
+ mInitialRegistrationState = source.readInt();
mRoamingType = source.readInt();
mAccessNetworkTechnology = source.readInt();
mRejectCause = source.readInt();
@@ -336,6 +347,7 @@
mDomain = nri.mDomain;
mTransportType = nri.mTransportType;
mRegistrationState = nri.mRegistrationState;
+ mInitialRegistrationState = nri.mInitialRegistrationState;
mRoamingType = nri.mRoamingType;
mAccessNetworkTechnology = nri.mAccessNetworkTechnology;
mIsUsingCarrierAggregation = nri.mIsUsingCarrierAggregation;
@@ -398,6 +410,15 @@
}
/**
+ * @return The initial registration state.
+ *
+ * @hide
+ */
+ public @RegistrationState int getInitialRegistrationState() {
+ return mInitialRegistrationState;
+ }
+
+ /**
* @return {@code true} if registered on roaming or home network, {@code false} otherwise.
*/
public boolean isRegistered() {
@@ -451,6 +472,17 @@
*/
public void setRoamingType(@ServiceState.RoamingType int roamingType) {
mRoamingType = roamingType;
+
+ // make sure mRegistrationState to be consistent in case of any roaming type override
+ if (isRoaming()) {
+ if (mRegistrationState == REGISTRATION_STATE_HOME) {
+ mRegistrationState = REGISTRATION_STATE_ROAMING;
+ }
+ } else {
+ if (mRegistrationState == REGISTRATION_STATE_ROAMING) {
+ mRegistrationState = REGISTRATION_STATE_HOME;
+ }
+ }
}
/**
@@ -634,6 +666,8 @@
.append(" transportType=").append(
AccessNetworkConstants.transportTypeToString(mTransportType))
.append(" registrationState=").append(registrationStateToString(mRegistrationState))
+ .append(" mInitialRegistrationState=")
+ .append(registrationStateToString(mInitialRegistrationState))
.append(" roamingType=").append(ServiceState.roamingTypeToString(mRoamingType))
.append(" accessNetworkTechnology=")
.append(TelephonyManager.getNetworkTypeName(mAccessNetworkTechnology))
@@ -654,10 +688,10 @@
@Override
public int hashCode() {
- return Objects.hash(mDomain, mTransportType, mRegistrationState, mRoamingType,
- mAccessNetworkTechnology, mRejectCause, mEmergencyOnly, mAvailableServices,
- mCellIdentity, mVoiceSpecificInfo, mDataSpecificInfo, mNrState, mRplmn,
- mIsUsingCarrierAggregation);
+ return Objects.hash(mDomain, mTransportType, mRegistrationState, mInitialRegistrationState,
+ mRoamingType, mAccessNetworkTechnology, mRejectCause, mEmergencyOnly,
+ mAvailableServices, mCellIdentity, mVoiceSpecificInfo, mDataSpecificInfo, mNrState,
+ mRplmn, mIsUsingCarrierAggregation);
}
@Override
@@ -672,6 +706,7 @@
return mDomain == other.mDomain
&& mTransportType == other.mTransportType
&& mRegistrationState == other.mRegistrationState
+ && mInitialRegistrationState == other.mInitialRegistrationState
&& mRoamingType == other.mRoamingType
&& mAccessNetworkTechnology == other.mAccessNetworkTechnology
&& mRejectCause == other.mRejectCause
@@ -694,6 +729,7 @@
dest.writeInt(mDomain);
dest.writeInt(mTransportType);
dest.writeInt(mRegistrationState);
+ dest.writeInt(mInitialRegistrationState);
dest.writeInt(mRoamingType);
dest.writeInt(mAccessNetworkTechnology);
dest.writeInt(mRejectCause);
@@ -790,7 +826,7 @@
private int mTransportType;
@RegistrationState
- private int mRegistrationState;
+ private int mInitialRegistrationState;
@NetworkType
private int mAccessNetworkTechnology;
@@ -851,7 +887,7 @@
* @return The same instance of the builder.
*/
public @NonNull Builder setRegistrationState(@RegistrationState int registrationState) {
- mRegistrationState = registrationState;
+ mInitialRegistrationState = registrationState;
return this;
}
@@ -970,7 +1006,7 @@
*/
@SystemApi
public @NonNull NetworkRegistrationInfo build() {
- return new NetworkRegistrationInfo(mDomain, mTransportType, mRegistrationState,
+ return new NetworkRegistrationInfo(mDomain, mTransportType, mInitialRegistrationState,
mAccessNetworkTechnology, mRejectCause, mEmergencyOnly, mAvailableServices,
mCellIdentity, mRplmn, mVoiceSpecificRegistrationInfo,
mDataSpecificRegistrationInfo);
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index d07d809..2337a5a 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -3426,10 +3426,21 @@
* Get subscriptionInfo list of subscriptions that are in the same group of given subId.
* See {@link #createSubscriptionGroup(List)} for more details.
*
- * Caller will either have {@link android.Manifest.permission#READ_PHONE_STATE}
- * permission or had carrier privilege permission on the subscription.
+ * Caller must have {@link android.Manifest.permission#READ_PHONE_STATE}
+ * or carrier privilege permission on the subscription.
* {@link TelephonyManager#hasCarrierPrivileges()}
*
+ * <p>Starting with API level 33, the caller needs the additional permission
+ * {@link Manifest.permission#USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER}
+ * to get the list of subscriptions associated with a group UUID.
+ * This method can be invoked if one of the following requirements is met:
+ * <ul>
+ * <li>If the app has carrier privilege permission.
+ * {@link TelephonyManager#hasCarrierPrivileges()}
+ * <li>If the app has {@link android.Manifest.permission#READ_PHONE_STATE} and
+ * {@link Manifest.permission#USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER} permission.
+ * </ul>
+ *
* @throws IllegalStateException if Telephony service is in bad state.
* @throws SecurityException if the caller doesn't meet the requirements
* outlined above.
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 652be61..d1729f8 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -8244,6 +8244,30 @@
public static final int AUTHTYPE_EAP_SIM = PhoneConstants.AUTH_CONTEXT_EAP_SIM;
/** Authentication type for UICC challenge is EAP AKA. See RFC 4187 for details. */
public static final int AUTHTYPE_EAP_AKA = PhoneConstants.AUTH_CONTEXT_EAP_AKA;
+ /**
+ * Authentication type for GBA Bootstrap Challenge is GBA_BOOTSTRAP.
+ * See 3GPP 33.220 Section 5.3.2.
+ * @hide
+ */
+ public static final int AUTHTYPE_GBA_BOOTSTRAP = PhoneConstants.AUTH_CONTEXT_GBA_BOOTSTRAP;
+ /**
+ * Authentication type for GBA Network Application Functions (NAF) key
+ * External Challenge is AUTHTYPE_GBA_NAF_KEY_EXTERNAL.
+ * See 3GPP 33.220 Section 5.3.2.
+ * @hide
+ */
+ public static final int AUTHTYPE_GBA_NAF_KEY_EXTERNAL =
+ PhoneConstants.AUTHTYPE_GBA_NAF_KEY_EXTERNAL;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({
+ AUTHTYPE_EAP_SIM,
+ AUTHTYPE_EAP_AKA,
+ AUTHTYPE_GBA_BOOTSTRAP,
+ AUTHTYPE_GBA_NAF_KEY_EXTERNAL
+ })
+ public @interface AuthType {}
/**
* Returns the response of authentication for the default subscription.
@@ -8258,7 +8282,7 @@
* </ul>
*
* @param appType the icc application type, like {@link #APPTYPE_USIM}
- * @param authType the authentication type, {@link #AUTHTYPE_EAP_AKA} or
+ * @param authType the authentication type, any one of {@link #AUTHTYPE_EAP_AKA} or
* {@link #AUTHTYPE_EAP_SIM}
* @param data authentication challenge data, base64 encoded.
* See 3GPP TS 31.102 7.1.2 for more details.
@@ -8273,7 +8297,7 @@
// READ_PRIVILEGED_PHONE_STATE. It certainly shouldn't reference the permission in Javadoc since
// it's not public API.
@RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
- public String getIccAuthentication(int appType, int authType, String data) {
+ public String getIccAuthentication(int appType,@AuthType int authType, String data) {
return getIccAuthentication(getSubId(), appType, authType, data);
}
@@ -8286,7 +8310,7 @@
*
* @param subId subscription ID used for authentication
* @param appType the icc application type, like {@link #APPTYPE_USIM}
- * @param authType the authentication type, {@link #AUTHTYPE_EAP_AKA} or
+ * @param authType the authentication type, any one of {@link #AUTHTYPE_EAP_AKA} or
* {@link #AUTHTYPE_EAP_SIM}
* @param data authentication challenge data, base64 encoded.
* See 3GPP TS 31.102 7.1.2 for more details.
@@ -8300,7 +8324,7 @@
* @hide
*/
@UnsupportedAppUsage
- public String getIccAuthentication(int subId, int appType, int authType, String data) {
+ public String getIccAuthentication(int subId, int appType,@AuthType int authType, String data) {
try {
IPhoneSubInfo info = getSubscriberInfoService();
if (info == null)
@@ -17008,4 +17032,41 @@
}
mTelephonyRegistryMgr.removeCarrierPrivilegesCallback(callback);
}
+
+ /**
+ * set removable eSIM as default eUICC.
+ *
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
+ @RequiresFeature(PackageManager.FEATURE_TELEPHONY_EUICC)
+ public void setRemovableEsimAsDefaultEuicc(boolean isDefault) {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ telephony.setRemovableEsimAsDefaultEuicc(isDefault, getOpPackageName());
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error in setRemovableEsimAsDefault: " + e);
+ }
+ }
+
+ /**
+ * Returns whether the removable eSIM is default eUICC or not.
+ *
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ @RequiresFeature(PackageManager.FEATURE_TELEPHONY_EUICC)
+ public boolean isRemovableEsimDefaultEuicc() {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ return telephony.isRemovableEsimDefaultEuicc(getOpPackageName());
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error in isRemovableEsimDefaultEuicc: " + e);
+ }
+ return false;
+ }
}
diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java
index eede9dc..a673807 100644
--- a/telephony/java/android/telephony/euicc/EuiccManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccManager.java
@@ -25,18 +25,17 @@
import android.annotation.SystemApi;
import android.app.Activity;
import android.app.PendingIntent;
-import android.app.compat.CompatChanges;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledSince;
import android.content.Context;
import android.content.Intent;
import android.content.IntentSender;
import android.content.pm.PackageManager;
-import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.RemoteException;
import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
import android.telephony.TelephonyFrameworkInitializer;
import android.telephony.TelephonyManager;
import android.telephony.UiccCardInfo;
@@ -1209,18 +1208,16 @@
return;
}
try {
- // TODO: Uncomment below compat change code once callers are ported to use
- // switchToSubscription with portIndex for disable operation.
- // if (subscriptionId == SubscriptionManager.INVALID_SUBSCRIPTION_ID
- // && getIEuiccController().isCompatChangeEnabled(mContext.getOpPackageName(),
- // SWITCH_WITHOUT_PORT_INDEX_EXCEPTION_ON_DISABLE)) {
- // // Apps targeting on Android T and beyond will get exception whenever
- // // switchToSubscription without portIndex is called with INVALID_SUBSCRIPTION_ID.
- // Log.e(TAG, "switchToSubscription without portIndex is not allowed for"
- // + " disable operation");
- // throw new IllegalArgumentException("Must use switchToSubscription with portIndex"
- // + " API for disable operation");
- // }
+ if (subscriptionId == SubscriptionManager.INVALID_SUBSCRIPTION_ID
+ && getIEuiccController().isCompatChangeEnabled(mContext.getOpPackageName(),
+ SWITCH_WITHOUT_PORT_INDEX_EXCEPTION_ON_DISABLE)) {
+ // Apps targeting on Android T and beyond will get exception whenever
+ // switchToSubscription without portIndex is called with INVALID_SUBSCRIPTION_ID.
+ Log.e(TAG, "switchToSubscription without portIndex is not allowed for"
+ + " disable operation");
+ throw new IllegalArgumentException("Must use switchToSubscription with portIndex"
+ + " API for disable operation");
+ }
getIEuiccController().switchToSubscription(mCardId,
subscriptionId, mContext.getOpPackageName(), callbackIntent);
} catch (RemoteException e) {
diff --git a/telephony/java/android/telephony/ims/feature/RcsFeature.java b/telephony/java/android/telephony/ims/feature/RcsFeature.java
index 843827b..1862412 100644
--- a/telephony/java/android/telephony/ims/feature/RcsFeature.java
+++ b/telephony/java/android/telephony/ims/feature/RcsFeature.java
@@ -118,8 +118,10 @@
@Override
public void setCapabilityExchangeEventListener(
@Nullable ICapabilityExchangeEventListener listener) throws RemoteException {
- CapabilityExchangeEventListener listenerWrapper =
- new CapabilityExchangeAidlWrapper(listener);
+ // Set the listener wrapper to null if the listener passed in is null. This will notify
+ // the RcsFeature to trigger the destruction of active capability exchange interface.
+ CapabilityExchangeEventListener listenerWrapper = listener != null
+ ? new CapabilityExchangeAidlWrapper(listener) : null;
executeMethodAsync(() -> mReference.setCapabilityExchangeEventListener(listenerWrapper),
"setCapabilityExchangeEventListener");
}
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 7d116f9..0ce6b14 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -2553,4 +2553,18 @@
* for the slot, or {@code null} if none is resolved
*/
String getCarrierServicePackageNameForLogicalSlot(int logicalSlotIndex);
+
+ /**
+ * set removable eSIM as default eUICC.
+ *
+ * @hide
+ */
+ void setRemovableEsimAsDefaultEuicc(boolean isDefault, String callingPackage);
+
+ /**
+ * Returns whether the removable eSIM is default eUICC or not.
+ *
+ * @hide
+ */
+ boolean isRemovableEsimDefaultEuicc(String callingPackage);
}
diff --git a/telephony/java/com/android/internal/telephony/PhoneConstants.java b/telephony/java/com/android/internal/telephony/PhoneConstants.java
index 813e80e..b2f7be6 100644
--- a/telephony/java/com/android/internal/telephony/PhoneConstants.java
+++ b/telephony/java/com/android/internal/telephony/PhoneConstants.java
@@ -226,6 +226,8 @@
// per 3GPP TS 31.102 (Section 7.1.2)
public static final int AUTH_CONTEXT_EAP_SIM = 128;
public static final int AUTH_CONTEXT_EAP_AKA = 129;
+ public static final int AUTH_CONTEXT_GBA_BOOTSTRAP = 132;
+ public static final int AUTHTYPE_GBA_NAF_KEY_EXTERNAL = 133;
public static final int AUTH_CONTEXT_UNDEFINED = -1;
/**
diff --git a/tests/ApkVerityTest/AndroidTest.xml b/tests/ApkVerityTest/AndroidTest.xml
index 55704ed..3c8e1ed 100644
--- a/tests/ApkVerityTest/AndroidTest.xml
+++ b/tests/ApkVerityTest/AndroidTest.xml
@@ -35,6 +35,8 @@
<option name="push" value="ApkVerityTestCert.der->/data/local/tmp/ApkVerityTestCert.der" />
</target_preparer>
+ <!-- Skip on HWASan. TODO(b/232288278): Re-enable -->
+ <object type="module_controller" class="com.android.tradefed.testtype.suite.module.SkipHWASanModuleController" />
<test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
<option name="jar" value="ApkVerityTest.jar" />
</test>
diff --git a/tests/TelephonyCommonTests/src/com/android/internal/telephony/tests/SmsApplicationTest.java b/tests/TelephonyCommonTests/src/com/android/internal/telephony/tests/SmsApplicationTest.java
index 7ee19fb..052ce3a 100644
--- a/tests/TelephonyCommonTests/src/com/android/internal/telephony/tests/SmsApplicationTest.java
+++ b/tests/TelephonyCommonTests/src/com/android/internal/telephony/tests/SmsApplicationTest.java
@@ -22,6 +22,7 @@
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNotNull;
import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.ArgumentMatchers.matches;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doAnswer;
@@ -214,7 +215,7 @@
ApplicationInfo bluetoothApplicationInfo = new ApplicationInfo();
bluetoothApplicationInfo.uid = FAKE_BT_UID;
bluetoothPackageInfo.applicationInfo = bluetoothApplicationInfo;
- when(mPackageManager.getPackageInfo(eq(SmsApplication.BLUETOOTH_PACKAGE_NAME), anyInt()))
+ when(mPackageManager.getPackageInfo(matches(".*android.bluetooth.services"), anyInt()))
.thenReturn(bluetoothPackageInfo);
PackageInfo telephonyProviderPackageInfo = new PackageInfo();
diff --git a/tools/processors/intdef_mappings/Android.bp b/tools/processors/intdef_mappings/Android.bp
index 82a5dac..7059c52 100644
--- a/tools/processors/intdef_mappings/Android.bp
+++ b/tools/processors/intdef_mappings/Android.bp
@@ -7,18 +7,24 @@
default_applicable_licenses: ["frameworks_base_license"],
}
+java_library_host {
+ name: "libintdef-annotation-processor",
+
+ srcs: [
+ ":framework-annotations",
+ "src/**/*.java",
+ "src/**/*.kt",
+ ],
+
+ use_tools_jar: true,
+}
+
java_plugin {
name: "intdef-annotation-processor",
processor_class: "android.processor.IntDefProcessor",
- srcs: [
- ":framework-annotations",
- "src/**/*.java",
- "src/**/*.kt"
- ],
-
- use_tools_jar: true,
+ static_libs: ["libintdef-annotation-processor"],
}
java_test_host {
@@ -26,8 +32,8 @@
srcs: [
"test/**/*.java",
- "test/**/*.kt"
- ],
+ "test/**/*.kt",
+ ],
java_resource_dirs: ["test/resources"],
static_libs: [
@@ -35,7 +41,7 @@
"truth-prebuilt",
"junit",
"guava",
- "intdef-annotation-processor"
+ "libintdef-annotation-processor",
],
test_suites: ["general-tests"],
diff --git a/tools/processors/view_inspector/Android.bp b/tools/processors/view_inspector/Android.bp
index ea9974f..877a1d2 100644
--- a/tools/processors/view_inspector/Android.bp
+++ b/tools/processors/view_inspector/Android.bp
@@ -7,10 +7,8 @@
default_applicable_licenses: ["frameworks_base_license"],
}
-java_plugin {
- name: "view-inspector-annotation-processor",
-
- processor_class: "android.processor.view.inspector.PlatformInspectableProcessor",
+java_library_host {
+ name: "libview-inspector-annotation-processor",
srcs: ["src/java/**/*.java"],
java_resource_dirs: ["src/resources"],
@@ -23,6 +21,16 @@
use_tools_jar: true,
}
+java_plugin {
+ name: "view-inspector-annotation-processor",
+
+ processor_class: "android.processor.view.inspector.PlatformInspectableProcessor",
+
+ static_libs: [
+ "libview-inspector-annotation-processor",
+ ],
+}
+
java_test_host {
name: "view-inspector-annotation-processor-test",
@@ -32,7 +40,7 @@
static_libs: [
"junit",
"guava",
- "view-inspector-annotation-processor"
+ "libview-inspector-annotation-processor",
],
test_suites: ["general-tests"],